"""Test configuration parsing and validation."""

import json
import os

from databuilder_logic_sdk.core.config import (
    Config,
    EmbeddingServiceConfig,
    RerankServiceConfig,
    ServiceConfig,
    get_config,
    get_embedding_config,
    get_global_config,
    get_ontology_config,
    get_rerank_config,
    get_workspace_id,
)

from .utils import gen_test_config, reset_global_config


def test_config_parsing() -> None:
    """Test that configuration is parsed correctly from environment variable."""
    test_config = gen_test_config()
    os.environ["ServiceConfig"] = json.dumps(test_config)

    parsed_config = Config.model_validate(
        {
            "service_config": test_config,
        }
    )

    assert isinstance(parsed_config, Config)
    assert isinstance(parsed_config.service_config, ServiceConfig)
    assert isinstance(parsed_config.service_config.embedding, EmbeddingServiceConfig)
    assert isinstance(parsed_config.service_config.rerank, RerankServiceConfig)
    assert parsed_config.service_config.embedding.endpoint == "http://embedding.service"
    assert parsed_config.service_config.rerank.modelServingName == "rerank_model_v1"


def test_config_validation_error() -> None:
    """Test that invalid configuration raises validation error."""
    invalid_config = {
        "embedding": {
            "endpoint": "http://embedding.service",
            # Missing modelServingName and baseModelName
        },
        "rerank": {
            "endpoint": "http://rerank.service",
            "modelServingName": "rerank_model_v1",
            "baseModelName": "base_rerank_model",
        },
    }
    os.environ["ServiceConfig"] = json.dumps(invalid_config)

    try:
        Config.model_validate(
            {
                "service_config": invalid_config,
            }
        )
    except Exception as e:
        assert "modelServingName" in str(e)
        assert "baseModelName" in str(e)


def test_empty_config() -> None:
    """Test that empty configuration raises validation error."""
    os.environ["ServiceConfig"] = "{}"

    try:
        Config.model_validate(
            {
                "service_config": {},
            }
        )
    except Exception as e:
        assert "embedding" in str(e)
        assert "rerank" in str(e)


def test_get_config() -> None:
    """Test the get_config function."""
    test_config = gen_test_config()
    os.environ["ServiceConfig"] = json.dumps(test_config)

    config = get_global_config()
    config1 = get_global_config()

    assert id(config) == id(config1)

    assert isinstance(config, Config)
    assert isinstance(config.service_config, ServiceConfig)
    assert isinstance(config.service_config.embedding, EmbeddingServiceConfig)
    assert isinstance(config.service_config.rerank, RerankServiceConfig)
    assert config.service_config.embedding.endpoint == "http://embedding.service"
    assert config.service_config.rerank.modelServingName == "rerank_model_v1"

    test_config["embedding"]["endpoint"] = "http://new.embedding.service"
    new_config = get_config({"service_config": test_config})

    assert isinstance(new_config, Config)
    assert id(new_config) != id(config)  # Ensure a new instance is created
    assert new_config.service_config.embedding.endpoint == "http://new.embedding.service"
    assert new_config.service_config.embedding.endpoint != config.service_config.embedding.endpoint


def test_ontology_config() -> None:
    """Test that Ontology Service configuration is parsed correctly from environment variable."""
    test_config = gen_test_config()
    os.environ["ServiceConfig"] = json.dumps(test_config)

    parsed_config = Config.model_validate(
        {
            "service_config": test_config,
        }
    )

    assert isinstance(parsed_config, Config)
    assert isinstance(parsed_config.service_config, ServiceConfig)
    assert hasattr(parsed_config.service_config, "ontology")
    assert parsed_config.service_config.ontology.endpoint == "http://ontology.service"
    assert parsed_config.service_config.ontology.token == "ontology_service_token"


