"""alice quota — Check your Cheshire Gate token usage and remaining budget."""

from __future__ import annotations

from datetime import UTC, datetime
from typing import TYPE_CHECKING, Any

import boto3
import click
from botocore.exceptions import BotoCoreError, ClientError

from alice_cli import personality
from alice_cli.auth import resolve_username
from alice_cli.console import (
    err_console,
    print_banner,
    print_status,
    print_success,
    spinner,
)
from alice_cli.errors import AliceCLIError
from alice_cli.logo import LOGO_CHESHIRE_GATE

if TYPE_CHECKING:
    from alice_cli.models import CLIConfig


def _resolve_quota_table(config: CLIConfig) -> str:
    """Discover the Cheshire Gate DynamoDB table name via SSM."""
    ssm_name = f"/{config.namespace}/{config.environment}/cheshire-gate/quota-table"
    try:
        session = boto3.Session(profile_name=config.profile, region_name=config.region)
        ssm = session.client("ssm")
        resp = ssm.get_parameter(Name=ssm_name)
        return str(resp["Parameter"]["Value"])
    except (ClientError, BotoCoreError) as exc:
        raise AliceCLIError(
            f"Could not find Cheshire Gate quota table via SSM ({ssm_name}).\n"
            f"  Is the cheshire-gate module deployed? Error: {exc}"
        ) from exc


def _resolve_overrides_table(config: CLIConfig) -> str:
    """Discover the Cheshire Gate Overrides Table name via SSM."""
    ssm_name = f"/{config.namespace}/{config.environment}/cheshire-gate/overrides-table"
    try:
        session = boto3.Session(profile_name=config.profile, region_name=config.region)
        ssm = session.client("ssm")
        resp = ssm.get_parameter(Name=ssm_name)
        return str(resp["Parameter"]["Value"])
    except (ClientError, BotoCoreError) as exc:
        raise AliceCLIError(
            f"Could not find Cheshire Gate overrides table via SSM ({ssm_name}).\n"
            f"  Is the cheshire-gate module deployed? Error: {exc}"
        ) from exc


def _get_usage(config: CLIConfig, table_name: str, user_id: str, period: str) -> dict[str, Any]:
    """Read the user's token usage from DynamoDB."""
    try:
        session = boto3.Session(profile_name=config.profile, region_name=config.region)
        dynamodb = session.resource("dynamodb")
        table = dynamodb.Table(table_name)
        resp = table.get_item(Key={"user_id": user_id, "period": period})
        item: dict[str, Any] = resp.get("Item", {})
        return item
    except (ClientError, BotoCoreError) as exc:
        raise AliceCLIError(f"Could not read quota table: {exc}") from exc


def _set_override(
    config: CLIConfig, table_name: str, jhed: str, limit: float, updated_by: str
) -> None:
    """Write a per-user cost limit override to the Overrides Table."""
    from decimal import Decimal

    try:
        session = boto3.Session(profile_name=config.profile, region_name=config.region)
        dynamodb = session.resource("dynamodb")
        table = dynamodb.Table(table_name)
        table.put_item(
            Item={
                "user_id": jhed,
                "monthly_cost_limit_usd": Decimal(str(limit)),
                "updated_at": datetime.now(UTC).isoformat(),
                "updated_by": updated_by,
            }
        )
    except (ClientError, BotoCoreError) as exc:
        raise AliceCLIError(
            f"Failed to set override for {jhed} (limit=${limit:.2f}): {exc}"
        ) from exc


def _remove_override(config: CLIConfig, table_name: str, jhed: str) -> None:
    """Delete a per-user cost limit override from the Overrides Table."""
    try:
        session = boto3.Session(profile_name=config.profile, region_name=config.region)
        dynamodb = session.resource("dynamodb")
        table = dynamodb.Table(table_name)
        table.delete_item(Key={"user_id": jhed})
    except (ClientError, BotoCoreError) as exc:
        raise AliceCLIError(f"Failed to remove override for {jhed}: {exc}") from exc


def _get_cost_limit(config: CLIConfig, overrides_table_name: str, user_id: str) -> float:
    """Resolve the user's cost limit: Overrides Table → env var default → 10.0."""
    import os

    try:
        session = boto3.Session(profile_name=config.profile, region_name=config.region)
        dynamodb = session.resource("dynamodb")
        table = dynamodb.Table(overrides_table_name)
        resp = table.get_item(
            Key={"user_id": user_id},
            ProjectionExpression="monthly_cost_limit_usd",
        )
        override = resp.get("Item", {})
        if "monthly_cost_limit_usd" in override:
            return float(override["monthly_cost_limit_usd"])
    except (ClientError, BotoCoreError):
        pass  # fail-open: fall through to default

    return float(os.environ.get("CHESHIRE_GATE_DEFAULT_COST_LIMIT", "10.0"))


def _get_warning_threshold() -> float:
    """Return the warning threshold percentage from env var or default 80."""
    import os

    return float(os.environ.get("CHESHIRE_GATE_WARNING_THRESHOLD", "80"))


