"""Tests for error_messages module."""

import pytest

from openzim_mcp.error_messages import (
    ERROR_CONFIGS,
    GENERIC_ERROR_TEMPLATE,
    NOT_FOUND_ERROR_CONFIG,
    PERMISSION_ERROR_CONFIG,
    ErrorConfig,
    format_error_message,
    format_generic_error,
    get_error_config,
)
from openzim_mcp.exceptions import (
    OpenZimMcpArchiveError,
    OpenZimMcpFileNotFoundError,
    OpenZimMcpRateLimitError,
    OpenZimMcpSecurityError,
    OpenZimMcpValidationError,
)


class TestErrorConfig:
    """Test ErrorConfig dataclass."""

    def test_error_config_creation(self):
        """Test ErrorConfig creation."""
        config = ErrorConfig(
            title="Test Error",
            issue="Something went wrong",
            steps=["Step 1", "Step 2"],
        )

        assert config.title == "Test Error"
        assert config.issue == "Something went wrong"
        assert len(config.steps) == 2

    def test_error_config_frozen(self):
        """Test that ErrorConfig is frozen (immutable)."""
        config = ErrorConfig(
            title="Test",
            issue="Issue",
            steps=["Step"],
        )

        with pytest.raises(AttributeError):
            config.title = "New Title"  # type: ignore


class TestErrorConfigs:
    """Test ERROR_CONFIGS dictionary."""

    def test_file_not_found_config_exists(self):
        """Test FileNotFoundError config exists."""
        assert OpenZimMcpFileNotFoundError in ERROR_CONFIGS
        config = ERROR_CONFIGS[OpenZimMcpFileNotFoundError]
        assert "File Not Found" in config.title
        assert len(config.steps) > 0

    def test_archive_error_config_exists(self):
        """Test ArchiveError config exists."""
        assert OpenZimMcpArchiveError in ERROR_CONFIGS
        config = ERROR_CONFIGS[OpenZimMcpArchiveError]
        assert "Archive" in config.title
        assert len(config.steps) > 0

    def test_security_error_config_exists(self):
        """Test SecurityError config exists."""
        assert OpenZimMcpSecurityError in ERROR_CONFIGS
        config = ERROR_CONFIGS[OpenZimMcpSecurityError]
        assert "Security" in config.title
        assert len(config.steps) > 0

    def test_validation_error_config_exists(self):
        """Test ValidationError config exists."""
        assert OpenZimMcpValidationError in ERROR_CONFIGS
        config = ERROR_CONFIGS[OpenZimMcpValidationError]
        assert "Validation" in config.title
        assert len(config.steps) > 0

    def test_rate_limit_error_config_exists(self):
        """Test RateLimitError config exists."""
        assert OpenZimMcpRateLimitError in ERROR_CONFIGS
        config = ERROR_CONFIGS[OpenZimMcpRateLimitError]
        assert "Rate Limit" in config.title
        assert len(config.steps) > 0


class TestSpecialErrorConfigs:
    """Test special error configurations."""

    def test_permission_error_config(self):
        """Test PERMISSION_ERROR_CONFIG."""
        assert PERMISSION_ERROR_CONFIG.title == "Permission Error"
        assert "permission" in PERMISSION_ERROR_CONFIG.issue.lower()
        assert len(PERMISSION_ERROR_CONFIG.steps) > 0

    def test_not_found_error_config(self):
        """Test NOT_FOUND_ERROR_CONFIG."""
        assert NOT_FOUND_ERROR_CONFIG.title == "Resource Not Found"
        assert "not" in NOT_FOUND_ERROR_CONFIG.issue.lower()
        assert len(NOT_FOUND_ERROR_CONFIG.steps) > 0


class TestGenericErrorTemplate:
    """Test generic error template."""

    def test_generic_error_template_has_placeholders(self):
        """Test that generic error template has expected placeholders."""
        assert "{operation}" in GENERIC_ERROR_TEMPLATE
        assert "{error_type}" in GENERIC_ERROR_TEMPLATE
        assert "{context}" in GENERIC_ERROR_TEMPLATE
        assert "{details}" in GENERIC_ERROR_TEMPLATE

    def test_generic_error_template_structure(self):
        """Test generic error template structure."""
        assert "**Operation Failed**" in GENERIC_ERROR_TEMPLATE
        assert "**Troubleshooting Steps**" in GENERIC_ERROR_TEMPLATE
        assert "**Technical Details**" in GENERIC_ERROR_TEMPLATE


class TestFormatErrorMessage:
    """Test format_error_message function."""

    def test_format_error_message_basic(self):
        """Test basic error message formatting."""
        config = ErrorConfig(
            title="Test Error",
            issue="Test issue description",
            steps=["First step", "Second step"],
        )

        result = format_error_message(
            config=config,
            operation="test operation",
            context="test context",
            details="test details",
        )

        assert "**Test Error**" in result
        assert "test operation" in result
        assert "Test issue description" in result
        assert "test context" in result
        assert "First step" in result
        assert "Second step" in result
        assert "test details" in result

    def test_format_error_message_numbered_steps(self):
        """Test that steps are numbered."""
        config = ErrorConfig(
            title="Error",
            issue="Issue",
            steps=["Step A", "Step B", "Step C"],
        )

        result = format_error_message(
            config=config,
            operation="op",
            context="ctx",
            details="det",
        )

        assert "1. Step A" in result
        assert "2. Step B" in result
        assert "3. Step C" in result