def test_get_xxx_config() -> None:
    """Test the get_xxx_config function."""
    test_config = gen_test_config()
    os.environ["ServiceConfig"] = json.dumps(test_config)

    config = get_global_config()
    embedding_config = get_embedding_config()
    rerank_config = get_rerank_config()
    ontology_config = get_ontology_config()

    assert isinstance(embedding_config, type(config.service_config.embedding))
    assert embedding_config.endpoint == "http://embedding.service"
    assert embedding_config.modelServingName == "embedding_model_v1"
    assert isinstance(rerank_config, type(config.service_config.rerank))
    assert rerank_config.endpoint == "http://rerank.service"
    assert rerank_config.modelServingName == "rerank_model_v1"
    assert isinstance(ontology_config, type(config.service_config.ontology))
    assert ontology_config.endpoint == "http://ontology.service"
    assert ontology_config.token == "ontology_service_token"


def test_get_api_key_from_service_config() -> None:
    """Test reading apiKey from ServiceConfig."""
    reset_global_config()
    test_config = gen_test_config(
        embedding={
            "endpoint": "http://embedding.service",
            "modelServingName": "embedding_model_v1",
            "baseModelName": "base_embedding_model",
            "apiKey": "embedding-api-key",
        },
        rerank={
            "endpoint": "http://rerank.service",
            "modelServingName": "rerank_model_v1",
            "baseModelName": "base_rerank_model",
            "apiKey": "rerank-api-key",
        },
    )
    os.environ["ServiceConfig"] = json.dumps(test_config)

    embedding_config = get_embedding_config()
    rerank_config = get_rerank_config()

    assert embedding_config is not None
    assert rerank_config is not None
    assert embedding_config.apiKey == "embedding-api-key"
    assert rerank_config.apiKey == "rerank-api-key"


def test_get_ontology_bce_headers_from_service_config() -> None:
    """Test reading ontology BCE header fields from ServiceConfig."""
    reset_global_config()
    test_config = gen_test_config(
        ontology={
            "endpoint": "http://ontology.service",
            "token": "ontology_service_token",
            "bceAccessKey": "access-key",
            "bceSecurityKey": "security-key",
            "bceSecurityToken": "security-token",
        }
    )
    os.environ["ServiceConfig"] = json.dumps(test_config)

    ontology_config = get_ontology_config()

    assert ontology_config is not None
    assert ontology_config.bceAccessKey == "access-key"
    assert ontology_config.bceSecurityKey == "security-key"
    assert ontology_config.bceSecurityToken == "security-token"


def test_get_ontology_bce_headers_from_legacy_service_config_keys() -> None:
    """Test legacy x-bce-* keys are still parsed for compatibility."""
    reset_global_config()
    test_config = gen_test_config(
        ontology={
            "endpoint": "http://ontology.service",
            "token": "ontology_service_token",
            "x-bce-access-key": "access-key",
            "x-bce-security-key": "security-key",
            "x-bce-security-token": "security-token",
        }
    )
    os.environ["ServiceConfig"] = json.dumps(test_config)

    ontology_config = get_ontology_config()

    assert ontology_config is not None
    assert ontology_config.bceAccessKey == "access-key"
    assert ontology_config.bceSecurityKey == "security-key"
    assert ontology_config.bceSecurityToken == "security-token"


def test_get_workspace_id() -> None:
    """Test getting workspace ID from global config."""
    test_config = gen_test_config()
    os.environ["ServiceConfig"] = json.dumps(test_config)

    config = get_global_config()
    assert config.service_config.workspaceId == "workspace_123"
    workspace_id = get_workspace_id()
    assert workspace_id == "workspace_123"


def test_get_xxx_none_config() -> None:
    """Test the get_xxx_config function when service configs are None."""
    os.environ["ServiceConfig"] = json.dumps({})
    reset_global_config()
    embedding_config = get_embedding_config()
    rerank_config = get_rerank_config()
    ontology_config = get_ontology_config()
    workspace_id = get_workspace_id()

    assert embedding_config is None
    assert rerank_config is None
    assert ontology_config is None
    assert workspace_id is None


if __name__ == "__main__":
    test_config_parsing()
    test_config_validation_error()
    test_empty_config()
