"""``keiro models`` — list available models and rate limits.

Two modes:
    - **Online (default):** fetches from the gateway via ``Client.get_models()``,
      including ``rate_limits`` when upstream quotas are configured.
    - **Offline (``--local``):** lists from the local variant registry with no
      network calls; rate limits are not shown.

Examples::

    keiro models                       # online, table format
    keiro models --local               # offline, table format
    keiro models --format json         # online, JSON output
    keiro models --local --format json # offline, JSON output
"""

from __future__ import annotations

import argparse
import json
import sys
from collections.abc import Mapping
from typing import Any

# Customer-safe descriptions. Never expose internal details like GNN,
# candidates, judge, fan-out, or provider names.
_MODEL_DESCRIPTIONS: dict[str, str] = {
    "eb1-delta-preview": "Adaptive model with orchestration",
    "eb1-preview": "Adaptive frontier model",
    "eb1": "Standard multi-model",
    "eb1-synth": "Synthesize mode",
    "eb1-pro": "Extended capability",
    "eb1-frontier": "Highest quality, max reasoning",
    "eb1-codex": "Optimized for code and SWE",
    "eb1-codex-high": "Code-optimized, max reasoning",
    "eb1-fast": "Low latency, lighter models",
    "eb1-fast-preview": "Adaptive routing, low latency",
    "eb1-frontier-preview": "Adaptive routing, max quality",
    "eb1-swe": "Coding optimized",
    "eb1-swe-pro": "Coding, extended",
    "eb1-swe-frontier": "Coding, max quality",
    "eb1-swe-fast": "Coding, low latency",
    "eb1-pro-high": "Extended capability, max reasoning",
    "eb1-preview-03212026": "Adaptive frontier model (2026-03-21 snapshot)",
    "eb1-delta-preview-03212026": "Adaptive model with orchestration (2026-03-21 snapshot)",
    "eb1-fast-preview-03212026": "Adaptive routing, low latency (2026-03-21 snapshot)",
    "eb1-frontier-preview-03212026": "Adaptive routing, max quality (2026-03-21 snapshot)",
}


def get_model_description(model: str) -> str:
    """Return the customer-safe description for a model, or empty string."""
    return _MODEL_DESCRIPTIONS.get(model, "")


def list_model_descriptions() -> Mapping[str, str]:
    """Return all customer-safe model descriptions keyed by model id."""
    return _MODEL_DESCRIPTIONS


def build_parser() -> argparse.ArgumentParser:
    """Build argument parser for ``keiro models``."""
    parser = argparse.ArgumentParser(
        prog="keiro models",
        description="List available EB1 models and rate limits.",
    )
    parser.add_argument(
        "--local",
        action="store_true",
        help="List from local variant registry (no network call).",
    )
    parser.add_argument(
        "--format",
        choices=("table", "json"),
        default="table",
        dest="output_format",
        help="Output format (default: table).",
    )
    parser.add_argument(
        "--gateway-url",
        default=None,
        help="Override gateway URL for online mode.",
    )
    return parser


def run(args: argparse.Namespace) -> int:
    """Execute ``keiro models``."""
    if args.local:
        return _run_local(args.output_format)
    return _run_remote(args.output_format, gateway_url=args.gateway_url)


# ---------------------------------------------------------------------------
# Local mode
# ---------------------------------------------------------------------------


def _run_local(output_format: str) -> int:
    """List models from the local variant registry."""
    from keiro.defaults import DEFAULT_MODEL
    from keiro.ensemble.catalog import all_variants

    rows: list[dict[str, Any]] = []
    for variant in all_variants():
        desc = _MODEL_DESCRIPTIONS.get(variant.key, "")
        if variant.key == DEFAULT_MODEL and desc:
            desc += " (default)"
        rows.append({"model": variant.key, "description": desc})

    if output_format == "json":
        json.dump(rows, sys.stdout, indent=2)
        sys.stdout.write("\n")
        return 0

    _print_table(rows, has_limits=False)
    return 0


# ---------------------------------------------------------------------------
# Remote mode
# ---------------------------------------------------------------------------


def _run_remote(output_format: str, *, gateway_url: str | None) -> int:
    """Fetch models from the gateway and display them."""
    from keiro.client import Client, KeirError

    try:
        kwargs: dict[str, Any] = {}
        if gateway_url:
            kwargs["base_url"] = gateway_url
        client = Client(**kwargs)
        data = client.get_models()
    except KeirError as exc:
        print(
            f"Could not reach gateway: {exc.user_message}\n"
            "Hint: use --local to list models without a "
            "gateway connection.",
            file=sys.stderr,
        )
        return 1
    except Exception:
        print(
            "Could not reach gateway. Check your network "
            "connection.\n"
            "Hint: use --local to list models without a "
            "gateway connection.",
            file=sys.stderr,
        )
        return 1

    entries = data.get("data", []) if isinstance(data, dict) else []

    rows: list[dict[str, Any]] = []
    has_limits = False
    for entry in entries:
        if not isinstance(entry, dict):
            continue
        model_id = entry.get("id", "")
        # Only show eb1 variants, not passthrough models.
        # Skip provider-namespaced duplicates like "eb1/eb1-preview".
        if not model_id.startswith("eb1") or "/" in model_id:
            continue
        row: dict[str, Any] = {
            "model": model_id,
            "description": (entry.get("description") or _MODEL_DESCRIPTIONS.get(model_id, "")),
        }
        rate_limits = entry.get("rate_limits")
        if isinstance(rate_limits, dict):
            row["rpm"] = rate_limits.get("rpm")
            row["tpm"] = rate_limits.get("tpm")
            has_limits = True
        rows.append(row)

    if output_format == "json":
        json.dump(rows, sys.stdout, indent=2)
        sys.stdout.write("\n")
        return 0

    if not rows:
        print("No EB1 models found on the gateway.", file=sys.stderr)
        return 1

    _print_table(rows, has_limits=has_limits)
    return 0


# ---------------------------------------------------------------------------
# Table rendering
# ---------------------------------------------------------------------------


def _print_table(
    rows: list[dict[str, Any]],
    *,
    has_limits: bool,
) -> None:
    """Print a formatted table of models to stdout."""
    if not rows:
        return

    headers = ["Model", "Description"]
    if has_limits:
        headers.extend(["RPM", "TPM"])

    # Compute column widths.
    widths = [len(h) for h in headers]
    formatted_rows: list[list[str]] = []
    for row in rows:
        cells = [
            row.get("model", ""),
            row.get("description", ""),
        ]
        if has_limits:
            rpm = row.get("rpm")
            tpm = row.get("tpm")
            cells.append(f"{rpm:,}" if rpm is not None else "-")
            cells.append(f"{tpm:,}" if tpm is not None else "-")
        formatted_rows.append(cells)
        for i, cell in enumerate(cells):
            widths[i] = max(widths[i], len(cell))

    # Print header.
    header_line = "  ".join(h.ljust(widths[i]) for i, h in enumerate(headers))
    separator = "  ".join("-" * widths[i] for i in range(len(headers)))
    print(header_line)
    print(separator)

    # Print rows.
    for cells in formatted_rows:
        line = "  ".join(
            cells[i].rjust(widths[i]) if i >= 2 else cells[i].ljust(widths[i])
            for i in range(len(cells))
        )
        print(line)
