#!/usr/bin/env python3
"""fzf-ai-stats: usage analytics dashboard for AI coding sessions.

Reads the fzf-ai index cache (or runs a fresh index) and displays a terminal
dashboard with session counts, agent distribution, daily activity, top
projects, and tag/star stats.

Usage:
    fzf-ai-stats              # full dashboard
    fzf-ai-stats --json       # JSON output (machine-readable)
    fzf-ai-stats --days 7     # last 7 days only
"""

from __future__ import annotations

import json
import os
import sys
from collections import Counter, defaultdict
from datetime import datetime, timezone
from pathlib import Path

# ANSI helpers
NO_COLOR = bool(os.environ.get("NO_COLOR"))


def _c(code: str, s: str) -> str:
    if NO_COLOR:
        return s
    return f"\033[{code}m{s}\033[0m"


BOLD = lambda s: _c("1", s)
DIM = lambda s: _c("2", s)
CYAN = lambda s: _c("36", s)
GREEN = lambda s: _c("32", s)
YELLOW = lambda s: _c("33", s)
MAGENTA = lambda s: _c("35", s)
RED = lambda s: _c("31", s)
BLUE = lambda s: _c("34", s)

HOME = Path.home()
STATE_HOME = Path(os.environ.get("XDG_STATE_HOME", HOME / ".local" / "state"))
FZFAI_DIR = STATE_HOME / "fzf-ai"
CACHE_DIR = Path(os.environ.get("XDG_CACHE_HOME", HOME / ".cache")) / "fzf-ai"

# Colors for agent names
_AGENT_COLOR = {
    "claude": CYAN,
    "codex": BLUE,
    "opencode": MAGENTA,
    "droid": GREEN,
    "pi": YELLOW,
}


def _load_cache() -> dict:
    """Load the index cache (fastest path, no indexing)."""
    path = CACHE_DIR / "index.json"
    if not path.is_file():
        return {}
    try:
        return json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        return {}


def _load_tags() -> dict:
    path = FZFAI_DIR / "tags.json"
    if not path.is_file():
        return {}
    try:
        return json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        return {}


def _load_stars() -> set[str]:
    path = FZFAI_DIR / "stars.json"
    if not path.is_file():
        return set()
    try:
        return set(json.loads(path.read_text(encoding="utf-8")).keys())
    except Exception:
        return set()


def _load_titles() -> dict:
    path = FZFAI_DIR / "titles.json"
    if not path.is_file():
        return {}
    try:
        return json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        return {}


def _bar(val: int, max_val: int, width: int = 30) -> str:
    """Render a horizontal bar."""
    if max_val == 0:
        return " " * width
    filled = int((val / max_val) * width)
    return "█" * filled + "░" * (width - filled)


