"""bandito review pipeline — basics (deterministic stats + patterns).

Production path: delegates to backend POST /analyze/basics.
Local fallback: runs aggregation + patterns locally.
"""

from __future__ import annotations

import sys

from .models import (
    AggregateStats,
    Distribution,
    ModelBreakdown,
    Pattern,
    ReviewConfig,
    ReviewResult,
    SpanKindBreakdown,
)


def run_basics(config: ReviewConfig, store=None, evaluations=None, client=None) -> None:
    """Stats + patterns, no LLM. Delegates to backend when client is available."""
    from .formatter import format_review

    if store is None:
        if config.directory:
            from ..storage import LocalStore
            store = LocalStore(config.directory)
        else:
            from ..storage import get_store
            store = get_store(project=config.project)

    # Resolve project
    project = config.project
    if project is None:
        projects = store.list_projects()
        if len(projects) == 0:
            _hint(
                "No traces found.",
                f"Traces directory: {config.directory}",
                "",
                "Instrument your app with bandito.trace() first.",
            )
            return
        if len(projects) == 1:
            project = projects[0]
        else:
            _hint(
                f"{len(projects)} projects found. Pick one with --project:",
                "",
                *[f"  bandito observe basics --project {p}" for p in projects[:5]],
                *(["  ..."] if len(projects) > 5 else []),
                "",
                "See all projects:  bandito observe projects",
            )
            return

    # Load traces
    traces = store.list_traces_filtered(
        project=project,
        tag=config.tag,
        limit=config.last_n,
    )

    if not traces:
        all_traces = store.list_traces(project)
        if all_traces:
            _hint(
                f"No traces match --last {config.last_n}.",
                f"Project '{project}' has {len(all_traces)} traces total.",
                "",
                f"Try without --last:",
                f"  bandito observe basics --project {project}",
            )
        else:
            _hint(
                f"No traces found for project '{project}'.",
                f"Traces directory: {config.directory}",
                "",
                "Instrument your app with bandito.trace() first.",
            )
        return

    if evaluations is None:
        evaluations = {}
    mode = "enhanced" if evaluations else "bootstrap"

    # Try backend, fall back to local
    if client is not None:
        result = _run_remote(config, project, traces, evaluations, mode, client)
    else:
        result = _run_local(config, project, traces, evaluations, mode)

    print(format_review(result))


def _run_remote(config, project, traces, evaluations, mode, client) -> ReviewResult:
    """Delegate analysis to the backend."""
    data = client.analyze_basics(traces, evaluations or None)

    # Reconstruct ReviewResult from backend response
    raw_stats = data["stats"]
    stats = AggregateStats(
        trace_count=raw_stats["trace_count"],
        span_count=raw_stats["span_count"],
        cost=Distribution(**raw_stats["cost"]),
        latency=Distribution(**raw_stats["latency"]),
        tokens=Distribution(**raw_stats["tokens"]),
        models=[ModelBreakdown(**m) for m in raw_stats.get("models", [])],
        span_kinds=[SpanKindBreakdown(**sk) for sk in raw_stats.get("span_kinds", [])],
        error_count=raw_stats.get("error_count", 0),
        eval_count=raw_stats.get("eval_count", 0),
        human_eval_count=raw_stats.get("human_eval_count", 0),
        human_avg_grade=raw_stats.get("human_avg_grade"),
        judge_eval_count=raw_stats.get("judge_eval_count", 0),
        judge_avg_grade=raw_stats.get("judge_avg_grade"),
    )
    patterns = [
        Pattern(**p) for p in data.get("patterns", [])
    ]

    return ReviewResult(
        config=ReviewConfig(directory=config.directory, project=project, last_n=config.last_n),
        stats=stats,
        patterns=patterns,
        mode=mode,
        command="basics",
    )


def _run_local(config, project, traces, evaluations, mode) -> ReviewResult:
    """Local fallback: run aggregation + patterns locally."""
    from .aggregator import aggregate
    from .patterns import run_all

    stats = aggregate(traces, evaluations)
    patterns = run_all(traces, stats, evaluations)

    return ReviewResult(
        config=ReviewConfig(directory=config.directory, project=project, last_n=config.last_n),
        stats=stats,
        patterns=patterns,
        mode=mode,
        command="basics",
    )


def _hint(*lines: str) -> None:
    for line in lines:
        print(line, file=sys.stderr)
