"""
Unit tests for API version configuration.

Tests cover:
- Valid version selection (3.11, 3.12, 3.13)
- Invalid version validation
- Default version behavior
- Environment variable loading
- Artifact path resolution
- Version mismatch detection

Copyright (C) 2025 Luciano Guerche

This file is part of rabbitmq-mcp-server.

rabbitmq-mcp-server is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

rabbitmq-mcp-server is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with rabbitmq-mcp-server. If not, see <https://www.gnu.org/licenses/>.
"""

import os
from pathlib import Path
from unittest.mock import patch

import pytest
from pydantic import ValidationError

from config.settings import Settings


class TestAPIVersionValidation:
    """Test API version field validation."""

    def test_valid_version_3_11(self) -> None:
        """Test version 3.11 is accepted."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.11"}):
            settings = Settings()
            assert settings.api_version == "3.11"

    def test_valid_version_3_12(self) -> None:
        """Test version 3.12 is accepted."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.12"}):
            settings = Settings()
            assert settings.api_version == "3.12"

    def test_valid_version_3_13(self) -> None:
        """Test version 3.13 is accepted."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.13"}):
            settings = Settings()
            assert settings.api_version == "3.13"

    def test_invalid_version_raises_error(self) -> None:
        """Test invalid version raises ValueError with correct message."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.10"}):
            with pytest.raises(ValidationError) as exc_info:
                Settings()

            error_message = str(exc_info.value)
            assert "API version '3.10' not supported" in error_message
            assert "Supported: 3.11, 3.12, 3.13" in error_message
            assert "Check available OpenAPI files in data/ directory" in error_message

    def test_default_version_is_3_13(self) -> None:
        """Test default version is 3.13 when env var not set."""
        with patch.dict(os.environ, {}, clear=True):
            # Clear any existing RABBITMQ_API_VERSION
            os.environ.pop("RABBITMQ_API_VERSION", None)
            settings = Settings()
            assert settings.api_version == "3.13"

    def test_environment_variable_override(self) -> None:
        """Test environment variable overrides default."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.11"}):
            settings = Settings()
            assert settings.api_version == "3.11"


class TestVersionPathResolution:
    """Test version-specific path resolution methods."""

    def test_get_api_version(self) -> None:
        """Test get_api_version returns validated version."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.12"}):
            settings = Settings()
            assert settings.get_api_version() == "3.12"

    def test_get_openapi_path_3_11(self) -> None:
        """Test OpenAPI path resolution for version 3.11."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.11"}):
            settings = Settings()
            path = settings.get_openapi_path()
            assert path == Path("data/openapi-3.11.yaml")

    def test_get_openapi_path_3_12(self) -> None:
        """Test OpenAPI path resolution for version 3.12."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.12"}):
            settings = Settings()
            path = settings.get_openapi_path()
            assert path == Path("data/openapi-3.12.yaml")

    def test_get_openapi_path_3_13(self) -> None:
        """Test OpenAPI path resolution for version 3.13."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.13"}):
            settings = Settings()
            path = settings.get_openapi_path()
            assert path == Path("data/openapi-3.13.yaml")

    def test_get_operations_path_3_11(self) -> None:
        """Test operations registry path resolution for version 3.11."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.11"}):
            settings = Settings()
            path = settings.get_operations_path()
            assert path == Path("data/operations-3.11.json")

    def test_get_operations_path_3_12(self) -> None:
        """Test operations registry path resolution for version 3.12."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.12"}):
            settings = Settings()
            path = settings.get_operations_path()
            assert path == Path("data/operations-3.12.json")

    def test_get_operations_path_3_13(self) -> None:
        """Test operations registry path resolution for version 3.13."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.13"}):
            settings = Settings()
            path = settings.get_operations_path()
            assert path == Path("data/operations-3.13.json")

    def test_get_embeddings_path_3_11(self) -> None:
        """Test embeddings path resolution for version 3.11."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.11"}):
            settings = Settings()
            path = settings.get_embeddings_path()
            assert path == Path("data/embeddings-3.11.json")

    def test_get_embeddings_path_3_12(self) -> None:
        """Test embeddings path resolution for version 3.12."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.12"}):
            settings = Settings()
            path = settings.get_embeddings_path()
            assert path == Path("data/embeddings-3.12.json")

    def test_get_embeddings_path_3_13(self) -> None:
        """Test embeddings path resolution for version 3.13."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.13"}):
            settings = Settings()
            path = settings.get_embeddings_path()
            assert path == Path("data/embeddings-3.13.json")

    def test_get_schemas_module_name_3_11(self) -> None:
        """Test schema module name for version 3.11."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.11"}):
            settings = Settings()
            module_name = settings.get_schemas_module_name()
            assert module_name == "schemas_3_11"

    def test_get_schemas_module_name_3_12(self) -> None:
        """Test schema module name for version 3.12."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.12"}):
            settings = Settings()
            module_name = settings.get_schemas_module_name()
            assert module_name == "schemas_3_12"

    def test_get_schemas_module_name_3_13(self) -> None:
        """Test schema module name for version 3.13."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.13"}):
            settings = Settings()
            module_name = settings.get_schemas_module_name()
            assert module_name == "schemas_3_13"

    def test_operations_registry_path_property(self) -> None:
        """Test operations_registry_path property returns version-specific path."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.12"}):
            settings = Settings()
            assert settings.operations_registry_path == "data/operations-3.12.json"

    def test_embeddings_path_property(self) -> None:
        """Test embeddings_path property returns version-specific path."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.12"}):
            settings = Settings()
            assert settings.embeddings_path == "data/embeddings-3.12.json"


class TestVersionMetadata:
    """Test version metadata formatting and display."""

    def test_version_format_3_11(self) -> None:
        """Test version format for 3.11."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.11"}):
            settings = Settings()
            expected_display = "3.11.x"
            assert f"{settings.api_version}.x" == expected_display

    def test_version_format_3_12(self) -> None:
        """Test version format for 3.12."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.12"}):
            settings = Settings()
            expected_display = "3.12.x"
            assert f"{settings.api_version}.x" == expected_display

    def test_version_format_3_13(self) -> None:
        """Test version format for 3.13."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.13"}):
            settings = Settings()
            expected_display = "3.13.x"
            assert f"{settings.api_version}.x" == expected_display


class TestOpenAPIFileValidation:
    """Test OpenAPI file existence validation."""

    def test_validate_openapi_exists_missing_file(self) -> None:
        """Test validation fails when OpenAPI file is missing."""
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.99"}):
            # Use a version that doesn't exist
            with pytest.raises(ValidationError):
                # Should fail during validation
                Settings()

    def test_validate_openapi_exists_file_present(self, tmp_path: Path) -> None:
        """Test validation passes when OpenAPI file exists."""
        # This tests that real files work - we already have 3.11, 3.12, 3.13 files created
        with patch.dict(os.environ, {"RABBITMQ_API_VERSION": "3.13"}):
            settings = Settings()
            # validate_openapi_exists should not raise for existing version
            # The actual file check is done at server startup, not during Settings init
            assert settings.get_openapi_path() == Path("data/openapi-3.13.yaml")
