"""alice appraise — Token usage and cost reporting from the Cloud Locker."""

from __future__ import annotations

from collections import defaultdict
from typing import TYPE_CHECKING

import click
from rich.table import Table

from alice_cli import personality
from alice_cli.auth import detect_identity_from_key, detect_username
from alice_cli.commands.recall import filter_entries
from alice_cli.console import (
    err_console,
    print_banner,
    print_status,
    print_success,
    spinner,
)
from alice_cli.constants import get_memory_bucket
from alice_cli.locker import CloudLocker
from alice_cli.models import MODEL_ALIASES
from alice_cli.pricing import estimate_cost, format_cost

if TYPE_CHECKING:
    from alice_cli.models import IndexEntry


@click.command("appraise")
@click.option("--since", default=None, help="Include sessions on or after this date (YYYY-MM-DD)")
@click.option("--model", default=None, help="Filter by model alias or ID (substring match)")
@click.option(
    "--detailed",
    is_flag=True,
    default=False,
    help="Show per-session token counts instead of per-model aggregates",
)
@click.pass_context
def appraise_cmd(
    ctx: click.Context,
    since: str | None,
    model: str | None,
    detailed: bool,
) -> None:
    """View token usage and estimated costs from past sessions.

    \b
    Examples:
        alice appraise
        alice appraise --since 2025-01-01
        alice appraise --model sonnet --detailed
    """
    config = ctx.obj["config"]

    print_banner(personality.BANNER, config.quiet)

    # ── Authenticate ──────────────────────────────────────────────────
    username: str

    if config.bedrock_secret_key and not config.profile:
        username = detect_identity_from_key(config.bedrock_access_key)
        print_status(personality.status_using_api_key(username), config.quiet)
    else:
        with spinner(personality.status_detecting_identity(), config.quiet):
            result = detect_username(config.profile, config.region)
        username = result.username
        print_status(personality.status_identity_detected(username), config.quiet)

    locker = CloudLocker(
        config=config,
        username=username,
        bucket=get_memory_bucket(config.namespace, config.environment),
    )

    # ── Load index and filter ─────────────────────────────────────────
    with spinner("Loading session index…", config.quiet):
        index = locker.load_index()

    # Reuse recall's filter_entries for --since and --model filtering.
    # We pass a very large limit so nothing is truncated.
    filtered = filter_entries(
        index.entries,
        since=since,
        model=model,
        limit=0,  # 0 means no limit in filter_entries
    )

    # Keep only entries that have token usage data
    entries_with_tokens = [e for e in filtered if e.tokens is not None]

    # If we matched sessions but none have tokens, try backfilling from
    # the full session records stored in S3 / local cache.
    if filtered and not entries_with_tokens:
        with spinner("Backfilling token data from session records…", config.quiet):
            filtered, filled = locker.backfill_tokens(filtered)
        if filled:
            err_console.print(f"  [dim]Backfilled token data for {filled} session(s).[/dim]")
        entries_with_tokens = [e for e in filtered if e.tokens is not None]

    if not entries_with_tokens:
        if filtered:
            err_console.print(
                f"  [dim]Found {len(filtered)} session(s) but none have token usage recorded.[/dim]"
            )
        else:
            err_console.print("  [dim]No matching sessions found.[/dim]")
        return

    # Build ARN → model_id reverse map so inference profile ARNs price correctly.
    # config.inference_profile_arns maps alias → ARN; MODEL_ALIASES maps alias → model_id.
    alias_to_model_id = {ma.alias: ma.model_id for ma in MODEL_ALIASES}
    arn_to_model: dict[str, str] = {}
    if config.inference_profile_arns:
        for alias, arn in config.inference_profile_arns.items():
            if alias in alias_to_model_id:
                arn_to_model[arn] = alias_to_model_id[alias]

    if detailed:
        _display_detailed(entries_with_tokens, config.quiet, arn_to_model)
    else:
        _display_aggregated(entries_with_tokens, config.quiet, arn_to_model)


