"""Config file reader/writer for ~/.reviewate/config.toml

Stores model preferences only (no secrets). API keys come from env vars.
"""

from __future__ import annotations

import tomllib
from pathlib import Path

from pydantic import BaseModel, model_validator
from rich.console import Console
from rich.panel import Panel
from rich.prompt import Prompt

_console = Console(highlight=False)

CONFIG_PATH = Path.home() / ".reviewate" / "config.toml"

# Providers where litellm knows the model catalog
_VALIDATABLE_PROVIDERS = {"gemini", "anthropic", "openai", "openrouter"}


def _validate_model_exists(provider_model: str) -> str | None:
    """Check provider/model against litellm. Returns error message or None."""
    if "/" not in provider_model:
        return f"Invalid format '{provider_model}' — expected 'provider/model'"
    provider = provider_model.split("/", 1)[0]
    if provider not in _VALIDATABLE_PROVIDERS:
        return None
    try:
        from litellm import get_model_info

        get_model_info(provider_model)
        return None
    except Exception:
        return f"Unknown model '{provider_model}'. Check the name."


class ModelsConfig(BaseModel):
    review: str
    utility: str

    @model_validator(mode="after")
    def check_models(self) -> ModelsConfig:
        errors: list[str] = []
        for field in ("review", "utility"):
            val = getattr(self, field)
            if "/" not in val:
                errors.append(f"models.{field}: expected 'provider/model', got '{val}'")
                continue
            err = _validate_model_exists(val)
            if err:
                errors.append(f"models.{field}: {err}")
        if errors:
            raise ValueError("\n".join(errors))
        return self


class OpenRouterConfig(BaseModel):
    review_provider_order: str | None = None
    utility_provider_order: str | None = None


class ConfigFile(BaseModel):
    models: ModelsConfig
    urls: dict[str, str] | None = None
    openrouter: OpenRouterConfig | None = None


def validate_config_file(data: dict[str, object]) -> list[str]:
    """Validate config file data. Returns list of error messages (empty = valid)."""
    try:
        ConfigFile(**data)  # type: ignore[arg-type]
        return []
    except ValueError as e:
        errors: list[str] = []
        for line in str(e).splitlines():
            stripped = line.strip()
            if not stripped:
                continue
            if stripped.startswith(("For further", "[type=")):
                continue
            if "validation error" in stripped.lower():
                continue
            # Clean "Value error, ..." prefix
            if stripped.startswith("Value error, "):
                stripped = stripped[len("Value error, ") :]
            # Strip trailing pydantic metadata like [type=..., input_value=...]
            if " [type=" in stripped:
                stripped = stripped[: stripped.index(" [type=")]
            errors.append(stripped)
        return errors or ["Invalid config file"]


def load_config_file(path: Path = CONFIG_PATH) -> dict[str, object] | None:
    """Load config from TOML file. Returns None if file doesn't exist."""
    if not path.is_file():
        return None
    with open(path, "rb") as f:
        return tomllib.load(f)


def save_config_file(data: dict[str, object], path: Path = CONFIG_PATH) -> None:
    """Write config dict to TOML file (simple key=value serialization)."""
    path.parent.mkdir(parents=True, exist_ok=True)
    lines: list[str] = []
    for section, values in data.items():
        lines.append(f"[{section}]")
        if isinstance(values, dict):
            for key, val in values.items():
                lines.append(f'{key} = "{val}"')
        lines.append("")
    path.write_text("\n".join(lines))


def get_config_model(tier: str, data: dict[str, object]) -> str | None:
    """Get 'provider/model' string for a tier from config data."""
    models = data.get("models")
    if not isinstance(models, dict):
        return None
    val = models.get(tier)
    return str(val) if val else None


def get_config_openrouter_order(tier: str, data: dict[str, object]) -> str | None:
    """Get OpenRouter provider order for a tier from config data."""
    section = data.get("openrouter")
    if not isinstance(section, dict):
        return None
    val = section.get(f"{tier}_provider_order")
    return str(val) if val else None


def get_config_url(provider: str, data: dict[str, object]) -> str | None:
    """Get custom API URL for a provider from config data."""
    urls = data.get("urls")
    if not isinstance(urls, dict):
        return None
    val = urls.get(provider.lower())
    return str(val) if val else None


# =============================================================================
# Interactive first-run setup
# =============================================================================

PROVIDERS = [
    ("1", "gemini"),
    ("2", "anthropic"),
    ("3", "openai"),
    ("4", "openrouter"),
    ("5", "openai-compatible"),
]


API_KEY_ENV_VARS: dict[str, str] = {
    "gemini": "GEMINI_API_KEY",
    "anthropic": "ANTHROPIC_API_KEY",
    "openai": "OPENAI_API_KEY",
    "openrouter": "OPENROUTER_API_KEY",
}

