"""Citation statistics analyzer.

Computes aggregate analytics over citation session history, including
total counts, format/type breakdowns, top sources, and monthly trends.
"""

from __future__ import annotations

from collections import Counter
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any


@dataclass
class StatsReport:
    """Aggregate analytics over citation history."""

    total_sessions: int
    total_citations: int
    format_breakdown: dict[str, int] = field(default_factory=dict)
    type_breakdown: dict[str, int] = field(default_factory=dict)
    top_sources: list[tuple[str, int]] = field(default_factory=list)
    monthly_counts: dict[str, int] = field(default_factory=dict)


def compute_stats(sessions: list[dict[str, Any]]) -> StatsReport:
    """Compute aggregate statistics from a list of cite session metadata dicts.

    Each session dict is expected to contain:
      - "output_format": str
      - "reference_count": int
      - "citation_records": list of dicts with "doi", "title", "citation_type"
      - "timestamp": str (ISO format datetime)

    Pure function — takes deserialized session metadata, returns StatsReport.
    """
    total_sessions = len(sessions)
    total_citations = sum(s.get("reference_count", 0) for s in sessions)

    # Format breakdown: count sessions per output_format
    format_counter: Counter[str] = Counter()
    for s in sessions:
        fmt = s.get("output_format", "unknown")
        format_counter[fmt] += 1

    # Type breakdown: count citation records per citation_type
    type_counter: Counter[str] = Counter()
    for s in sessions:
        for rec in s.get("citation_records", []):
            ctype = rec.get("citation_type", "unknown")
            type_counter[ctype] += 1

    top_sources = _extract_top_sources(sessions)
    monthly_counts = _extract_monthly_counts(sessions)

    return StatsReport(
        total_sessions=total_sessions,
        total_citations=total_citations,
        format_breakdown=dict(format_counter),
        type_breakdown=dict(type_counter),
        top_sources=top_sources,
        monthly_counts=monthly_counts,
    )


def _extract_monthly_counts(sessions: list[dict[str, Any]], months: int = 12) -> dict[str, int]:
    """Count sessions per month for the most recent *months* months.

    Parses the ``"timestamp"`` field from each session (ISO 8601 format),
    buckets by ``YYYY-MM``, and returns the most recent *months* buckets
    sorted chronologically.
    """
    month_counter: Counter[str] = Counter()
    for s in sessions:
        ts = s.get("timestamp", "")
        if not ts:
            continue
        try:
            dt = datetime.fromisoformat(ts)
            month_key = dt.strftime("%Y-%m")
            month_counter[month_key] += 1
        except (ValueError, TypeError):
            continue

    if not month_counter:
        return {}

    # Keep only the most recent N months
    sorted_months = sorted(month_counter.keys(), reverse=True)[:months]
    # Return in chronological order
    sorted_months.sort()
    return {m: month_counter[m] for m in sorted_months}


def _extract_top_sources(sessions: list[dict[str, Any]], top_n: int = 5) -> list[tuple[str, int]]:
    """Find the top *top_n* most-cited sources by DOI or title frequency.

    For each citation record across all sessions, uses the DOI as the
    source identifier if present, otherwise falls back to the title.
    Records with neither DOI nor title are skipped.
    """
    source_counter: Counter[str] = Counter()
    for s in sessions:
        for rec in s.get("citation_records", []):
            doi = rec.get("doi", "")
            title = rec.get("title", "")
            source_key = doi.strip() if doi and doi.strip() else title.strip()
            if source_key:
                source_counter[source_key] += 1

    return source_counter.most_common(top_n)
