"""Keiro command-line interface.

Usage::

    keiro                          # interactive REPL
    keiro "What is ML?"            # one-shot response
    echo ctx | keiro "Summarize"   # pipe context as input
    keiro -m eb1-pro "Hard task"   # use a specific model
    keiro setup                    # configure credentials
    keiro serve                    # start inference gateway
    keiro --version
"""

from __future__ import annotations

import logging
import os
import sys

import keiro
from keiro.defaults import DEFAULT_MODEL

_SUBCOMMANDS = frozenset({"serve", "setup", "models", "admin"})


def main(argv: list[str] | None = None) -> int:
    """Keiro CLI entry point.

    Subcommands (serve, setup) are dispatched first. Everything else is
    treated as a prompt for one-shot or REPL mode.

    Args:
        argv: Command-line arguments. Defaults to sys.argv[1:].

    Returns:
        Exit code.
    """
    args = list(argv if argv is not None else sys.argv[1:])

    # --version / -V
    if "--version" in args or "-V" in args:
        print(f"keiro {keiro.__version__}")
        return 0

    # Subcommand dispatch: check before consuming flags.
    # Pass remaining args (including --help) to the subcommand parser.
    first_positional = next((a for a in args if not a.startswith("-")), None)
    if first_positional in _SUBCOMMANDS:
        idx = args.index(first_positional)
        return _dispatch_subcommand(first_positional, args[:idx] + args[idx + 1:])

    # --help / -h (only when no subcommand)
    if "--help" in args or "-h" in args:
        _print_usage()
        return 0

    # Admin mode: persistent setting (keiro admin) or one-shot flag.
    admin_flag = "--admin" in args
    if admin_flag:
        args = [a for a in args if a != "--admin"]

    # Load credentials once for both admin resolution and auth check.
    from keiro.credentials import load_credentials
    creds = load_credentials()

    admin_enabled = _is_admin_enabled(admin_flag, creds)
    admin_token = _resolve_admin_token(creds) if admin_enabled else None

    # Extract -m / --model flag from anywhere in args.
    model, args = _extract_model_flag(args)

    logging.basicConfig(
        level=os.environ.get("KEIRO_LOG_LEVEL", "WARNING"),
        format="%(asctime)s %(levelname)s %(name)s: %(message)s",
    )

    from keiro.cli.repl import _read_stdin_context, one_shot, repl

    # Check credentials before making any API call. If missing and
    # running interactively, offer to run setup inline.
    has_key = bool(os.environ.get("KEIRO_API_KEY") or creds.get("api_key"))
    if not has_key and sys.stdin.isatty():
        return _prompt_setup_then_retry(
            model, args, admin_token=admin_token, admin=admin_enabled,
        )

    # Remaining args joined as the prompt.
    prompt = " ".join(args) if args else None

    if prompt:
        context = _read_stdin_context()
        return one_shot(
            prompt, model=model, context=context,
            admin_token=admin_token, admin=admin_enabled,
        )

    # No prompt, piped stdin: treat stdin as the prompt.
    if not sys.stdin.isatty():
        stdin_text = _read_stdin_context()
        if stdin_text and stdin_text.strip():
            return one_shot(
                stdin_text.strip(), model=model,
                admin_token=admin_token, admin=admin_enabled,
            )
        return 0

    # Interactive REPL.
    return repl(
        model=model, admin_token=admin_token, admin=admin_enabled,
    )


def _extract_model_flag(args: list[str]) -> tuple[str, list[str]]:
    """Extract -m/--model from args, returning (model, remaining_args)."""
    model = DEFAULT_MODEL
    remaining: list[str] = []
    i = 0
    while i < len(args):
        if args[i] in ("-m", "--model") and i + 1 < len(args):
            model = args[i + 1]
            i += 2
        elif args[i].startswith("-m") and len(args[i]) > 2:
            model = args[i][2:]
            i += 1
        elif args[i].startswith("--model="):
            model = args[i].split("=", 1)[1]
            i += 1
        else:
            remaining.append(args[i])
            i += 1
    return model, remaining


