from __future__ import annotations

import json
import os
from dataclasses import dataclass
from pathlib import Path

from simplicity_cli.errors import CliError, ExitCode
from simplicity_cli.models import GlobalOptions

DEFAULT_BASE_URL = "https://api.simplicity.ai"
API_KEY_ENV_VAR = "SIMPLICITY_AI_API_KEY"
XDG_CONFIG_HOME_ENV_VAR = "XDG_CONFIG_HOME"
CONFIG_DIR_NAME = "simplicity-cli"
CONFIG_FILE_NAME = "config.json"


@dataclass(frozen=True)
class RuntimeConfig:
    api_key: str
    base_url: str
    request_timeout_seconds: float
    json_output: bool


def resolve_runtime_config(options: GlobalOptions) -> RuntimeConfig:
    if options.request_timeout_seconds <= 0:
        raise CliError(
            "request timeout must be greater than 0 seconds.",
            exit_code=ExitCode.USAGE_ERROR,
            code="invalid_timeout",
        )

    api_key = (
        options.api_key
        or os.getenv(API_KEY_ENV_VAR, "")
        or load_saved_api_key()
        or ""
    ).strip()
    if not api_key:
        raise CliError(
            f"missing API key. Set --api-key, {API_KEY_ENV_VAR}, or run `simplicity-cli --api-key <key>` once.",
            exit_code=ExitCode.USAGE_ERROR,
            code="missing_api_key",
        )

    return RuntimeConfig(
        api_key=api_key,
        base_url=DEFAULT_BASE_URL,
        request_timeout_seconds=options.request_timeout_seconds,
        json_output=options.json_output,
    )


def load_saved_api_key() -> str | None:
    config_path = get_config_path()
    if not config_path.exists():
        return None

    try:
        payload = json.loads(config_path.read_text(encoding="utf-8"))
    except (OSError, json.JSONDecodeError):
        return None

    if not isinstance(payload, dict):
        return None
    api_key = payload.get("api_key")
    if isinstance(api_key, str):
        normalized = api_key.strip()
        return normalized or None
    return None


def save_api_key(api_key: str) -> Path:
    normalized = api_key.strip()
    if not normalized:
        raise CliError(
            "API key cannot be empty.",
            exit_code=ExitCode.USAGE_ERROR,
            code="invalid_api_key",
        )

    config_path = get_config_path()
    config_path.parent.mkdir(parents=True, exist_ok=True)
    payload = {"api_key": normalized}
    try:
        config_path.write_text(json.dumps(payload, ensure_ascii=True, indent=2) + "\n", encoding="utf-8")
        os.chmod(config_path, 0o600)
    except OSError as exc:
        raise CliError(
            f"failed to save API key to {config_path}.",
            exit_code=ExitCode.USAGE_ERROR,
            code="api_key_save_failed",
            details={"path": str(config_path), "error": str(exc)},
        ) from exc
    return config_path


def get_config_path() -> Path:
    config_home = os.getenv(XDG_CONFIG_HOME_ENV_VAR)
    if config_home:
        base = Path(config_home).expanduser()
    else:
        base = Path.home() / ".config"
    return base / CONFIG_DIR_NAME / CONFIG_FILE_NAME