def _cost_bar_color(pct: float, warning_threshold: float) -> str:
    """Return the Rich color name for the cost progress bar."""
    if pct >= 100.0:
        return "red"
    if pct >= warning_threshold:
        return "yellow"
    return "green"


@click.command("quota")
@click.option("--period", default=None, help="Period to check (YYYY-MM, default: current month)")
@click.option(
    "--set",
    "set_override",
    nargs=2,
    type=(str, float),
    default=None,
    help="Set a per-user cost limit override: --set JHED LIMIT_USD",
)
@click.option(
    "--remove-override",
    "remove_override_jhed",
    default=None,
    help="Remove a per-user cost limit override for the given JHED",
)
@click.pass_context
def quota_cmd(
    ctx: click.Context,
    period: str | None,
    set_override: tuple[str, float] | None,
    remove_override_jhed: str | None,
) -> None:
    """View your token usage and remaining quota.

    \b
    Examples:
        alice quota
        alice quota --period 2026-02
        alice quota --set jdoe1 25.00
        alice quota --remove-override jdoe1
    """
    config: CLIConfig = ctx.obj["config"]
    print_banner(personality.BANNER, config.quiet)

    # Resolve identity
    user_id = resolve_username(config)

    # --- Admin override operations ---
    if set_override is not None:
        jhed, limit_val = set_override
        overrides_table = _resolve_overrides_table(config)
        _set_override(config, overrides_table, jhed, limit_val, updated_by=user_id)
        print_success(
            f"Override set for [cyan]{jhed}[/cyan]: ${limit_val:.2f}/month",
            config.quiet,
        )
        return

    if remove_override_jhed is not None:
        overrides_table = _resolve_overrides_table(config)
        _remove_override(config, overrides_table, remove_override_jhed)
        print_success(
            f"Override removed for [cyan]{remove_override_jhed}[/cyan] — reverted to default",
            config.quiet,
        )
        return

    # Resolve period
    resolved_period = period or datetime.now(UTC).strftime("%Y-%m")

    # Discover table and fetch usage
    with spinner(personality.status_checking_quota(), config.quiet):
        table_name = _resolve_quota_table(config)
        usage = _get_usage(config, table_name, user_id, resolved_period)

    input_tokens = int(usage.get("input_tokens", 0))
    output_tokens = int(usage.get("output_tokens", 0))
    total_tokens = input_tokens + output_tokens
    request_count = int(usage.get("request_count", 0))
    last_updated = usage.get("last_updated", "never")

    # --- Cost-aware display ---
    cost_usd = float(usage.get("cost_usd", 0))
    rollover_usd = float(usage.get("rollover_usd", 0))
    burst_used_usd = float(usage.get("burst_used_usd", 0))

    # Resolve cost limit
    try:
        overrides_table = _resolve_overrides_table(config)
        cost_limit = _get_cost_limit(config, overrides_table, user_id)
    except AliceCLIError:
        # Overrides table not deployed — use env var default
        import os

        cost_limit = float(os.environ.get("CHESHIRE_GATE_DEFAULT_COST_LIMIT", "10.0"))

    warning_threshold = _get_warning_threshold()
    pct_used = (cost_usd / cost_limit * 100) if cost_limit > 0 else 0.0
    bar_color = _cost_bar_color(pct_used, warning_threshold)

    # Display
    err_console.print()
    if not config.quiet:
        err_console.print(LOGO_CHESHIRE_GATE, style="bold magenta")
    err_console.print("  [bold]Cheshire Gate — Token Usage[/bold]")
    err_console.print(f"  User:          [cyan]{user_id}[/cyan]")
    err_console.print(f"  Period:        {resolved_period}")
    err_console.print()
    err_console.print(f"  Input tokens:  {input_tokens:>12,}")
    err_console.print(f"  Output tokens: {output_tokens:>12,}")
    err_console.print(f"  Total tokens:  {total_tokens:>12,}")
    err_console.print(f"  Requests:      {request_count:>12,}")
    err_console.print(f"  Last activity: {last_updated}")
    err_console.print()

    # Cost progress bar
    err_console.print(f"  Cost:          ${cost_usd:>10.2f} / ${cost_limit:.2f}")
    clamped_pct = min(pct_used, 100.0)
    filled = int(clamped_pct / 100 * 30)
    empty = 30 - filled
    bar_str = "█" * filled + "░" * empty
    err_console.print(f"  [{bar_color}]{bar_str}[/{bar_color}] {pct_used:.1f}%")

    if rollover_usd > 0:
        err_console.print(f"  Rollover:      ${rollover_usd:>10.2f}")
    if burst_used_usd > 0:
        err_console.print(f"  Burst used:    ${burst_used_usd:>10.2f}")

    err_console.print()

    if total_tokens == 0:
        print_status(personality.quota_no_usage(resolved_period), config.quiet)
    else:
        print_success(personality.quota_summary(total_tokens, request_count), config.quiet)