def _dispatch_subcommand(command: str, rest: list[str]) -> int:
    """Dispatch to a named subcommand."""
    logging.basicConfig(
        level=os.environ.get("KEIRO_LOG_LEVEL", "INFO"),
        format="%(asctime)s %(levelname)s %(name)s: %(message)s",
    )

    if command == "serve":
        from keiro.cli.serve import build_parser, run
        parser = build_parser()
        args = parser.parse_args(rest)
        return run(args)

    if command == "setup":
        from keiro.cli.setup import build_parser, run
        parser = build_parser()
        args = parser.parse_args(rest)
        return run(args)

    if command == "models":
        from keiro.cli.models import build_parser, run
        parser = build_parser()
        args = parser.parse_args(rest)
        return run(args)

    if command == "admin":
        from keiro.cli.admin import build_parser, run
        parser = build_parser()
        args = parser.parse_args(rest)
        return run(args)

    return 1


def _print_usage() -> None:
    """Print usage help with model list derived from the descriptions registry."""
    from keiro.cli.models import list_model_descriptions

    lines = [
        f"keiro {keiro.__version__} -- EB1 compound AI inference",
        "",
        "Usage:",
        "  keiro                          Interactive chat REPL",
        '  keiro "prompt"                 One-shot response',
        '  keiro -m eb1-pro "prompt"      Use a specific model',
        '  echo ctx | keiro "prompt"      Pipe context as input',
        "  keiro setup                    Configure API credentials",
        "  keiro serve                    Start inference gateway",
        "  keiro models                   List available models and rate limits",
        "  keiro admin                    Toggle admin metrics (persistent)",
        "  keiro --version                Show version",
        "",
        "Models:",
    ]

    # Show primary variants (no dated snapshots) from the descriptions
    # registry. Stays in sync when new models are added to models.py.
    for model_key, desc in list_model_descriptions().items():
        # Skip dated snapshots (e.g. eb1-preview-03212026).
        suffix = model_key.rsplit("-", 1)[-1]
        if len(suffix) >= 8 and suffix.isdigit():
            continue
        label = f"{model_key} (default)" if model_key == DEFAULT_MODEL else model_key
        lines.append(f"  {label:<22} {desc}")

    lines.append("")
    lines.append("  Run 'keiro models' for the full list including snapshots.")
    print("\n".join(lines))


def _is_admin_enabled(flag: bool, creds: dict[str, str]) -> bool:
    """Whether admin mode is active via flag or persistent setting."""
    return flag or creds.get("admin_mode") == "on"


def _resolve_admin_token(creds: dict[str, str]) -> str | None:
    """Resolve admin token from env var or credentials file."""
    return (
        os.environ.get("KEIRO_ADMIN_TOKEN")
        or creds.get("admin_token")
        or None
    )


def _prompt_setup_then_retry(
    model: str,
    original_args: list[str],
    *,
    admin_token: str | None = None,
    admin: bool = False,
) -> int:
    """Offer to run setup when no credentials are configured.

    After successful setup, re-dispatches the original command so the user
    doesn't have to type it again.
    """
    sys.stderr.write(
        "\033[33mNo API key configured.\033[0m\n"
    )
    try:
        answer = input("Run setup now? [Y/n] ").strip().lower()
    except (EOFError, KeyboardInterrupt):
        sys.stderr.write("\n")
        return 1

    if answer in ("", "y", "yes"):
        import argparse

        from keiro.cli.setup import run
        result = run(argparse.Namespace(gateway_url=None, api_key=None))
        if result != 0:
            return result
        # Credentials saved — retry the original command.
        prompt = " ".join(original_args) if original_args else None
        if prompt:
            from keiro.cli.repl import _read_stdin_context, one_shot
            context = _read_stdin_context()
            return one_shot(
                prompt, model=model, context=context,
                admin_token=admin_token, admin=admin,
            )
        from keiro.cli.repl import repl
        return repl(
            model=model, admin_token=admin_token, admin=admin,
        )

    sys.stderr.write("Run 'keiro setup' or set KEIRO_API_KEY.\n")
    return 1


def cli_entry() -> None:
    """Script entry point for ``pyproject.toml [project.scripts]``."""
    sys.exit(main())
