"""Keiro setup command — guided credential configuration.

Probes the gateway to determine available onboarding paths, then presents
only the options that will actually work. Credentials are persisted to
``~/.keiro/credentials``.
"""

from __future__ import annotations

import argparse
import sys

import requests
from rich.console import Console

from keiro.cli.animations import (
    Spinner,
    _input_masked,
    prompt_with_live_header,
    shimmer_once,
)
from keiro.client import _build_url
from keiro.defaults import DEFAULT_GATEWAY_URL


def _mask_key(key: str) -> str:
    """Mask an API key for display: ``keiro_sk...7e41``."""
    if len(key) <= 12:
        return "****"
    return key[:8] + "..." + key[-4:]


def _redact_input_line(prompt_text: str, value: str) -> None:
    """Overwrite the previous input line with a masked version of *value*."""
    masked = _mask_key(value)
    sys.stdout.write(f"\033[s\033[1A\r{prompt_text}{masked}\033[K\033[u")
    sys.stdout.flush()


_TEST_PROMPT = "In one paragraph, what is machine learning?"

_NEXT_STEPS = """\
  Next:
    from keiro import models
    print(models("eb1-preview", "Explain quantum computing"))
"""


def build_parser() -> argparse.ArgumentParser:
    """Build the argument parser for ``keiro setup``."""
    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument(
        "--gateway-url",
        default=None,
        help="Gateway base URL (overrides default).",
    )
    parser.add_argument(
        "--api-key",
        default=None,
        help="API key (skips interactive prompt).",
    )
    return parser


def run(args: argparse.Namespace) -> int:
    """Execute the setup flow."""
    console = Console()

    gateway_url = args.gateway_url or DEFAULT_GATEWAY_URL
    api_key = args.api_key

    # Non-interactive: validate and save directly.
    if api_key:
        console.print()
        shimmer_once(console, "Keiro")
        console.print()
        return _validate_and_save(console, api_key, gateway_url)

    signup_available = _check_signup(gateway_url)

    if signup_available:
        choice = prompt_with_live_header(
            console,
            header="Keiro",
            body_lines=[
                "  How would you like to get started?",
                "  [dim][1][/dim] Create a new account",
                "  [dim][2][/dim] I already have an API key",
            ],
            prompt_text="  > ",
        ).strip()

        if choice == "1":
            return _flow_create_account(console, gateway_url)
        elif choice == "2":
            return _flow_existing_key(console, gateway_url)
        else:
            console.print(f"  Unknown option: {choice!r}")
            return 1
    else:
        api_key = prompt_with_live_header(
            console,
            header="Keiro",
            body_lines=[
                "  [dim]Enter your API key to get started.[/dim]",
            ],
            prompt_text="  API key: ",
            secret=True,
        ).strip()

        if not api_key:
            console.print("  API key cannot be empty.")
            return 1

        _redact_input_line("  API key: ", api_key)
        return _validate_and_save(console, api_key, gateway_url)


def _check_signup(gateway_url: str) -> bool:
    """Probe the gateway to see if self-service signup is available."""
    url = _build_url(gateway_url, "/v1/auth/register")
    try:
        resp = requests.post(url, json={}, timeout=3)
        return resp.status_code != 404
    except (requests.ConnectionError, requests.Timeout):
        return False


def _flow_existing_key(console: Console, gateway_url: str) -> int:
    """Secondary path: user chose 'I already have an API key' from menu."""
    api_key = _prompt("  API key: ", secret=True).strip()
    if not api_key:
        console.print("  API key cannot be empty.")
        return 1

    _redact_input_line("  API key: ", api_key)
    return _validate_and_save(console, api_key, gateway_url)


def _flow_create_account(console: Console, gateway_url: str) -> int:
    """Path: create a new account via the signup endpoint."""
    email = _prompt("  Email: ").strip()
    if not email or "@" not in email:
        console.print("  A valid email address is required.")
        return 1

    console.print()
    signup_url = _build_url(gateway_url, "/v1/auth/register")
    resp = None

    with Spinner(console, "Creating account"):
        try:
            resp = requests.post(
                signup_url,
                json={"email": email},
                timeout=15,
            )
        except (requests.ConnectionError, requests.Timeout):
            pass

    if resp is None:
        console.print(
            f"  Could not connect to Keiro at {gateway_url}. "
            "Check your network connection and try again."
        )
        return 1

    if resp.status_code == 409:
        console.print("  An account with this email already exists.")
        console.print("  Run 'keiro setup' again with your existing API key.")
        return 1

    if resp.status_code != 201:
        from keiro.client import extract_error_detail

        detail = extract_error_detail(resp)
        if detail:
            console.print(f"  Signup failed: {detail}")
        else:
            console.print(f"  Signup failed (HTTP {resp.status_code}). Try again later.")
        return 1

    try:
        data = resp.json()
    except ValueError:
        console.print("  Unexpected response from server.")
        return 1

    api_key = data.get("api_key")
    if not api_key:
        console.print("  No API key in signup response.")
        return 1

    console.print("  [bold green]Done.[/bold green]")
    console.print()
    console.print(f"  Your API key: [bold]{api_key}[/bold]")
    console.print("  [dim](Save this -- it will not be shown again.)[/dim]")
    console.print()
    return _finish(console, api_key, gateway_url)