# (review_default, utility_default) — no defaults for openrouter or openai-compatible
PROVIDER_DEFAULTS: dict[str, tuple[str, str]] = {
    "gemini": ("gemini-3-flash-preview", "gemini-2.5-flash-lite"),
    "anthropic": ("claude-sonnet-4-6", "claude-haiku-4-5-20251001"),
    "openai": ("gpt-5.2", "gpt-5-mini"),
}


def _prompt_model(label: str, provider: str, has_custom_url: bool, tier: str = "review") -> str:
    """Prompt for a model name, validating against litellm for known providers."""
    defaults = PROVIDER_DEFAULTS.get(provider)
    default_model = None
    if defaults and not has_custom_url:
        default_model = defaults[0] if tier == "review" else defaults[1]
        _console.print(
            f"  [dim]We recommend [bold]{default_model}[/bold]. Press Enter to use it.[/]"
        )
    while True:
        model = Prompt.ask(f"  {label}", default=default_model or "").strip()
        if not model:
            continue
        if has_custom_url:
            return model
        err = _validate_model_exists(f"{provider}/{model}")
        if err is None:
            return model
        _console.print(f"  [red]{err}[/]")


def _pick_provider() -> tuple[str, str | None]:
    """Show provider menu, return (provider_id, url_or_none)."""
    for key, name in PROVIDERS:
        _console.print(f"    [bold cyan]{key}[/]) {name}")
    _console.print()
    valid = {k for k, _ in PROVIDERS}
    choice = ""
    while choice not in valid:
        choice = Prompt.ask("  Pick a number").strip()
    provider = next(name for k, name in PROVIDERS if k == choice)

    url = None
    if provider == "openai-compatible":
        provider = "openai"
        url = ""
        while not url:
            url = Prompt.ask("  API base URL (e.g. http://localhost:11434/v1)").strip()
    return provider, url


def _run_interactive_setup() -> dict[str, object]:
    """Prompt for review + utility tier provider/model. Save to config file (no secrets)."""
    _console.print()
    _console.print(
        Panel(
            "Reviewate uses two model tiers:\n"
            "  [bold]Review tier[/]  — code analysis, fact-checking (needs strong reasoning)\n"
            "  [bold]Utility tier[/] — formatting, parsing (fast & cheap is fine)\n\n"
            "  Browse all supported models: [link=https://models.litellm.ai/]https://models.litellm.ai/[/link]",
            title="[bold]Welcome to Reviewate![/]",
            expand=False,
        )
    )
    _console.print()

    urls: dict[str, str] = {}
    openrouter_config: dict[str, str] = {}

    # Review tier
    _console.print("  [bold]Step 1 — Review tier provider:[/]")
    review_provider, review_url = _pick_provider()
    if review_url:
        urls[review_provider] = review_url
    review_model = _prompt_model(
        "Review model", review_provider, review_url is not None, tier="review"
    )
    if review_provider == "openrouter":
        order = Prompt.ask(
            "  Provider order (e.g. Anthropic,Google — leave empty to skip)", default=""
        ).strip()
        if order:
            openrouter_config["review_provider_order"] = order

    # Utility tier
    _console.print("\n  [bold]Step 2 — Utility tier provider:[/]")
    utility_provider, utility_url = _pick_provider()
    if utility_url:
        urls[utility_provider] = utility_url
    utility_model = _prompt_model(
        "Utility model", utility_provider, utility_url is not None, tier="utility"
    )
    if utility_provider == "openrouter":
        order = Prompt.ask(
            "  Provider order (e.g. Anthropic,Google — leave empty to skip)", default=""
        ).strip()
        if order:
            openrouter_config["utility_provider_order"] = order

    # Build provider/model strings
    review_full = f"{review_provider}/{review_model}"
    utility_full = f"{utility_provider}/{utility_model}"

    data: dict[str, object] = {
        "models": {"review": review_full, "utility": utility_full},
    }
    if urls:
        data["urls"] = urls
    if openrouter_config:
        data["openrouter"] = openrouter_config
    save_config_file(data)

    # Figure out which API key env vars they need
    env_vars = dict.fromkeys(
        [API_KEY_ENV_VARS.get(review_provider, f"{review_provider.upper()}_API_KEY")]
        + [API_KEY_ENV_VARS.get(utility_provider, f"{utility_provider.upper()}_API_KEY")]
    )

    _console.print("\n  [green]Saved to ~/.reviewate/config.toml[/]")
    _console.print("\n  [yellow]Set your API key(s) before running:[/]")
    for var in env_vars:
        _console.print(f"    [dim]export {var}=your-key[/]")
    _console.print()
    return data
