from __future__ import annotations

import getpass
import sys
from typing import Callable, TextIO

from ..config import ConfigManager
from .web_ui import _PROVIDER_PRESETS, update_onboarding_from_form, validate_onboarding_form

InputFn = Callable[[str], str]
SecretFn = Callable[[str], str]


def _supports_color(stream: TextIO) -> bool:
    isatty = getattr(stream, "isatty", None)
    return bool(isatty and isatty())


def _paint(text: str, code: str, *, stream: TextIO) -> str:
    if not _supports_color(stream):
        return text
    return f"\033[{code}m{text}\033[0m"


def _rule(title: str, *, stream: TextIO) -> None:
    line = "─" * max(10, 72 - len(title))
    print(f"{_paint(title, '1;36', stream=stream)} {line}", file=stream)


def _info(message: str, *, stream: TextIO) -> None:
    print(_paint(message, "36", stream=stream), file=stream)


def _warn(message: str, *, stream: TextIO) -> None:
    print(_paint(message, "33", stream=stream), file=stream)


def _success(message: str, *, stream: TextIO) -> None:
    print(_paint(message, "32", stream=stream), file=stream)


def _prompt_text(prompt: str, *, default: str = "", input_fn: InputFn, stream: TextIO) -> str:
    suffix = f" [{default}]" if default else ""
    raw = input_fn(f"{prompt}{suffix}: ").strip()
    return raw or default


def _prompt_secret(
    prompt: str,
    *,
    current: str = "",
    required: bool,
    secret_fn: SecretFn,
    stream: TextIO,
) -> str:
    while True:
        suffix = " [leave blank to keep current]" if current else ""
        value = secret_fn(f"{prompt}{suffix}: ").strip()
        if value:
            return value
        if current:
            return current
        if not required:
            return ""
        _warn(f"{prompt} is required.", stream=stream)


def _prompt_provider(*, default: str, input_fn: InputFn, stream: TextIO) -> str:
    names = list(_PROVIDER_PRESETS)
    labels = {name: _PROVIDER_PRESETS[name]["label"] for name in names}
    _rule("Provider", stream=stream)
    for index, name in enumerate(names, start=1):
        marker = "★" if name == default else " "
        print(f" {marker} {index}. {labels[name]}", file=stream)
    while True:
        raw = input_fn(f"Choose default provider [{default}]: ").strip().lower()
        if not raw:
            return default
        if raw in labels:
            return raw
        if raw.isdigit():
            idx = int(raw) - 1
            if 0 <= idx < len(names):
                return names[idx]
        _warn("Use provider name or number from the list above.", stream=stream)


def _confirm(prompt: str, *, default: bool, input_fn: InputFn, stream: TextIO) -> bool:
    suffix = "[Y/n]" if default else "[y/N]"
    raw = input_fn(f"{prompt} {suffix}: ").strip().lower()
    if not raw:
        return default
    return raw in {"y", "yes", "д", "да"}


def run_terminal_onboarding(
    config_path: str,
    *,
    input_fn: InputFn = input,
    secret_fn: SecretFn = getpass.getpass,
    stream: TextIO | None = None,
) -> bool:
    stream = stream or sys.stdout
    manager = ConfigManager(config_path)
    config = manager.data
    providers = ((config.get("providers", {}) or {}).get("items", {}) or {})
    default_provider = str((config.get("providers", {}) or {}).get("default", "openai") or "openai")
    if default_provider not in _PROVIDER_PRESETS:
        default_provider = "openai"

    form = {
        "telegram_bot_token": str((config.get("telegram", {}) or {}).get("bot_token", "")),
        "telegram_owner_user_ids": ",".join(str(x) for x in (config.get("telegram", {}) or {}).get("owner_user_ids", [])),
        "telegram_allowed_chat_ids": ",".join(str(x) for x in (config.get("telegram", {}) or {}).get("allowed_chat_ids", [])),
        "default_provider": default_provider,
    }
    for name, preset in _PROVIDER_PRESETS.items():
        entry = dict(providers.get(name, {}) or {})
        form[f"{name}_api_key"] = str(entry.get("api_key", ""))
        form[f"{name}_default_model"] = str(entry.get("default_model") or preset["default_model"])

    try:
        _rule("LiteClaw onboard", stream=stream)
        _info("Terminal quickstart wizard. It saves config and starts LiteClaw right after confirmation.", stream=stream)
        print(file=stream)

        _rule("Telegram", stream=stream)
        form["telegram_bot_token"] = _prompt_secret(
            "Telegram Bot Token",
            current=form["telegram_bot_token"],
            required=True,
            secret_fn=secret_fn,
            stream=stream,
        )
        form["telegram_owner_user_ids"] = _prompt_text(
            "Owner User IDs (comma-separated, optional)",
            default=form["telegram_owner_user_ids"],
            input_fn=input_fn,
            stream=stream,
        )
        form["telegram_allowed_chat_ids"] = _prompt_text(
            "Allowed Chat IDs (comma-separated, optional)",
            default=form["telegram_allowed_chat_ids"],
            input_fn=input_fn,
            stream=stream,
        )

        provider_name = _prompt_provider(default=form["default_provider"], input_fn=input_fn, stream=stream)
        form["default_provider"] = provider_name
        preset = _PROVIDER_PRESETS[provider_name]

        print(file=stream)
        _rule(f"{preset['label']} settings", stream=stream)
        form[f"{provider_name}_api_key"] = _prompt_secret(
            preset["api_key_label"],
            current=form[f"{provider_name}_api_key"],
            required=True,
            secret_fn=secret_fn,
            stream=stream,
        )
        form[f"{provider_name}_default_model"] = _prompt_text(
            f"{preset['label']} default model",
            default=form[f"{provider_name}_default_model"],
            input_fn=input_fn,
            stream=stream,
        )

        print(file=stream)
        _rule("Summary", stream=stream)
        print(f" Bot token: {'configured' if form['telegram_bot_token'] else 'missing'}", file=stream)
        print(f" Default provider: {preset['label']}", file=stream)
        print(f" Owner ids: {form['telegram_owner_user_ids'] or 'not set'}", file=stream)
        print(f" Allowed chat ids: {form['telegram_allowed_chat_ids'] or 'not set'}", file=stream)
        print(f" Provider key: {'configured' if form[f'{provider_name}_api_key'] else 'missing'}", file=stream)
        print(f" Model: {form[f'{provider_name}_default_model']}", file=stream)

        if not _confirm("Save config and launch LiteClaw now?", default=True, input_fn=input_fn, stream=stream):
            _warn("Onboarding cancelled. Config was not changed.", stream=stream)
            return False

        errors = validate_onboarding_form(form)
        if errors:
            for error in errors:
                _warn(error, stream=stream)
            return False

        update_onboarding_from_form(manager, form)
        _success("Config saved. Launching LiteClaw…", stream=stream)
        return True
    except KeyboardInterrupt:
        print(file=stream)
        _warn("Onboarding cancelled.", stream=stream)
        return False
