"""command-line interface for absolutelyright.

machine-readable by default: lists are ndjson (one json object per line) and
single results are one json object, so output pipes straight into jq or an
agent. pass --pretty for human-formatted output.
"""

import json
from functools import lru_cache
from pathlib import Path
from typing import Any

import cyclopts

import absolutelyright
from absolutelyright import _stats
from absolutelyright._records import DEFAULT_CLAUDE_DIR, Session, load_sessions

app = cyclopts.App(
    name="absolutelyright",
    help="analytics over your claude code session transcripts",
    version=absolutelyright.__version__,
)


def _emit(data: dict[str, Any]) -> None:
    print(json.dumps(data))


@app.default
def tui(*, days: int | None = None, claude_dir: Path = DEFAULT_CLAUDE_DIR) -> None:
    """interactive dashboard (the default — just run `absolutelyright`)."""
    if not (claude_dir / "projects").is_dir():
        raise SystemExit(f"no transcripts found under {claude_dir}/projects")
    from absolutelyright.tui import run

    run(claude_dir=claude_dir, days=days)


@lru_cache  # `report` runs every command in-process; parse transcripts once
def _load(claude_dir: Path, days: int | None) -> list[Session]:
    if not (claude_dir / "projects").is_dir():
        raise SystemExit(f"no transcripts found under {claude_dir}/projects")
    return load_sessions(claude_dir, days=days)


@app.command
def overview(
    *,
    days: int | None = None,
    claude_dir: Path = DEFAULT_CLAUDE_DIR,
    pretty: bool = False,
) -> None:
    """totals: sessions, prompts, interrupts, tokens, date range."""
    stats = _stats.overview(_load(claude_dir, days))
    if not pretty:
        _emit(stats)
        return
    span = ""
    if stats["first"]:
        span = f"   {stats['first'][:10]} → {stats['last'][:10]}"
    print(f"{stats['sessions']} sessions across {stats['projects']} projects{span}")
    print(f"  prompts: {stats['prompts']}")
    print(f"  interrupts: {stats['interrupts']}")
    print(f"  tool calls: {stats['toolCalls']}")
    print(f"  output tokens: {stats['outputTokens']:,}")


@app.command
def prompts(
    top: int = 15,
    *,
    days: int | None = None,
    claude_dir: Path = DEFAULT_CLAUDE_DIR,
    pretty: bool = False,
) -> None:
    """your most-repeated literal prompts."""
    for text, count in _stats.repeated_prompts(_load(claude_dir, days), top=top):
        if pretty:
            print(f"{count:5d}  {text}")
        else:
            _emit({"count": count, "text": text})


@app.command
def corrections(
    *,
    days: int | None = None,
    claude_dir: Path = DEFAULT_CLAUDE_DIR,
    pretty: bool = False,
) -> None:
    """prompts that open with no / wait / stop / actually."""
    sessions = _load(claude_dir, days)
    found = _stats.corrections(sessions)
    total = len(_stats.all_prompts(sessions))
    if pretty:
        rate = 100 * len(found) / total if total else 0
        print(f"{len(found)} of {total} prompts ({rate:.1f}%)\n")
        for p in found:
            first_line = p.text.splitlines()[0]
            print(f"  [{p.project}] {first_line[:100]}")
        return
    for p in found:
        _emit(
            {
                "text": p.text,
                "project": p.project,
                "timestamp": p.timestamp.isoformat() if p.timestamp else None,
            }
        )


@app.command
def projects(
    *,
    days: int | None = None,
    claude_dir: Path = DEFAULT_CLAUDE_DIR,
    pretty: bool = False,
) -> None:
    """per-project sessions, prompts, interrupts, and output tokens."""
    rows = _stats.by_project(_load(claude_dir, days))
    if not pretty:
        for row in rows:
            _emit(row)
        return
    width = max((len(r["project"]) for r in rows), default=7)
    print(f"{'project':<{width}}  sessions  prompts  interrupts  output tokens")
    for r in rows:
        print(
            f"{r['project']:<{width}}  {r['sessions']:8d}  {r['prompts']:7d}"
            f"  {r['interrupts']:10d}  {r['outputTokens']:13,}"
        )


@app.command
def tools(
    *,
    days: int | None = None,
    claude_dir: Path = DEFAULT_CLAUDE_DIR,
    pretty: bool = False,
) -> None:
    """tool call counts across all sessions."""
    for name, count in _stats.tool_counts(_load(claude_dir, days)):
        if pretty:
            print(f"{count:7d}  {name}")
        else:
            _emit({"tool": name, "count": count})


@app.command
def hours(
    *,
    days: int | None = None,
    claude_dir: Path = DEFAULT_CLAUDE_DIR,
    pretty: bool = False,
) -> None:
    """prompts by local hour of day."""
    histogram = _stats.hour_histogram(_load(claude_dir, days))
    if not pretty:
        _emit({f"{h:02d}": n for h, n in histogram.items()})
        return
    peak = max(histogram.values(), default=1)
    for hour, count in histogram.items():
        bar = "█" * max(1, round(40 * count / peak))
        print(f"{hour:02d}:00  {count:5d}  {bar}")


@app.command
def report(
    *,
    days: int | None = None,
    claude_dir: Path = DEFAULT_CLAUDE_DIR,
) -> None:
    """the whole picture, human-formatted."""
    for section in (overview, prompts, corrections, projects, tools, hours):
        print(f"\n── {section.__name__} {'─' * (40 - len(section.__name__))}")
        section(days=days, claude_dir=claude_dir, pretty=True)


def main() -> None:
    app()


if __name__ == "__main__":
    main()
