"""Tests for T-0101: DPE adapter healthchecks.

Validates:
1. Healthcheck failure produces actionable error messages
2. --skip-healthcheck bypasses checks
3. Simulation mode skips healthchecks automatically
"""

from __future__ import annotations

from dpe.adapters.base import ModelAdapter
from dpe.adapters.registry import (
    AdapterHealthCheckError,
    build_adapters,
    run_adapter_healthchecks,
)
from dpe.adapters.simulation import SimulationAdapter
from dpe.models.adapter import ModelRequest, ModelResult
from dpe.models.config import DPEConfig

# ------------------------------------------------------------------ #
# Stub adapters for testing                                            #
# ------------------------------------------------------------------ #


class _HealthyAdapter(ModelAdapter):
    """Adapter whose healthcheck always passes."""

    def generate(self, request: ModelRequest) -> ModelResult:
        return ModelResult(text="ok", adapter_name="healthy")

    def healthcheck(self) -> bool:
        return True

    def estimate_usage(self, request: ModelRequest) -> dict:
        return {}

    def get_usage_snapshot(self) -> dict:
        return {}


class _UnhealthyAdapter(ModelAdapter):
    """Adapter whose healthcheck always fails."""

    def generate(self, request: ModelRequest) -> ModelResult:
        return ModelResult(text="ok", adapter_name="unhealthy")

    def healthcheck(self) -> bool:
        return False

    def estimate_usage(self, request: ModelRequest) -> dict:
        return {}

    def get_usage_snapshot(self) -> dict:
        return {}


class _CrashingAdapter(ModelAdapter):
    """Adapter whose healthcheck raises an exception."""

    def generate(self, request: ModelRequest) -> ModelResult:
        return ModelResult(text="ok", adapter_name="crashing")

    def healthcheck(self) -> bool:
        raise ConnectionError("cannot reach backend")

    def estimate_usage(self, request: ModelRequest) -> dict:
        return {}

    def get_usage_snapshot(self) -> dict:
        return {}


# ------------------------------------------------------------------ #
# run_adapter_healthchecks tests                                       #
# ------------------------------------------------------------------ #


class TestRunAdapterHealthchecks:
    """run_adapter_healthchecks returns failure messages for unhealthy adapters."""

    def test_all_healthy_returns_empty(self):
        adapters = {"a": _HealthyAdapter(), "b": _HealthyAdapter()}
        assert run_adapter_healthchecks(adapters) == []

    def test_unhealthy_returns_failure_message(self):
        adapters = {"good": _HealthyAdapter(), "bad": _UnhealthyAdapter()}
        failures = run_adapter_healthchecks(adapters)
        assert len(failures) == 1
        assert "bad" in failures[0]
        assert "healthcheck returned False" in failures[0]

    def test_crashing_returns_exception_message(self):
        adapters = {"boom": _CrashingAdapter()}
        failures = run_adapter_healthchecks(adapters)
        assert len(failures) == 1
        assert "boom" in failures[0]
        assert "cannot reach backend" in failures[0]

    def test_multiple_failures(self):
        adapters = {
            "ok": _HealthyAdapter(),
            "bad1": _UnhealthyAdapter(),
            "bad2": _CrashingAdapter(),
        }
        failures = run_adapter_healthchecks(adapters)
        assert len(failures) == 2

    def test_simulation_adapter_always_healthy(self):
        adapters = {"simulation": SimulationAdapter()}
        assert run_adapter_healthchecks(adapters) == []


class TestAdapterHealthCheckError:
    """AdapterHealthCheckError captures failure details."""

    def test_message_contains_failures(self):
        err = AdapterHealthCheckError(["a: down", "b: timeout"])
        assert "a: down" in str(err)
        assert "b: timeout" in str(err)
        assert err.failures == ["a: down", "b: timeout"]


# ------------------------------------------------------------------ #
# Simulation mode skips healthchecks                                   #
# ------------------------------------------------------------------ #


class TestSimulationModeSkipsHealthcheck:
    """In simulation mode, only SimulationAdapter is created (always healthy)."""

    def test_simulation_mode_builds_only_simulation(self):
        cfg = DPEConfig(simulation_mode=True)
        adapters = build_adapters(cfg)
        assert "simulation" in adapters
        assert len(adapters) == 1
        # SimulationAdapter.healthcheck() always returns True
        assert run_adapter_healthchecks(adapters) == []
