"""Unit tests for metric prefix routing logic.

Tests the two-field taxonomy routing system that determines metric prefixes
based on model_category and model_type combinations.
"""

import pytest

from mca_sdk.utils.routing import get_metric_prefix, migrate_legacy_model_type


class TestGetMetricPrefix:
    """Tests for get_metric_prefix() function."""

    # Test internal + traditional ML → model.* namespace (AC#4)
    def test_internal_regression_routes_to_model(self):
        """Internal regression models should use model.* prefix."""
        assert get_metric_prefix("internal", "regression") == "model"

    def test_internal_time_series_routes_to_model(self):
        """Internal time-series models should use model.* prefix."""
        assert get_metric_prefix("internal", "time-series") == "model"

    def test_internal_classification_routes_to_model(self):
        """Internal classification models should use model.* prefix."""
        assert get_metric_prefix("internal", "classification") == "model"

    # Test internal + AI/LLM → genai.* namespace (AC#5)
    def test_internal_generative_routes_to_genai(self):
        """Internal generative models should use genai.* prefix."""
        assert get_metric_prefix("internal", "generative") == "genai"

    def test_internal_agentic_routes_to_agentic(self):
        """Internal agentic AI models should use agentic.* prefix."""
        assert get_metric_prefix("internal", "agentic") == "agentic"

    # Test vendor → vendor.* namespace always (AC#3)
    def test_vendor_regression_routes_to_vendor(self):
        """Vendor regression models should use vendor.* prefix."""
        assert get_metric_prefix("vendor", "regression") == "vendor"

    def test_vendor_time_series_routes_to_vendor(self):
        """Vendor time-series models should use vendor.* prefix."""
        assert get_metric_prefix("vendor", "time-series") == "vendor"

    def test_vendor_classification_routes_to_vendor(self):
        """Vendor classification models should use vendor.* prefix."""
        assert get_metric_prefix("vendor", "classification") == "vendor"

    def test_vendor_generative_routes_to_vendor(self):
        """Vendor generative models should use vendor.* prefix (vendor overrides type)."""
        assert get_metric_prefix("vendor", "generative") == "vendor"

    def test_vendor_agentic_routes_to_vendor(self):
        """Vendor agentic models should use vendor.* prefix (vendor overrides type)."""
        assert get_metric_prefix("vendor", "agentic") == "vendor"

    # Test invalid combinations
    def test_invalid_model_category_raises_error(self):
        """Invalid model_category should raise ValueError."""
        with pytest.raises(ValueError) as exc_info:
            get_metric_prefix("external", "regression")

        assert "Invalid model taxonomy combination" in str(exc_info.value)
        assert "model_category='external'" in str(exc_info.value)
        assert "Valid model_category values" in str(exc_info.value)

    def test_invalid_model_type_raises_error(self):
        """Invalid model_type should raise ValueError."""
        with pytest.raises(ValueError) as exc_info:
            get_metric_prefix("internal", "unknown")

        assert "Invalid model taxonomy combination" in str(exc_info.value)
        assert "model_type='unknown'" in str(exc_info.value)
        assert "Valid model_type values" in str(exc_info.value)

    def test_both_invalid_raises_error(self):
        """Both invalid values should raise ValueError."""
        with pytest.raises(ValueError) as exc_info:
            get_metric_prefix("invalid_category", "invalid_type")

        assert "Invalid model taxonomy combination" in str(exc_info.value)

    # Edge cases
    def test_empty_model_category_raises_error(self):
        """Empty model_category should raise ValueError."""
        with pytest.raises(ValueError):
            get_metric_prefix("", "regression")

    def test_empty_model_type_raises_error(self):
        """Empty model_type should raise ValueError."""
        with pytest.raises(ValueError):
            get_metric_prefix("internal", "")

    def test_case_sensitivity(self):
        """Function should be case-sensitive (uppercase should fail)."""
        with pytest.raises(ValueError):
            get_metric_prefix("Internal", "Regression")


class TestMigrateLegacyModelType:
    """Tests for migrate_legacy_model_type() function."""

    # Test legacy migration mappings
    def test_legacy_internal_migrates_to_internal_regression(self):
        """Legacy model_type='internal' should migrate to (internal, regression)."""
        category, model_type = migrate_legacy_model_type("internal")
        assert category == "internal"
        assert model_type == "regression"

    def test_legacy_generative_migrates_to_internal_generative(self):
        """Legacy model_type='generative' should migrate to (internal, generative)."""
        category, model_type = migrate_legacy_model_type("generative")
        assert category == "internal"
        assert model_type == "generative"

    def test_legacy_vendor_migrates_to_vendor_regression(self):
        """Legacy model_type='vendor' should migrate to (vendor, regression)."""
        category, model_type = migrate_legacy_model_type("vendor")
        assert category == "vendor"
        assert model_type == "regression"

    # Test invalid legacy values
    def test_invalid_legacy_type_raises_error(self):
        """Invalid legacy model_type should raise ValueError."""
        with pytest.raises(ValueError) as exc_info:
            migrate_legacy_model_type("unknown")

        assert "Invalid legacy model_type" in str(exc_info.value)
        assert "'unknown'" in str(exc_info.value)

    def test_new_taxonomy_values_raise_error(self):
        """New taxonomy model_type values should raise ValueError (not legacy)."""
        with pytest.raises(ValueError):
            migrate_legacy_model_type("regression")

        with pytest.raises(ValueError):
            migrate_legacy_model_type("time-series")

        with pytest.raises(ValueError):
            migrate_legacy_model_type("classification")

        with pytest.raises(ValueError):
            migrate_legacy_model_type("agentic")

    def test_empty_string_raises_error(self):
        """Empty string should raise ValueError."""
        with pytest.raises(ValueError):
            migrate_legacy_model_type("")

    def test_case_sensitivity_migration(self):
        """Migration should be case-sensitive (uppercase should fail)."""
        with pytest.raises(ValueError):
            migrate_legacy_model_type("Internal")


class TestRoutingIntegration:
    """Integration tests for routing logic with both functions."""

    def test_legacy_internal_routes_correctly(self):
        """Legacy 'internal' should migrate and route to 'model' prefix."""
        category, model_type = migrate_legacy_model_type("internal")
        prefix = get_metric_prefix(category, model_type)
        assert prefix == "model"

    def test_legacy_generative_routes_correctly(self):
        """Legacy 'generative' should migrate and route to 'genai' prefix."""
        category, model_type = migrate_legacy_model_type("generative")
        prefix = get_metric_prefix(category, model_type)
        assert prefix == "genai"

    def test_legacy_vendor_routes_correctly(self):
        """Legacy 'vendor' should migrate and route to 'vendor' prefix."""
        category, model_type = migrate_legacy_model_type("vendor")
        prefix = get_metric_prefix(category, model_type)
        assert prefix == "vendor"

    def test_all_new_taxonomy_combinations_valid(self):
        """All new taxonomy combinations should produce valid prefixes."""
        combinations = [
            ("internal", "regression", "model"),
            ("internal", "time-series", "model"),
            ("internal", "classification", "model"),
            ("internal", "generative", "genai"),
            ("internal", "agentic", "agentic"),
            ("vendor", "regression", "vendor"),
            ("vendor", "time-series", "vendor"),
            ("vendor", "classification", "vendor"),
            ("vendor", "generative", "vendor"),
            ("vendor", "agentic", "vendor"),
        ]

        for category, model_type, expected_prefix in combinations:
            prefix = get_metric_prefix(category, model_type)
            assert (
                prefix == expected_prefix
            ), f"({category}, {model_type}) should route to {expected_prefix}, got {prefix}"
