# standard
import json
from datetime import datetime, timezone
from pathlib import Path
from typing import Optional

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

# custom
from sunwaee.modules.logs.model import LogEntry
from sunwaee.config import (
    get_all_workspaces,
    get_default_workspace,
    get_workspaces_base_dir,
)
from sunwaee.core.audit import append_log
from sunwaee.core.output import console, error, success


def _logs_dir(workspace: str) -> Path:
    return get_workspaces_base_dir() / workspace / "logs"


def _resolve_workspaces(workspace: Optional[str]) -> list[str]:
    return [workspace] if workspace else get_all_workspaces()


def _read_day(workspace: str, date: str) -> list[LogEntry]:
    year, month, day = date.split("-")
    path = _logs_dir(workspace) / year / month / day / "logs.jsonl"
    if not path.exists():
        return []
    return _parse_jsonl(path)


def _read_month(workspace: str, month: str) -> list[LogEntry]:
    year, mon = month.split("-")
    month_dir = _logs_dir(workspace) / year / mon
    if not month_dir.exists():  # pragma: no cover
        return []
    entries = []
    for day_dir in sorted(month_dir.iterdir()):
        if day_dir.is_dir():
            log_file = day_dir / "logs.jsonl"
            if log_file.exists():
                entries.extend(_parse_jsonl(log_file))
    return entries


def _read_all(workspace: str) -> list[LogEntry]:
    base = _logs_dir(workspace)
    if not base.exists():  # pragma: no cover
        return []
    entries = []
    for log_file in sorted(base.rglob("logs.jsonl")):
        entries.extend(_parse_jsonl(log_file))
    return entries


def _parse_jsonl(path: Path) -> list[LogEntry]:
    entries = []
    with open(path) as f:
        for line in f:
            line = line.strip()
            if line:
                try:
                    entries.append(LogEntry.from_dict(json.loads(line)))
                except (json.JSONDecodeError, KeyError):  # pragma: no cover
                    pass
    return entries


def _collect(
    workspaces: list[str],
    date: Optional[str],
    month: Optional[str],
    all_time: bool,
) -> list[LogEntry]:
    entries: list[LogEntry] = []
    if all_time:
        for ws in workspaces:
            entries.extend(_read_all(ws))
    elif month:
        for ws in workspaces:
            entries.extend(_read_month(ws, month))
    else:
        target = date or datetime.now(timezone.utc).strftime("%Y-%m-%d")
        for ws in workspaces:
            entries.extend(_read_day(ws, target))
    return entries


def _validate_date_flags(
    date: Optional[str], month: Optional[str], all_time: bool
) -> None:
    if sum([bool(date), bool(month), all_time]) > 1:
        error("Use only one of --date, --month, or --all", "VALIDATION_ERROR")
    if month:
        try:
            datetime.strptime(month, "%Y-%m")
        except ValueError:
            error(f"Invalid --month format: {month!r}. Use YYYY-MM", "VALIDATION_ERROR")
    if date:
        try:
            datetime.strptime(date, "%Y-%m-%d")
        except ValueError:
            error(
                f"Invalid --date format: {date!r}. Use YYYY-MM-DD", "VALIDATION_ERROR"
            )


def _render_table(entries: list[LogEntry], multi_ws: bool) -> None:  # pragma: no cover
    if not entries:
        console.print("[dim]No logs found.[/dim]")
        return
    table = Table(box=box.SIMPLE, show_header=True, header_style="bold")
    table.add_column("Timestamp", style="dim", width=20, no_wrap=True)
    table.add_column("Caller", width=8)
    if multi_ws:
        table.add_column("Workspace", style="dim", width=14)
    table.add_column("Module", width=12)
    table.add_column("Operation", width=12)
    table.add_column("Item")
    table.add_column("OK", width=4)
    for e in entries:
        ts = e.timestamp[:19].replace("T", " ")
        ok_str = "[green]✓[/green]" if e.ok else "[red]✗[/red]"
        item = e.item_title or e.item_id or "—"
        row = [ts, e.caller]
        if multi_ws:
            row.append(e.workspace)
        row += [e.module, e.operation, item, ok_str]
        table.add_row(*row)
    console.print(table)


def list_logs(
    workspace: Optional[str] = typer.Option(
        None, "--workspace", "-w", help="Workspace name (default: all workspaces)"
    ),
    date: Optional[str] = typer.Option(
        None, "--date", help="Show logs for a specific day (YYYY-MM-DD, default: today)"
    ),
    month: Optional[str] = typer.Option(
        None, "--month", help="Show logs for a full month (YYYY-MM)"
    ),
    all_time: bool = typer.Option(
        False, "--all", help="Show all logs regardless of date"
    ),
    module: Optional[str] = typer.Option(
        None, "--module", "-m", help="Filter by module (notes, tasks, workspaces...)"
    ),
    operation: Optional[str] = typer.Option(
        None, "--operation", "-o", help="Filter by operation (create, edit, delete...)"
    ),
    caller: Optional[str] = typer.Option(
        None, "--caller", "-c", help="Filter by caller (human, api, sun)"
    ),
    query: Optional[str] = typer.Option(
        None,
        "--query",
        "-q",
        help="Search term (matches item title, id, module, operation, caller, workspace)",
    ),
    limit: int = typer.Option(
        50, "--limit", "-n", help="Maximum number of entries to show"
    ),
) -> None:
    """List activity logs. Defaults to today's logs."""
    _validate_date_flags(date, month, all_time)

    workspaces = _resolve_workspaces(workspace)
    multi_ws = workspace is None

    entries = _collect(workspaces, date, month, all_time)

    if module:
        entries = [e for e in entries if e.module == module]
    if operation:
        entries = [e for e in entries if e.operation == operation]
    if caller:
        entries = [e for e in entries if e.caller == caller]
    if query:
        entries = [e for e in entries if e.matches(query)]

    entries = sorted(entries, key=lambda e: e.timestamp, reverse=True)[:limit]

    _log_args: dict = {"results": len(entries)}
    if date:
        _log_args["date"] = date
    if month:
        _log_args["month"] = month
    if all_time:
        _log_args["all"] = True
    if module:
        _log_args["module"] = module
    if operation:
        _log_args["operation"] = operation
    if caller:
        _log_args["caller"] = caller
    if query:
        _log_args["query"] = query
    append_log(workspace or get_default_workspace(), "logs", "list", args=_log_args)

    success(
        [e.to_dict() for e in entries],
        human_fn=lambda: _render_table(entries, multi_ws),
    )