def render_dashboard(days: int | None = None, json_output: bool = False) -> str:
    """Render the stats dashboard."""
    cache = _load_cache()
    sources = cache.get("sources", {})
    if not sources:
        return "No session data found. Run fzf-ai first to build the index cache."

    # Collect records
    all_records: list[dict] = []
    for source_key, entry in sources.items():
        for rec in entry.get("records", []):
            ts = rec.get("updated", 0)
            if days and ts:
                cutoff = datetime.now(timezone.utc).timestamp() - days * 86400
                if ts < cutoff:
                    continue
            all_records.append(rec)

    if not all_records:
        return "No sessions found."

    # Compute stats
    total = len(all_records)
    total_msgs = sum(r.get("msgs", 0) for r in all_records)
    projects = len({r.get("cwd", "") for r in all_records if r.get("cwd")})
    agent_counts: Counter[str] = Counter(r.get("agent", "?") for r in all_records)
    msg_by_agent: Counter[str] = Counter()
    for r in all_records:
        msg_by_agent[r.get("agent", "?")] += r.get("msgs", 0)

    # Daily activity
    daily: Counter[str] = Counter()
    for r in all_records:
        ts = r.get("updated", 0)
        if ts:
            day = datetime.fromtimestamp(ts, tz=timezone.utc).strftime("%Y-%m-%d")
            daily[day] += 1

    # Top projects
    project_counts: Counter[str] = Counter(r.get("cwd", "") for r in all_records)

    # Tags & stars
    tags = _load_tags()
    stars = _load_stars()
    titles = _load_titles()
    starred_records = [r for r in all_records if r.get("session_id", "") in stars]
    tagged_sessions = len(tags)

    if json_output:
        return json.dumps({
            "total_sessions": total,
            "total_messages": total_msgs,
            "total_projects": projects,
            "agents": dict(agent_counts),
            "messages_by_agent": dict(msg_by_agent),
            "daily_activity": dict(sorted(daily.items())),
            "top_projects": dict(project_counts.most_common(10)),
            "starred": len(starred_records),
            "tagged_sessions": tagged_sessions,
            "tag_count": sum(len(v) for v in tags.values()),
        }, indent=2)

    # Build the terminal dashboard
    lines: list[str] = []
    width = 72

    lines.append("")
    lines.append(BOLD(f"  fzf-ai Usage Analytics"))
    lines.append(DIM(f"  {'─' * width}"))

    # Summary row
    lines.append(f"  {BOLD('Sessions:')}    {total:<6}  {BOLD('Messages:')}  {total_msgs:<8}  {BOLD('Projects:')}  {projects}")
    lines.append("")

    # Agent distribution
    max_agent = max(agent_counts.values()) if agent_counts else 1
    lines.append(f"  {BOLD('By Agent')}")
    for agent in ("claude", "codex", "opencode", "droid", "pi"):
        count = agent_counts.get(agent, 0)
        if count > 0:
            color = _AGENT_COLOR.get(agent, lambda s: s)
            pct = (count / total) * 100
            bar = _bar(count, max_agent, 20)
            label = agent.ljust(10)
            lines.append(
                f"    {color(label)} {bar}  {count:>5}  ({pct:5.1f}%)"
            )
    lines.append("")

    # Daily activity (last 14 days)
    sorted_days = sorted(daily.keys(), reverse=True)[:14]
    if sorted_days:
        max_day = max(daily.values())
        lines.append(f"  {BOLD('Daily Activity (last 14 days)')}")
        for day in sorted_days:
            count = daily[day]
            bar = _bar(count, max_day, 25)
            label = day[-5:]  # MM-DD
            lines.append(f"    {label} {bar} {count}")
        lines.append("")

    # Top projects
    if project_counts:
        max_proj = max(project_counts.values())
        lines.append(f"  {BOLD('Top Projects')}")
        for proj, count in project_counts.most_common(8):
            short = proj.split("/")[-1] if proj else "(unknown)"
            if len(short) > 28:
                short = short[:25] + "..."
            bar = _bar(count, max_proj, 20)
            lines.append(f"    {short:<28} {bar} {count}")
        lines.append("")

    # Tags & Stars
    lines.append(f"  {BOLD('Metadata')}")
    tag_count_total = sum(len(v) for v in tags.values())
    lines.append(f"    Starred sessions:  {len(starred_records)}")
    lines.append(f"    Tagged sessions:   {tagged_sessions}  ({tag_count_total} total tags)")
    if titles:
        lines.append(f"    Custom titles:    {len(titles)}")
    lines.append("")

    return "\n".join(lines)


def main() -> int:
    import argparse
    parser = argparse.ArgumentParser(description="fzf-ai usage analytics")
    parser.add_argument("--json", action="store_true", help="JSON output")
    parser.add_argument("--days", type=int, default=None, help="Last N days only")
    args = parser.parse_args()

    try:
        dashboard = render_dashboard(days=args.days, json_output=args.json)
        sys.stdout.write(dashboard)
        sys.stdout.write("\n")
    except BrokenPipeError:
        pass
    return 0


if __name__ == "__main__":
    sys.exit(main())
