"""
JQL query builder.
"""

from typing import Optional, List


class JQL:
    """Fluent JQL builder."""

    def __init__(self):
        self._parts: List[str] = []
        self._order: Optional[str] = None

    def _q(self, val: str) -> str:
        return f'"{val}"' if " " in val else val

    # Conditions
    def assigned_to_me(self) -> "JQL":
        self._parts.append("assignee = currentUser()")
        return self

    def project(self, key: str) -> "JQL":
        self._parts.append(f"project = {self._q(key)}")
        return self

    def sprint_open(self) -> "JQL":
        self._parts.append("sprint in openSprints()")
        return self

    def in_backlog(self) -> "JQL":
        self._parts.append("sprint is EMPTY")
        return self

    def not_done(self) -> "JQL":
        self._parts.append("statusCategory != Done")
        return self

    def status(self, name: str) -> "JQL":
        self._parts.append(f"status = {self._q(name)}")
        return self

    def label(self, name: str) -> "JQL":
        self._parts.append(f"labels = {self._q(name)}")
        return self

    def text(self, search: str) -> "JQL":
        self._parts.append(f'text ~ "{search}"')
        return self

    def issue_type(self, name: str) -> "JQL":
        self._parts.append(f"issuetype = {self._q(name)}")
        return self

    def raw(self, jql: str) -> "JQL":
        self._parts.append(jql)
        return self

    # Ordering
    def order_by(self, field: str, desc: bool = True) -> "JQL":
        self._order = f"ORDER BY {field} {'DESC' if desc else 'ASC'}"
        return self

    def build(self) -> str:
        jql = " AND ".join(self._parts)
        if self._order:
            jql = f"{jql} {self._order}"
        return jql.strip()


# Preset queries for main use cases
class Queries:
    @staticmethod
    def my_tickets(project: Optional[str] = None) -> JQL:
        q = JQL().assigned_to_me().not_done().order_by("updated")
        if project:
            q.project(project)
        return q

    @staticmethod
    def backlog(project: str) -> JQL:
        return JQL().project(project).in_backlog().not_done().order_by("priority")

    @staticmethod
    def current_sprint(project: str) -> JQL:
        return JQL().project(project).sprint_open().order_by("priority")
