# standard
from typing import Optional

# third party
import typer

# custom
from sunwaee.modules.tasks.model import TaskPriority, TaskStatus
from sunwaee.config import get_workspace_dir, is_machine_caller
from sunwaee.core.audit import append_log
from sunwaee.core.editor import open_editor
from sunwaee.core.git import ensure_git_repo, ws_commit
from sunwaee.core.logger import get_logger
from sunwaee.core.output import error, success
from ._helpers import _enrich, _find_in_all, _load, _save

_log = get_logger("modules.tasks")


def update(
    query: str = typer.Argument(..., help="Task id, slug, or title"),
    title: Optional[str] = typer.Option(None, "--title", "-t"),
    status: Optional[TaskStatus] = typer.Option(None, "--status", "-s"),
    priority: Optional[TaskPriority] = typer.Option(None, "--priority", "-p"),
    due: Optional[str] = typer.Option(None, "--due"),
    clear_due: bool = typer.Option(False, "--clear-due", help="Remove the due date"),
    tags: Optional[str] = typer.Option(None, "--tags"),
    body: Optional[str] = typer.Option(None, "--body", "-b"),
    workspace: Optional[str] = typer.Option(None, "--workspace", "-w"),
) -> None:
    """Edit a task. Without flags (human caller), opens $EDITOR for the body."""
    found = _find_in_all(query, workspace)
    if found is None:
        error(f"Task not found: {query!r}", "NOT_FOUND")
        return  # pragma: no cover
    ws, directory, path = found
    ws_dir = get_workspace_dir(ws)
    ensure_git_repo(ws_dir)

    task = _load(path)
    changed = False

    if title is not None:
        task.title = title
        changed = True
    if status is not None:
        task.status = status
        if status != TaskStatus.DONE:
            task.completed_at = None
        changed = True
    if priority is not None:
        task.priority = priority
        changed = True
    if clear_due:
        task.due_date = None
        changed = True
    elif due is not None:
        task.due_date = due
        changed = True
    if tags is not None:
        task.tags = [t.strip() for t in tags.split(",")]
        changed = True
    if body is not None:
        task.body = body
        changed = True

    if not changed and not is_machine_caller():  # pragma: no cover
        task.body = open_editor(task.body)
        changed = True

    if changed:
        task.touch()
        _save(task, directory, path)
        _log.info("Updated task %r at %s", task.title, path)

    diff = ws_commit(ws_dir, f"tasks: update '{task.title}'")
    append_log(ws, "tasks", "update", item_id=task.id, item_title=task.title)

    success(_enrich(task, ws, path), human_fn=lambda: print(diff))
