from __future__ import annotations

from dataclasses import dataclass
from typing import Any

import httpx
import pytest

from src.services import openclaw as openclaw_module
from src.services.openclaw import OpenClawService


class _FakeRegistry:
    def get_model(self, provider: str, use_case: str) -> str:
        return "qwen2.5:7b-instruct"

    def get_provider_options(self, provider: str) -> dict[str, Any]:
        return {"num_predict": 32, "temperature": 0.1, "top_p": 0.9}


@dataclass
class _FakeEndpoint:
    provider_name: str
    url: str


class _FakeRoute:
    def __init__(self, endpoints: list[_FakeEndpoint]) -> None:
        self._endpoints = endpoints

    def all_endpoints_in_order(self) -> list[_FakeEndpoint]:
        return self._endpoints


class _FakeManager:
    def __init__(self, endpoints: list[_FakeEndpoint]) -> None:
        self._endpoints = endpoints

    async def select_provider(self) -> _FakeRoute:
        return _FakeRoute(self._endpoints)


class _FakeResponse:
    status_code = 200

    def raise_for_status(self) -> None:
        return None

    def json(self) -> dict[str, Any]:
        return {"response": '{"action_title":"ok"}'}


class _FakeClient:
    def __init__(self, fail_urls: set[str]) -> None:
        self.fail_urls = fail_urls
        self.posted_urls: list[str] = []

    async def post(self, url: str, **kwargs: Any) -> _FakeResponse:
        self.posted_urls.append(url)
        if url in self.fail_urls:
            raise httpx.ConnectError("offline")
        return _FakeResponse()


@pytest.mark.asyncio
async def test_legacy_ollama_uses_failover_order_before_gemini(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    monkeypatch.setattr(openclaw_module, "get_model_registry", lambda: _FakeRegistry())
    monkeypatch.setattr(openclaw_module.settings, "OPENCLAW_TIMEOUT", 30)
    monkeypatch.setattr(openclaw_module.settings, "OLLAMA_DIAGNOSE_TIMEOUT_SECONDS", 200)
    monkeypatch.setattr(
        openclaw_module,
        "get_ollama_failover_manager",
        lambda: _FakeManager(
            [
                _FakeEndpoint("ollama_gcp_a", "http://gcp-a:11435"),
                _FakeEndpoint("ollama_gcp_b", "http://gcp-b:11436"),
                _FakeEndpoint("ollama_local", "http://local-111:11434"),
                _FakeEndpoint("gemini", ""),
            ],
        ),
    )

    client = _FakeClient(fail_urls={"http://gcp-a:11435/api/generate"})
    service = object.__new__(OpenClawService)

    async def _get_client() -> _FakeClient:
        return client

    monkeypatch.setattr(service, "_get_client", _get_client)

    result, ok = await service._call_ollama("diagnose")

    assert ok is True
    assert result == '{"action_title":"ok"}'
    assert client.posted_urls == [
        "http://gcp-a:11435/api/generate",
        "http://gcp-b:11436/api/generate",
    ]


@pytest.mark.asyncio
async def test_legacy_ollama_falls_back_to_configured_three_layer_urls(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    monkeypatch.setattr(openclaw_module, "get_model_registry", lambda: _FakeRegistry())
    monkeypatch.setattr(openclaw_module.settings, "OPENCLAW_TIMEOUT", 30)
    monkeypatch.setattr(openclaw_module.settings, "OLLAMA_DIAGNOSE_TIMEOUT_SECONDS", 200)
    monkeypatch.setattr(openclaw_module.settings, "OLLAMA_URL", "http://gcp-a:11435")
    monkeypatch.setattr(openclaw_module.settings, "OLLAMA_SECONDARY_URL", "http://gcp-b:11436")
    monkeypatch.setattr(openclaw_module.settings, "OLLAMA_FALLBACK_URL", "http://local-111:11434")
    monkeypatch.setattr(
        openclaw_module,
        "get_ollama_failover_manager",
        lambda: _FakeManager([_FakeEndpoint("gemini", "")]),
    )

    client = _FakeClient(
        fail_urls={
            "http://gcp-a:11435/api/generate",
            "http://gcp-b:11436/api/generate",
        },
    )
    service = object.__new__(OpenClawService)

    async def _get_client() -> _FakeClient:
        return client

    monkeypatch.setattr(service, "_get_client", _get_client)

    result, ok = await service._call_ollama("diagnose")

    assert ok is True
    assert result == '{"action_title":"ok"}'
    assert client.posted_urls == [
        "http://gcp-a:11435/api/generate",
        "http://gcp-b:11436/api/generate",
        "http://local-111:11434/api/generate",
    ]
