import uuid

import pytest

from ember._internal.context.runtime import EmberContext
from ember._internal.exceptions import ProviderAPIError
from ember.models.providers.takumi import TakumiProvider
from ember.takumi import config as takumi_config


class DummyResponse:
    def __init__(self, status_code=200, payload=None, text=""):
        self.status_code = status_code
        self._payload = payload or {}
        self.text = text

    def json(self):
        return self._payload


@pytest.fixture(autouse=True)
def _disable_retry():
    """Eliminate retry wait during tests."""
    from tenacity import wait_none

    original = TakumiProvider._execute_request.retry.wait
    TakumiProvider._execute_request.retry.wait = wait_none()
    yield
    TakumiProvider._execute_request.retry.wait = original


def test_takumi_builds_idempotency_header_auto(monkeypatch):
    captured = {}

    def fake_post(self_session, url, **kwargs):
        captured["url"] = url
        captured["headers"] = kwargs.get("headers")
        return DummyResponse(
            200,
            {
                "choices": [{"message": {"content": "hi"}}],
                "model": "gpt-4",
                "usage": {
                    "prompt_tokens": 1,
                    "completion_tokens": 1,
                    "total_tokens": 2,
                    "cost_usd": 0.001,
                },
            },
        )

    monkeypatch.setattr("requests.sessions.Session.post", fake_post)

    provider = TakumiProvider(api_key="test-key", base_url="https://api.takumi.ai")
    provider.complete("Hello", model="gpt-4")

    # Should include Idempotency-Key header (auto-generated)
    assert "Idempotency-Key" in captured["headers"]
    # Validate UUID format
    uuid.UUID(captured["headers"]["Idempotency-Key"])  # will raise if invalid


def test_takumi_respects_provided_idempotency_key(monkeypatch):
    captured = {}

    def fake_post(self_session, url, **kwargs):
        captured["headers"] = kwargs.get("headers")
        return DummyResponse(
            200,
            {"choices": [{"message": {"content": "ok"}}], "model": "gpt-4"},
        )

    monkeypatch.setattr("requests.sessions.Session.post", fake_post)

    provider = TakumiProvider(api_key="test-key", base_url="https://api.takumi.ai")
    provider.complete("Hello", model="gpt-4", idempotency_key="abc-123")
    assert captured["headers"]["Idempotency-Key"] == "abc-123"


def test_takumi_request_payload_contains_model_and_messages(monkeypatch):
    captured = {}

    def fake_post(self_session, url, **kwargs):
        captured["payload"] = kwargs.get("json")
        return DummyResponse(
            200,
            {"choices": [{"message": {"content": "ok"}}], "model": "gpt-4"},
        )

    monkeypatch.setattr("requests.sessions.Session.post", fake_post)

    provider = TakumiProvider(api_key="test-key", base_url="https://api.takumi.ai")
    provider.complete("User prompt", model="gpt-4", system="Sys", temperature=0.2)

    payload = captured["payload"]
    assert payload["model"] == "gpt-4"
    assert payload["messages"][0]["role"] == "system"
    assert payload["messages"][0]["content"] == "Sys"
    assert payload["messages"][1]["role"] == "user"
    assert payload["messages"][1]["content"] == "User prompt"
    assert payload["temperature"] == 0.2


def test_takumi_forwards_response_format(monkeypatch):
    captured = {}

    def fake_post(self_session, url, **kwargs):
        captured["payload"] = kwargs.get("json")
        return DummyResponse(
            200,
            {
                "choices": [{"message": {"content": "structured"}}],
                "model": "gpt-5",
                "usage": {
                    "prompt_tokens": 1,
                    "completion_tokens": 1,
                    "total_tokens": 2,
                },
            },
        )

    monkeypatch.setattr("requests.sessions.Session.post", fake_post)

    provider = TakumiProvider(api_key="test-key", base_url="https://api.takumi.ai")
    response_format = {"type": "json_schema", "schema": {"properties": {}}}
    provider.complete("Prompt", model="gpt-5", response_format=response_format)

    assert captured["payload"]["response_format"] is response_format


def test_takumi_maps_usage_cost_to_actual_cost(monkeypatch):
    def fake_post(self_session, url, **kwargs):
        return DummyResponse(
            200,
            {
                "choices": [{"message": {"content": "ok"}}],
                "model": "gpt-4",
                "usage": {
                    "prompt_tokens": 2,
                    "completion_tokens": 3,
                    "total_tokens": 5,
                    "cost_usd": 0.0123,
                },
            },
        )

    monkeypatch.setattr("requests.sessions.Session.post", fake_post)

    provider = TakumiProvider(api_key="test-key", base_url="https://api.takumi.ai")
    resp = provider.complete("Hello", model="gpt-4")
    assert resp.usage is not None
    assert resp.usage.actual_cost_usd == pytest.approx(0.0123)


def test_takumi_handles_rate_limit(monkeypatch):
    def fake_post(self_session, url, **kwargs):
        return DummyResponse(429, text="rate limited")

    monkeypatch.setattr("requests.sessions.Session.post", fake_post)

    provider = TakumiProvider(api_key="test-key", base_url="https://api.takumi.ai")
    with pytest.raises(ProviderAPIError) as ei:
        provider.complete("Hello", model="gpt-4")
    assert ei.value.context.get("error_type") == "rate_limit"


def test_takumi_provider_reads_base_url_from_config(monkeypatch, tmp_path):
    config_path = tmp_path / "config.yaml"
    config_path.write_text(
        (
            "base_url: http://localhost:9999\n"
            "gateway:\n"
            "  providers:\n"
            "    takumi:\n"
            "      api_key: configured-key\n"
        ),
        encoding="utf-8",
    )
    monkeypatch.setenv("EMBER_CONFIG_PATH", str(config_path))
    takumi_config.reload_takumi_settings(config_path)
    with EmberContext(config_path=config_path) as _ctx:
        provider = TakumiProvider(api_key="configured-key")
        assert provider.base_url == "http://localhost:9999"
