"""Adapter registry — builds adapter instances from DPEConfig."""

from __future__ import annotations

import logging
from typing import Any

from dpe.adapters.base import ModelAdapter
from dpe.adapters.claude_code_cli import ClaudeCodeCliAdapter
from dpe.adapters.codex_cli import CodexCliAdapter
from dpe.adapters.local import LocalAdapter
from dpe.adapters.simulation import SimulationAdapter
from dpe.models.config import AdapterConfig, DPEConfig

logger = logging.getLogger(__name__)

# Mapping from adapter_type string to (constructor, is_premium_default)
_BUILTIN_ADAPTERS: dict[str, type[ModelAdapter]] = {
    "claude_code_cli": ClaudeCodeCliAdapter,
    "codex_cli": CodexCliAdapter,
    "local": LocalAdapter,
}


def build_adapters(config: DPEConfig) -> dict[str, ModelAdapter]:
    """Build adapter instances from config.

    If config.adapters is empty, creates default instances for the
    built-in adapter types. Returns a name->adapter mapping.
    """
    adapters: dict[str, ModelAdapter] = {}

    if config.simulation_mode:
        sim = SimulationAdapter()
        adapters["simulation"] = sim
        return adapters

    if config.adapters:
        for name, acfg in config.adapters.items():
            if not acfg.enabled:
                logger.info("Adapter '%s' disabled, skipping", name)
                continue
            adapter = _build_from_config(name, acfg)
            if adapter is not None:
                adapters[name] = adapter
    else:
        # Default: create built-in adapters with default settings
        adapters["claude_code_cli"] = ClaudeCodeCliAdapter()
        adapters["codex_cli"] = CodexCliAdapter()
        adapters["local"] = LocalAdapter()

    return adapters


def _build_from_config(name: str, acfg: AdapterConfig) -> ModelAdapter | None:
    """Instantiate an adapter from an AdapterConfig."""
    cls = _BUILTIN_ADAPTERS.get(acfg.adapter_type)
    if cls is None:
        if acfg.adapter_type in ("openai_api", "anthropic_api"):
            logger.warning(
                "Adapter '%s' (type=%s) is not implemented in V1",
                name, acfg.adapter_type,
            )
            return None
        logger.warning("Unknown adapter type: %s", acfg.adapter_type)
        return None

    kwargs: dict[str, Any] = {"timeout_seconds": acfg.timeout_seconds}
    if acfg.command_template:
        kwargs["command_template"] = acfg.command_template
    if acfg.model_name and hasattr(cls, "model_name"):
        kwargs["model_name"] = acfg.model_name

    return cls(**kwargs)


class AdapterHealthCheckError(RuntimeError):
    """Raised when one or more adapter healthchecks fail."""

    def __init__(self, failures: list[str]) -> None:
        self.failures = failures
        summary = "; ".join(failures)
        super().__init__(f"Adapter healthcheck failed: {summary}")


def run_adapter_healthchecks(
    adapters: dict[str, ModelAdapter],
) -> list[str]:
    """Run healthcheck on every adapter. Return list of failure messages.

    Each adapter's ``healthcheck()`` method is called; adapters that return
    ``False`` or raise are collected as failures.
    """
    failures: list[str] = []
    for name, adapter in sorted(adapters.items()):
        try:
            ok = adapter.healthcheck()
        except Exception as exc:
            failures.append(f"{name}: {exc}")
            continue
        if not ok:
            failures.append(f"{name}: healthcheck returned False")
    return failures


# Premium classification: maps adapter type to is_premium default
_PREMIUM_DEFAULTS: dict[str, bool] = {
    "claude_code_cli": True,
    "codex_cli": True,
    "local": False,
    "simulation": False,
    "openai_api": True,
    "anthropic_api": True,
}


def is_adapter_premium(name: str, config: DPEConfig) -> bool:
    """Determine if an adapter is premium using AdapterConfig.is_premium
    if available, otherwise use built-in defaults."""
    if name in config.adapters:
        return config.adapters[name].is_premium
    return _PREMIUM_DEFAULTS.get(name, False)
