"""Tests for resource convenience transforms (embedders, LLMs, rerankers).

Shared patterns are parametrized; resource-specific behaviors have dedicated tests.
"""

import json

import httpx
import pytest

from goodmem._transforms import apply_convenience_transforms
from tests.conftest import EMBEDDER_RESPONSE, LLM_RESPONSE, RERANKER_RESPONSE


def _apply(ns, kwargs):
    apply_convenience_transforms((ns, "create"), kwargs)
    return kwargs


# ---------------------------------------------------------------------------
# Parametrized: shared convenience patterns across all three resource types
# ---------------------------------------------------------------------------

# (namespace, model_identifier, expected_provider, extra_expected_fields)
_KNOWN_MODELS = [
    ("embedders", "text-embedding-3-small", "OPENAI", {"dimensionality": 1536, "distribution_type": "DENSE"}),
    ("llms", "gpt-4o", "OPENAI", {"max_context_length": 128000}),
    ("rerankers", "rerank-v3.5", "COHERE", {}),
]


@pytest.mark.parametrize("ns, model, expected_provider, extra", _KNOWN_MODELS,
                         ids=["embedders", "llms", "rerankers"])
class TestKnownModelAutoFill:
    def test_auto_fills_provider_type(self, ns, model, expected_provider, extra):
        result = _apply(ns, {"model_identifier": model, "display_name": "Test", "api_key": "sk-test"})
        assert result["provider_type"] == expected_provider

    def test_auto_fills_endpoint_url(self, ns, model, expected_provider, extra):
        result = _apply(ns, {"model_identifier": model, "display_name": "Test", "api_key": "sk-test"})
        assert "endpoint_url" in result

    def test_auto_fills_resource_specific_fields(self, ns, model, expected_provider, extra):
        if not extra:
            pytest.skip("no resource-specific auto-fill fields")
        result = _apply(ns, {"model_identifier": model, "display_name": "Test", "api_key": "sk-test"})
        for field, expected in extra.items():
            assert result[field] == expected, f"{field}: {result.get(field)} != {expected}"


# (namespace, model_identifier, explicit_overrides)
_EXPLICIT_OVERRIDE_CASES = [
    ("embedders", "text-embedding-3-small", {"provider_type": "CUSTOM", "dimensionality": 768, "endpoint_url": "https://custom.example.com"}),
    ("llms", "gpt-4o", {"provider_type": "VLLM", "endpoint_url": "http://localhost:8000"}),
    ("rerankers", "rerank-v3.5", {"provider_type": "CUSTOM", "endpoint_url": "https://custom.example.com"}),
]


@pytest.mark.parametrize("ns, model, overrides", _EXPLICIT_OVERRIDE_CASES,
                         ids=["embedders", "llms", "rerankers"])
def test_explicit_values_win_over_registry(ns, model, overrides):
    kwargs = {"model_identifier": model, "display_name": "Test", **overrides}
    result = _apply(ns, kwargs)
    for field, expected in overrides.items():
        assert result[field] == expected


# (namespace, api_key_value)
_API_KEY_CASES = [
    ("embedders", "sk-secret"),
    ("llms", "sk-secret"),
    ("rerankers", "key-123"),
]


@pytest.mark.parametrize("ns, api_key", _API_KEY_CASES,
                         ids=["embedders", "llms", "rerankers"])
def test_api_key_converted_to_credentials(ns, api_key):
    result = _apply(ns, {"display_name": "Test", "api_key": api_key})
    assert "api_key" not in result
    assert result["credentials"]["kind"] == "CREDENTIAL_KIND_API_KEY"
    assert result["credentials"]["api_key"]["inline_secret"] == api_key


@pytest.mark.parametrize("ns", ["embedders", "llms", "rerankers"])
def test_api_key_and_credentials_raises(ns):
    kwargs = {
        "display_name": "Test",
        "api_key": "sk-secret",
        "credentials": {"kind": "CUSTOM", "data": "custom"},
    }
    with pytest.raises(ValueError, match="Cannot specify both"):
        _apply(ns, kwargs)