def _display_aggregated(
    entries: list[IndexEntry],
    quiet: bool,
    arn_to_model: dict[str, str] | None = None,
) -> None:
    """Display per-model aggregate token usage with a summary row."""
    # Aggregate by model
    model_stats: dict[str, list[int]] = defaultdict(lambda: [0, 0, 0])

    for entry in entries:
        assert entry.tokens is not None
        stats = model_stats[entry.model]
        stats[0] += entry.tokens.input
        stats[1] += entry.tokens.output
        stats[2] += entry.tokens.total

    table = Table(title="Token Usage by Model", show_lines=False)
    table.add_column("Model", style="green")
    table.add_column("Input Tokens", style="cyan", justify="right")
    table.add_column("Output Tokens", style="cyan", justify="right")
    table.add_column("Total Tokens", style="cyan", justify="right")
    table.add_column("Est. Cost", style="yellow", justify="right")

    total_input = 0
    total_output = 0
    total_total = 0
    total_cost = 0.0

    _arn_map = arn_to_model or {}
    for model_name, (inp, out, tot) in sorted(model_stats.items()):
        cost = estimate_cost(_arn_map.get(model_name, model_name), inp, out)
        total_input += inp
        total_output += out
        total_total += tot
        total_cost += cost
        table.add_row(
            model_name,
            f"{inp:,}",
            f"{out:,}",
            f"{tot:,}",
            format_cost(cost),
        )

    # Summary row
    table.add_section()
    table.add_row(
        "[bold]Total[/bold]",
        f"[bold]{total_input:,}[/bold]",
        f"[bold]{total_output:,}[/bold]",
        f"[bold]{total_total:,}[/bold]",
        f"[bold]{format_cost(total_cost)}[/bold]",
    )

    err_console.print(table)
    print_success(
        f"{len(entries)} session(s), {total_total:,} tokens, {format_cost(total_cost)}",
        quiet,
    )


def _display_detailed(
    entries: list[IndexEntry],
    quiet: bool,
    arn_to_model: dict[str, str] | None = None,
) -> None:
    """Display per-session token usage with a summary row."""
    table = Table(title="Token Usage by Session", show_lines=False)
    table.add_column("Timestamp", style="cyan", no_wrap=True)
    table.add_column("Type", style="magenta")
    table.add_column("Model", style="green")
    table.add_column("Input Tokens", style="cyan", justify="right")
    table.add_column("Output Tokens", style="cyan", justify="right")
    table.add_column("Total Tokens", style="cyan", justify="right")
    table.add_column("Est. Cost", style="yellow", justify="right")

    total_input = 0
    total_output = 0
    total_total = 0
    total_cost = 0.0

    _arn_map = arn_to_model or {}
    for entry in entries:
        assert entry.tokens is not None
        cost = estimate_cost(
            _arn_map.get(entry.model, entry.model),
            entry.tokens.input,
            entry.tokens.output,
        )
        total_input += entry.tokens.input
        total_output += entry.tokens.output
        total_total += entry.tokens.total
        total_cost += cost
        table.add_row(
            entry.timestamp[:19],
            entry.type,
            entry.model,
            f"{entry.tokens.input:,}",
            f"{entry.tokens.output:,}",
            f"{entry.tokens.total:,}",
            format_cost(cost),
        )

    # Summary row
    table.add_section()
    table.add_row(
        "[bold]Total[/bold]",
        "",
        "",
        f"[bold]{total_input:,}[/bold]",
        f"[bold]{total_output:,}[/bold]",
        f"[bold]{total_total:,}[/bold]",
        f"[bold]{format_cost(total_cost)}[/bold]",
    )

    err_console.print(table)
    print_success(
        f"{len(entries)} session(s), {total_total:,} tokens, {format_cost(total_cost)}",
        quiet,
    )
