"""aggregations over parsed sessions."""

from __future__ import annotations

import re
from collections import Counter
from datetime import UTC, date, datetime, timedelta
from typing import Any

from absolutelyright._records import Prompt, Session

CORRECTION_RE = re.compile(
    r"^(no|nope|wait|stop|actually|wrong|not that|undo|revert|that's not)\b", re.I
)

MAX_REPEAT_LEN = 200  # longer prompts are never literal repeats worth surfacing


def all_prompts(sessions: list[Session]) -> list[Prompt]:
    return [p for s in sessions for p in s.prompts]


def overview(sessions: list[Session]) -> dict[str, Any]:
    prompts = all_prompts(sessions)
    timestamps = sorted(p.timestamp for p in prompts if p.timestamp)
    return {
        "sessions": len(sessions),
        "prompts": len(prompts),
        "interrupts": sum(s.interrupts for s in sessions),
        "toolCalls": sum(sum(s.tool_calls.values()) for s in sessions),
        "outputTokens": sum(s.output_tokens for s in sessions),
        "cacheReadTokens": sum(s.cache_read_tokens for s in sessions),
        "prsShipped": len({url for s in sessions for url in s.pr_urls}),
        "projects": len({s.project for s in sessions}),
        "first": timestamps[0].isoformat() if timestamps else None,
        "last": timestamps[-1].isoformat() if timestamps else None,
    }


def repeated_prompts(
    sessions: list[Session], top: int = 15, min_count: int = 2
) -> list[tuple[str, int]]:
    counts = Counter(
        p.text.lower() for p in all_prompts(sessions) if len(p.text) <= MAX_REPEAT_LEN
    )
    return [(text, n) for text, n in counts.most_common(top) if n >= min_count]


def corrections(sessions: list[Session]) -> list[Prompt]:
    return [p for p in all_prompts(sessions) if CORRECTION_RE.match(p.text)]


def by_project(sessions: list[Session]) -> list[dict[str, Any]]:
    rows: dict[str, dict[str, Any]] = {}
    for s in sessions:
        row = rows.setdefault(
            s.project,
            {
                "project": s.project,
                "sessions": 0,
                "prompts": 0,
                "interrupts": 0,
                "outputTokens": 0,
            },
        )
        row["sessions"] += 1
        row["prompts"] += len(s.prompts)
        row["interrupts"] += s.interrupts
        row["outputTokens"] += s.output_tokens
    return sorted(rows.values(), key=lambda r: r["prompts"], reverse=True)


def tool_counts(sessions: list[Session]) -> list[tuple[str, int]]:
    totals: Counter[str] = Counter()
    for s in sessions:
        totals.update(s.tool_calls)
    return totals.most_common()


def hour_histogram(sessions: list[Session]) -> dict[int, int]:
    """prompts by local hour of day."""
    hours: Counter[int] = Counter()
    for p in all_prompts(sessions):
        if p.timestamp:
            hours[p.timestamp.astimezone().hour] += 1
    return dict(sorted(hours.items()))


def claudeisms(sessions: list[Session]) -> list[tuple[str, int]]:
    """things claude says, counted across all assistant turns."""
    totals: Counter[str] = Counter()
    for s in sessions:
        totals.update(s.isms)
    return totals.most_common()


def vibe(sessions: list[Session]) -> list[tuple[str, int]]:
    """things you say."""
    totals: Counter[str] = Counter()
    for s in sessions:
        totals.update(s.vibe)
    totals["images pasted"] = sum(s.images for s in sessions)
    return totals.most_common()


def model_mix(sessions: list[Session]) -> list[tuple[str, int]]:
    totals: Counter[str] = Counter()
    for s in sessions:
        totals.update(s.models)
    return totals.most_common()


def slash_counts(sessions: list[Session]) -> list[tuple[str, int]]:
    totals: Counter[str] = Counter()
    for s in sessions:
        totals.update(s.slash_commands)
    return totals.most_common()


def shipped(sessions: list[Session]) -> list[dict[str, str]]:
    """unique PRs opened, most recent project first."""
    epoch = datetime.min.replace(tzinfo=UTC)
    seen: dict[str, str] = {}
    for s in sorted(
        sessions, key=lambda s: s.last_ts or s.first_ts or epoch, reverse=True
    ):
        for url in sorted(s.pr_urls):
            seen.setdefault(url, s.project)
    return [{"url": url, "project": project} for url, project in seen.items()]


def session_rows(sessions: list[Session]) -> list[dict[str, Any]]:
    """one row per session for the sessions browser, most recent first."""
    rows = []
    for s in sessions:
        if s.first_ts is None:
            continue
        rows.append(
            {
                "when": s.first_ts.astimezone().strftime("%m-%d %H:%M"),
                "title": s.title or "(untitled)",
                "project": s.project,
                "activeMinutes": round(s.active_seconds / 60),
                "prompts": len(s.prompts),
                "interrupts": s.interrupts,
                "outputTokens": s.output_tokens,
                "_sort": s.first_ts,
            }
        )
    rows.sort(key=lambda r: r["_sort"], reverse=True)
    for row in rows:
        del row["_sort"]
    return rows


def daily_counts(sessions: list[Session], days: int = 30) -> list[int]:
    """prompts per day for the trailing window, oldest first (sparkline food)."""
    today = date.today()
    counts: Counter[date] = Counter()
    for p in all_prompts(sessions):
        if p.timestamp:
            counts[p.timestamp.astimezone().date()] += 1
    return [counts.get(today - timedelta(days=i), 0) for i in range(days - 1, -1, -1)]
