# standard
from typing import Optional

# third party
import typer
from rich import box
from rich.table import Table

# custom
from sunwaee.config import get_default_workspace
from sunwaee.core.audit import append_log
from sunwaee.core.fs import list_md
from sunwaee.core.output import console, error, success
from ._helpers import _enrich, _load, _resolve_dirs

_NOTE_SORT_KEYS = {
    "updated": lambda n: n.updated_at,
    "created": lambda n: n.created_at,
    "title": lambda n: n.title.lower(),
}


def list_notes(
    tags: Optional[str] = typer.Option(
        None, "--tags", help="Filter by tag (comma-separated)"
    ),
    query: Optional[str] = typer.Option(
        None, "--query", "-q", help="Search term (matches title, tags, body)"
    ),
    sort: str = typer.Option(
        "updated", "--sort", help="Sort by: updated (default), created, title"
    ),
    workspace: Optional[str] = typer.Option(
        None, "--workspace", "-w", help="Workspace name (default: all workspaces)"
    ),
) -> None:
    """List all notes."""
    if sort not in _NOTE_SORT_KEYS:
        error(
            f"Invalid --sort value: {sort!r}. Choose from: {', '.join(_NOTE_SORT_KEYS)}",
            "VALIDATION_ERROR",
        )

    dirs = _resolve_dirs(workspace)
    multi_ws = workspace is None

    triples: list[tuple, ...] = []
    for ws, directory in dirs:
        for p in list_md(directory):
            triples.append((_load(p), p, ws))

    if tags:
        filter_tags = {t.strip().lower() for t in tags.split(",")}
        triples = [
            (n, p, w)
            for n, p, w in triples
            if any(t.lower() in filter_tags for t in n.tags)
        ]

    if query:
        q = query.lower()
        triples = [
            (n, p, w)
            for n, p, w in triples
            if q in n.title.lower()
            or q in n.body.lower()
            or any(q in t.lower() for t in n.tags)
        ]

    key_fn = _NOTE_SORT_KEYS[sort]
    reverse = sort != "title"
    triples = sorted(triples, key=lambda x: key_fn(x[0]), reverse=reverse)

    notes = [n for n, p, w in triples]
    paths = [p for n, p, w in triples]
    ws_names = [w for n, p, w in triples]

    _log_args: dict = {"results": len(notes)}
    if tags:
        _log_args["tags"] = tags
    if query:
        _log_args["query"] = query
    if sort != "updated":
        _log_args["sort"] = sort
    append_log(workspace or get_default_workspace(), "notes", "list", args=_log_args)

    def human_output() -> None:  # pragma: no cover
        if not notes:
            scope = "all workspaces" if multi_ws else f"workspace '{workspace}'"
            console.print(f"[dim]No notes in {scope}.[/dim]")
            return
        table = Table(box=box.SIMPLE, show_header=True, header_style="bold")
        table.add_column("ID", style="dim", width=10, no_wrap=True)
        table.add_column("Title")
        if multi_ws:
            table.add_column("Workspace", style="dim", width=14)
        table.add_column("Tags")
        table.add_column("Updated", style="dim", width=12)
        table.add_column("Path", style="dim")
        for note, path, ws_name in zip(notes, paths, ws_names):
            row = [note.id[:8], note.title]
            if multi_ws:
                row.append(ws_name)
            row += [
                ", ".join(note.tags) if note.tags else "—",
                note.updated_at[:10],
                str(path.resolve()),
            ]
            table.add_row(*row)
        console.print(table)

    success(
        [_enrich(n, ws_n, p) for n, p, ws_n in zip(notes, paths, ws_names)],
        human_fn=human_output,
    )
