from __future__ import annotations

# standard
from pathlib import Path
from typing import Annotated, Literal

# third party
# custom
from sunwaee.config import get_default_workspace, get_module_dir, get_workspace_dir
from sunwaee.core.fs import find_md, list_md, make_slug, read_md, search_md, write_md
from sunwaee.core.git import ensure_git_repo, ws_commit
from sunwaee.core.tools import err, ok, tool
from sunwaee.modules.notes.model import Note


def _ws(workspace: str | None) -> str:
    return workspace or get_default_workspace()


def _dir(workspace: str) -> Path:
    return get_module_dir(workspace, "notes")


def _ws_dir(workspace: str) -> Path:
    return get_workspace_dir(workspace)


@tool(
    "Manage notes. Actions: "
    "'create' (requires title), "
    "'read' (requires query), "
    "'update' (requires query, updates only provided fields), "
    "'delete' (requires query), "
    "'list' (filter by tags/query)."
)
def notes(
    action: Annotated[
        Literal["create", "read", "update", "delete", "list"], "Action to perform"
    ],
    query: Annotated[
        str | None, "Note id, slug, or title — required for read/update/delete"
    ] = None,
    workspace: Annotated[str | None, "Workspace name (uses default if omitted)"] = None,
    title: Annotated[str | None, "Note title — required for create"] = None,
    body: Annotated[str | None, "Note content in Markdown"] = None,
    tags: Annotated[
        list[str] | None, "List of tags (filter for list, replace for update)"
    ] = None,
) -> str:
    ws = _ws(workspace)
    d = _dir(ws)
    ws_d = _ws_dir(ws)
    ensure_git_repo(ws_d)

    if action == "create":
        if not title:
            return err("'title' is required for action='create'")
        note = Note(title=title, body=body or "", tags=tags or [])
        path = d / f"{make_slug(title, note.id)}.md"
        write_md(path, note.to_frontmatter_meta(), note.body)
        diff = ws_commit(ws_d, f"notes: create '{note.title}'")
        return ok(note.to_dict(), git_diff=diff)

    if action == "list":
        paths = search_md(query, d) if query else list_md(d)
        result = []
        for p in paths:
            meta, b = read_md(p)
            note = Note.from_dict(meta, b)
            if tags and not any(t in note.tags for t in tags):
                continue
            result.append(note.to_dict())
        return ok(result)

    if not query:
        return err(f"'query' is required for action={action!r}")

    if action == "read":
        path = find_md(query, d)
        if not path:
            return err(f"Note not found: {query!r}")
        meta, b = read_md(path)
        return ok(Note.from_dict(meta, b).to_dict())

    if action == "update":
        path = find_md(query, d)
        if not path:
            return err(f"Note not found: {query!r}")
        meta, existing_body = read_md(path)
        note = Note.from_dict(meta, existing_body)
        if title is not None:  # pragma: no cover
            note.title = title
        if body is not None:
            note.body = body
        if tags is not None:  # pragma: no cover
            note.tags = tags
        note.touch()
        write_md(path, note.to_frontmatter_meta(), note.body)
        diff = ws_commit(ws_d, f"notes: update '{note.title}'")
        return ok(note.to_dict(), git_diff=diff)

    if action == "delete":
        path = find_md(query, d)
        if not path:
            return err(f"Note not found: {query!r}")
        title_for_commit = path.stem
        path.unlink()
        diff = ws_commit(ws_d, f"notes: delete '{title_for_commit}'")
        return ok({"deleted": query}, git_diff=diff)

    return err(f"Unknown action: {action!r}")  # pragma: no cover


TOOLS = [notes._tool]