class TestFormatGenericError:
    """Test format_generic_error function."""

    def test_format_generic_error_basic(self):
        """Test basic generic error formatting."""
        result = format_generic_error(
            operation="test operation",
            error_type="TestError",
            context="test context",
            details="test details",
        )

        assert "test operation" in result
        assert "TestError" in result
        assert "test context" in result
        assert "test details" in result

    def test_format_generic_error_includes_troubleshooting(self):
        """Test that generic error includes troubleshooting steps."""
        result = format_generic_error(
            operation="op",
            error_type="type",
            context="ctx",
            details="det",
        )

        assert "Troubleshooting" in result
        assert "get_server_health" in result


class TestGetErrorConfig:
    """Test get_error_config function."""

    def test_get_error_config_exact_match(self):
        """Test getting config for exact exception type."""
        error = OpenZimMcpFileNotFoundError("Test")
        config = get_error_config(error)

        assert config is not None
        assert "File Not Found" in config.title

    def test_get_error_config_archive_error(self):
        """Test getting config for archive error."""
        error = OpenZimMcpArchiveError("Archive failed")
        config = get_error_config(error)

        assert config is not None
        assert "Archive" in config.title

    def test_get_error_config_security_error(self):
        """Test getting config for security error."""
        error = OpenZimMcpSecurityError("Security violation")
        config = get_error_config(error)

        assert config is not None
        assert "Security" in config.title

    def test_get_error_config_validation_error(self):
        """Test getting config for validation error."""
        error = OpenZimMcpValidationError("Invalid input")
        config = get_error_config(error)

        assert config is not None
        assert "Validation" in config.title

    def test_get_error_config_rate_limit_error(self):
        """Test getting config for rate limit error."""
        error = OpenZimMcpRateLimitError("Too many requests")
        config = get_error_config(error)

        assert config is not None
        assert "Rate Limit" in config.title

    def test_get_error_config_permission_pattern(self):
        """Test getting config for permission error pattern."""
        error = Exception("Permission denied accessing file")
        config = get_error_config(error)

        assert config is not None
        assert config == PERMISSION_ERROR_CONFIG

    def test_get_error_config_access_pattern(self):
        """Test getting config for access error pattern."""
        error = Exception("Access denied to resource")
        config = get_error_config(error)

        assert config is not None
        assert config == PERMISSION_ERROR_CONFIG

    def test_get_error_config_not_found_pattern(self):
        """Test getting config for not found error pattern."""
        error = Exception("Resource not found")
        config = get_error_config(error)

        assert config is not None
        assert config == NOT_FOUND_ERROR_CONFIG

    def test_get_error_config_does_not_exist_pattern(self):
        """Test getting config for does not exist error pattern."""
        error = Exception("File does not exist")
        config = get_error_config(error)

        assert config is not None
        assert config == NOT_FOUND_ERROR_CONFIG

    def test_get_error_config_unknown_error(self):
        """Test getting config for unknown error type."""
        error = Exception("Some random error")
        config = get_error_config(error)

        assert config is None

    def test_get_error_config_case_insensitive(self):
        """Test that pattern matching is case insensitive."""
        error = Exception("PERMISSION DENIED")
        config = get_error_config(error)

        assert config is not None
        assert config == PERMISSION_ERROR_CONFIG


class TestErrorConfigSteps:
    """Test that error configs have useful steps."""

    def test_file_not_found_steps_are_actionable(self):
        """Test that file not found steps are actionable."""
        config = ERROR_CONFIGS[OpenZimMcpFileNotFoundError]

        # Should mention checking the path
        steps_text = " ".join(config.steps).lower()
        assert "path" in steps_text or "file" in steps_text

    def test_archive_error_steps_mention_diagnostics(self):
        """Test that archive error steps mention diagnostics."""
        config = ERROR_CONFIGS[OpenZimMcpArchiveError]

        steps_text = " ".join(config.steps).lower()
        # Should mention some form of verification or diagnostics
        assert (
            "verify" in steps_text or "check" in steps_text or "diagnose" in steps_text
        )

    def test_security_error_steps_mention_paths(self):
        """Test that security error steps mention paths."""
        config = ERROR_CONFIGS[OpenZimMcpSecurityError]

        steps_text = " ".join(config.steps).lower()
        assert "path" in steps_text or "directory" in steps_text

    def test_rate_limit_steps_mention_waiting(self):
        """Test that rate limit error steps mention waiting."""
        config = ERROR_CONFIGS[OpenZimMcpRateLimitError]

        steps_text = " ".join(config.steps).lower()
        assert "wait" in steps_text or "retry" in steps_text