# (namespace, model, create_kwargs, response, id_field)
_ROUND_TRIP_CASES = [
    ("embedders", "text-embedding-3-small", {"display_name": "My Embedder"}, EMBEDDER_RESPONSE, "embedder_id", "emb-123"),
    ("rerankers", "rerank-v3.5", {"display_name": "My Reranker"}, RERANKER_RESPONSE, "reranker_id", "rr-123"),
]


@pytest.mark.parametrize("ns, model, create_kwargs, response, id_field, expected_id",
                         _ROUND_TRIP_CASES, ids=["embedders", "rerankers"])
def test_create_round_trip(mock_client_factory, ns, model, create_kwargs, response, id_field, expected_id):
    """Full round-trip: create resource with known model, check request body."""
    captured = {}

    def handler(request: httpx.Request) -> httpx.Response:
        captured["body"] = json.loads(request.content)
        return httpx.Response(200, json=response)

    client = mock_client_factory(handler)
    result = getattr(client, ns).create(
        model_identifier=model,
        api_key="sk-test",
        **create_kwargs,
    )

    body = captured["body"]
    assert "providerType" in body
    assert "endpointUrl" in body
    assert getattr(result, id_field) == expected_id


# ---------------------------------------------------------------------------
# Embedder-specific tests
# ---------------------------------------------------------------------------

def test_embedder_unknown_model_no_auto_fill():
    result = _apply("embedders", {"model_identifier": "unknown-model", "display_name": "Test"})
    assert "provider_type" not in result
    assert "dimensionality" not in result
    # distribution_type still gets default
    assert result["distribution_type"] == "DENSE"


def test_embedder_auth_header_sent(mock_client_factory):
    """Verify the auth header is included in the request."""
    captured = {}

    def handler(request: httpx.Request) -> httpx.Response:
        captured["headers"] = dict(request.headers)
        return httpx.Response(200, json=EMBEDDER_RESPONSE)

    client = mock_client_factory(handler, api_key="gm_test_key")
    client.embedders.create(
        display_name="Test",
        model_identifier="text-embedding-3-small",
        api_key="sk-test",
    )

    assert captured["headers"]["x-api-key"] == "gm_test_key"


# ---------------------------------------------------------------------------
# LLM-specific tests
# ---------------------------------------------------------------------------

def test_llm_vllm_provider_no_auto_endpoint():
    """VLLM has None in endpoint map — user must provide endpoint_url."""
    result = _apply("llms", {
        "model_identifier": "unknown",
        "display_name": "Test",
        "provider_type": "VLLM",
    })
    assert "endpoint_url" not in result


def test_llm_create_returns_full_response(mock_client_factory):
    """LLM create should return full CreateLLMResponse with .llm and .statuses."""
    def handler(request: httpx.Request) -> httpx.Response:
        return httpx.Response(200, json={"llm": LLM_RESPONSE})

    client = mock_client_factory(handler)
    result = client.llms.create(
        display_name="GPT-4o",
        model_identifier="gpt-4o",
        api_key="sk-test",
    )

    assert result.llm.llm_id == "llm-123"
    assert result.llm.display_name == "Test LLM"


def test_llm_create_sends_correct_body(mock_client_factory):
    """Verify the request body contains auto-inferred fields."""
    captured = {}

    def handler(request: httpx.Request) -> httpx.Response:
        captured["body"] = json.loads(request.content)
        return httpx.Response(200, json={"llm": LLM_RESPONSE})

    client = mock_client_factory(handler)
    client.llms.create(
        display_name="GPT-4o",
        model_identifier="gpt-4o",
        api_key="sk-test",
    )

    body = captured["body"]
    assert body["providerType"] == "OPENAI"
    assert "endpointUrl" in body
    assert "maxContextLength" in body


# ---------------------------------------------------------------------------
# Reranker-specific tests
# ---------------------------------------------------------------------------

def test_reranker_jina_model_auto_fills():
    result = _apply("rerankers", {
        "model_identifier": "jina-reranker-v2-base-multilingual",
        "display_name": "Test",
        "api_key": "sk-test",
    })
    assert result["provider_type"] == "JINA"
    assert result["endpoint_url"] == "https://api.jina.ai"
