"""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_token = _resolve_admin_if_active(admin_flag, creds)

    # 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)

    # 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,
        )

    # 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,
            )
        return 0

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


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."""
    print(f"""\
keiro {keiro.__version__} -- EB1 multi-model ensemble 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:
  eb1-preview (default)  Adaptive frontier ensemble
  eb1-delta-preview      Adaptive ensemble with orchestration
  eb1                    Standard ensemble
  eb1-pro                Extended capability
  eb1-frontier           Highest quality, max reasoning
  eb1-codex              Optimized for code / SWE
  eb1-fast               Low latency
  eb1-fast-preview       Adaptive routing, low latency
  eb1-frontier-preview   Adaptive routing, max quality""")


def _resolve_admin_if_active(
    flag: bool,
    creds: dict[str, str],
) -> str | None:
    """Return admin token if admin mode is active, else None.

    Admin mode is active when:
    - ``--admin`` flag was passed (one-shot override), OR
    - ``admin_mode: on`` is set in credentials (persistent toggle)

    Token resolution: ``KEIRO_ADMIN_TOKEN`` env var > credentials file.
    """
    active = flag or creds.get("admin_mode") == "on"
    if not active:
        return None
    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,
) -> 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,
            )
        from keiro.cli.repl import repl
        return repl(model=model, admin_token=admin_token)

    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())