def _validate_and_save(console: Console, api_key: str, gateway_url: str) -> int:
    """Validate an API key against the gateway and persist to config."""
    console.print()
    models_url = _build_url(gateway_url, "/v1/models")
    resp = None

    with Spinner(console, "Validating"):
        try:
            resp = requests.get(
                models_url,
                headers={"Authorization": f"Bearer {api_key}"},
                timeout=10,
            )
        except (requests.ConnectionError, requests.Timeout):
            pass

    if resp is None:
        console.print(
            f"  Could not connect to Keiro at {gateway_url}. "
            "Check your network connection and try again."
        )
        return 1

    if resp.status_code == 401:
        console.print("  Invalid API key. Check that you copied the full key.")
        return 1

    if resp.status_code == 403:
        console.print("  API key is valid but does not have access. Contact support.")
        return 1

    if resp.status_code >= 400:
        from keiro.client import extract_error_detail

        detail = extract_error_detail(resp)
        if detail:
            console.print(f"  Setup failed: {detail}")
        else:
            console.print(f"  Unexpected error (HTTP {resp.status_code}). Try again later.")
        return 1

    console.print("  [bold green]Done.[/bold green]")
    console.print()
    return _finish(console, api_key, gateway_url)


def _finish(console: Console, api_key: str, gateway_url: str) -> int:
    """Save credentials, stream a live test call, and print next steps."""
    path = _save_config(api_key, gateway_url)
    console.print(f"  Saved to {path}")
    console.print()
    _stream_test_call(console, api_key, gateway_url)
    console.print()
    console.print(_NEXT_STEPS)
    return 0


def _stream_test_call(console: Console, api_key: str, gateway_url: str) -> None:
    """Make a live eb1-preview call and print the response with a typewriter effect."""
    from keiro.cli.animations import animations_enabled

    console.print(f"  [dim]> {_TEST_PROMPT}[/dim]")
    console.print()

    url = _build_url(gateway_url, "/v1/chat/completions")
    payload = {
        "model": "eb1-preview",
        "messages": [{"role": "user", "content": _TEST_PROMPT}],
    }
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    }
    resp = None
    with Spinner(console, "eb1-preview"):
        try:
            resp = requests.post(url, json=payload, headers=headers, timeout=120)
        except (requests.ConnectionError, requests.Timeout):
            pass

    if resp is None:
        console.print("  [dim](Could not reach gateway for test call.)[/dim]")
        return
    if resp.status_code >= 400:
        console.print("  [dim](Test call returned an error — skipping.)[/dim]")
        return

    try:
        data = resp.json()
    except ValueError:
        return

    # Extract text from chat completions response.
    text = ""
    choices = data.get("choices")
    if isinstance(choices, list) and choices:
        message = choices[0].get("message", {})
        text = message.get("content", "")
    if not text:
        return

    if not animations_enabled():
        console.print(f"  [bold]eb1-preview[/bold] [dim]\u25b6[/dim] {text}")
        return

    _typewriter(text)


def _typewriter(text: str, char_delay: float = 0.008, wrap_at: int = 72) -> None:
    """Print *text* character-by-character with word-wrap.

    Uses raw ANSI for the prefix line — only called when TTY is confirmed.
    """
    import time

    sys.stdout.write("  \033[1meb1-preview\033[0m \033[2m\u25b6\033[0m ")
    sys.stdout.flush()
    col = 16  # Account for visible prefix width.
    for char in text:
        if char == "\n":
            sys.stdout.write("\n  ")
            sys.stdout.flush()
            col = 2
            continue
        if col >= wrap_at and char == " ":
            sys.stdout.write("\n  ")
            sys.stdout.flush()
            col = 2
            continue
        sys.stdout.write(char)
        sys.stdout.flush()
        col += 1
        time.sleep(char_delay)
    sys.stdout.write("\n")
    sys.stdout.flush()


def _save_config(api_key: str, gateway_url: str) -> str:
    """Persist Keiro credentials to ``~/.keiro/credentials``."""
    from keiro.credentials import save_credentials

    path = save_credentials(api_key, gateway_url)
    return "~/.keiro/credentials" if "/.keiro/" in str(path) else str(path)


def _prompt(text: str, default: str = "", secret: bool = False) -> str:
    """Read a line from stdin with a default value.

    Args:
        text: Prompt string to display.
        default: Value to return if user enters nothing.
        secret: If True, show * per character instead of plaintext.
    """
    try:
        value = _input_masked(text) if secret else input(text)
    except (EOFError, KeyboardInterrupt):
        print()
        sys.exit(1)
    return value if value else default
