"""Schema validation tests for logging module.

Validates that generated log events, configs, and policies conform to
Crucible JSON schemas.

NOTE: These tests are currently skipped because they require a local schema
resolver to handle $ref resolution. The schemas use remote $id URLs
(https://schemas.fulmenhq.dev/crucible/...) that don't exist yet. We need
to implement a local resolver that maps these URLs to local schema files.

See: .plans/roadmap/local-schema-resolver.md
"""

from datetime import UTC, datetime

import pytest

from pyfulmen.logging import Logger
from pyfulmen.logging._models import LoggingProfile
from pyfulmen.schema.validator import validate_against_schema

# Skip all schema validation tests until local resolver is implemented
pytestmark = pytest.mark.skip(reason="Requires local schema resolver - schemas use remote $id URLs not yet published")


class TestLogEventSchemaValidation:
    """Test log events validate against log-event.schema.json."""

    def test_minimal_log_event_validates(self):
        """Test minimal log event passes schema validation."""
        event = {
            "timestamp": datetime.now(UTC).isoformat(),
            "severity": "INFO",
            "severityLevel": 20,
            "message": "Test message",
            "service": "test-service",
            "environment": "test",
        }

        # Should not raise ValidationError
        validate_against_schema(data=event, category="observability/logging", version="v1.0.0", name="log-event")

    def test_full_log_event_validates(self):
        """Test complete log event with all fields passes validation."""
        event = {
            "timestamp": "2024-10-14T12:00:00.123456Z",
            "severity": "ERROR",
            "severityLevel": 40,
            "message": "Payment processing failed",
            "service": "payment-api",
            "component": "payment-processor",
            "environment": "production",
            "correlationId": "550e8400-e29b-41d4-a716-446655440000",
            "context": {
                "payment_id": "pay_123",
                "amount": 99.99,
                "currency": "USD",
                "error_code": "INSUFFICIENT_FUNDS",
            },
            "caller": {"file": "payment.py", "line": 45, "function": "process_payment"},
            "stacktrace": "Traceback (most recent call last)...",
            "redactionFlags": ["secrets"],
            "throttleBucket": "payment-events",
        }

        validate_against_schema(data=event, category="observability/logging", version="v1.0.0", name="log-event")

    def test_generated_simple_event_validates(self):
        """Test event generated by SIMPLE logger validates."""
        logger = Logger(service="test-app", profile=LoggingProfile.SIMPLE)

        # Create an event (we'll extract it from the internal structure)
        event_data = {
            "timestamp": datetime.now(UTC).isoformat(),
            "severity": "INFO",
            "severityLevel": 20,
            "message": "Test event",
            "service": "test-app",
            "environment": "development",
        }

        validate_against_schema(data=event_data, category="observability/logging", version="v1.0.0", name="log-event")

    def test_generated_structured_event_validates(self):
        """Test event generated by STRUCTURED logger validates."""
        event_data = {
            "timestamp": datetime.now(UTC).isoformat(),
            "severity": "INFO",
            "severityLevel": 20,
            "message": "Request processed",
            "service": "api-service",
            "environment": "production",
            "context": {"method": "GET", "path": "/api/users", "duration_ms": 45},
        }

        validate_against_schema(data=event_data, category="observability/logging", version="v1.0.0", name="log-event")

    def test_generated_enterprise_event_validates(self):
        """Test event generated by ENTERPRISE logger validates."""
        event_data = {
            "timestamp": datetime.now(UTC).isoformat(),
            "severity": "INFO",
            "severityLevel": 20,
            "message": "Payment processed",
            "service": "payment-api",
            "component": "payment-processor",
            "environment": "production",
            "correlationId": "550e8400-e29b-41d4-a716-446655440000",
            "context": {"payment_id": "pay_123", "amount": 99.99},
        }

        validate_against_schema(data=event_data, category="observability/logging", version="v1.0.0", name="log-event")

    def test_invalid_severity_fails_validation(self):
        """Test event with invalid severity fails validation."""
        event = {
            "timestamp": datetime.now(UTC).isoformat(),
            "severity": "INVALID",  # Not a valid severity
            "severityLevel": 20,
            "message": "Test",
            "service": "test",
            "environment": "test",
        }

        with pytest.raises(Exception):  # ValidationError or similar
            validate_against_schema(data=event, category="observability/logging", version="v1.0.0", name="log-event")

    def test_missing_required_field_fails_validation(self):
        """Test event missing required field fails validation."""
        event = {
            "timestamp": datetime.now(UTC).isoformat(),
            "severity": "INFO",
            # Missing severityLevel (required)
            "message": "Test",
            "service": "test",
            "environment": "test",
        }

        with pytest.raises(Exception):
            validate_against_schema(data=event, category="observability/logging", version="v1.0.0", name="log-event")


class TestLoggerConfigSchemaValidation:
    """Test logger configs validate against logger-config.schema.json."""

    def test_simple_config_validates(self):
        """Test SIMPLE profile config validates."""
        config = {
            "profile": "SIMPLE",
            "service": "test-app",
            "environment": "development",
            "defaultLevel": "INFO",
            "sinks": [{"type": "console", "format": "text"}],
        }

        validate_against_schema(data=config, category="observability/logging", version="v1.0.0", name="logger-config")

    def test_structured_config_validates(self):
        """Test STRUCTURED profile config validates."""
        config = {
            "profile": "STRUCTURED",
            "service": "api-service",
            "environment": "production",
            "defaultLevel": "INFO",
            "sinks": [{"type": "console", "format": "json", "level": "INFO"}],
        }

        validate_against_schema(data=config, category="observability/logging", version="v1.0.0", name="logger-config")

    def test_enterprise_config_validates(self):
        """Test ENTERPRISE profile config validates."""
        config = {
            "profile": "ENTERPRISE",
            "service": "payment-api",
            "environment": "production",
            "policyFile": ".goneat/logging-policy.yaml",
            "defaultLevel": "INFO",
            "sinks": [{"type": "console", "format": "json"}],
            "middleware": [{"name": "correlation", "enabled": True, "order": 0}],
            "throttling": {
                "enabled": True,
                "maxRate": 10000,
                "burstSize": 1000,
                "windowSize": 60,
                "dropPolicy": "drop-oldest",
            },
        }

        validate_against_schema(data=config, category="observability/logging", version="v1.0.0", name="logger-config")

    def test_config_with_static_fields_validates(self):
        """Test config with static fields validates."""
        config = {
            "profile": "STRUCTURED",
            "service": "worker-service",
            "environment": "staging",
            "defaultLevel": "DEBUG",
            "sinks": [{"type": "console", "format": "json"}],
            "staticFields": {
                "version": "2.1.0",
                "region": "us-west-2",
                "instance_id": "i-1234567890abcdef",
            },
        }

        validate_against_schema(data=config, category="observability/logging", version="v1.0.0", name="logger-config")

    def test_config_with_file_sink_validates(self):
        """Test config with file sink validates."""
        config = {
            "profile": "STRUCTURED",
            "service": "app",
            "sinks": [
                {
                    "type": "file",
                    "name": "app-logs",
                    "format": "json",
                    "level": "DEBUG",
                    "options": {"path": "/var/log/app/app.log"},
                }
            ],
        }

        validate_against_schema(data=config, category="observability/logging", version="v1.0.0", name="logger-config")

    def test_config_with_rolling_file_sink_validates(self):
        """Test config with rolling-file sink validates."""
        config = {
            "profile": "STRUCTURED",
            "service": "app",
            "sinks": [
                {
                    "type": "rolling-file",
                    "name": "app-logs",
                    "format": "json",
                    "options": {
                        "path": "/var/log/app/app.log",
                        "maxSize": "100MB",
                        "maxBackups": 7,
                        "compress": True,
                    },
                }
            ],
        }

        validate_against_schema(data=config, category="observability/logging", version="v1.0.0", name="logger-config")

    def test_invalid_profile_fails_validation(self):
        """Test config with invalid profile fails validation."""
        config = {"profile": "INVALID_PROFILE", "service": "test", "sinks": [{"type": "console"}]}

        with pytest.raises(Exception):
            validate_against_schema(
                data=config,
                category="observability/logging",
                version="v1.0.0",
                name="logger-config",
            )


class TestLoggingPolicySchemaValidation:
    """Test logging policies validate against logging-policy.schema.json."""

    def test_minimal_policy_validates(self):
        """Test minimal policy validates."""
        policy = {"version": "1.0", "allowedProfiles": ["SIMPLE", "STRUCTURED", "ENTERPRISE"]}

        validate_against_schema(data=policy, category="observability/logging", version="v1.0.0", name="logging-policy")

    def test_full_policy_validates(self):
        """Test complete policy with all fields validates."""
        policy = {
            "version": "1.0",
            "allowedProfiles": ["STRUCTURED", "ENTERPRISE"],
            "requiredProfiles": {"api-service": ["ENTERPRISE"], "worker-service": ["STRUCTURED"]},
            "environmentRules": {
                "production": ["ENTERPRISE"],
                "staging": ["STRUCTURED", "ENTERPRISE"],
                "development": ["SIMPLE", "STRUCTURED"],
            },
            "profileRequirements": {
                "ENTERPRISE": {
                    "requiredMiddleware": ["correlation", "redact-secrets"],
                    "requiredSinks": ["console", "file"],
                    "minThrottleRate": 1000,
                }
            },
            "auditSettings": {"logPolicyViolations": True, "strictMode": False},
        }

        validate_against_schema(data=policy, category="observability/logging", version="v1.0.0", name="logging-policy")

    def test_policy_with_environment_rules_validates(self):
        """Test policy with environment-specific rules validates."""
        policy = {
            "version": "1.0",
            "allowedProfiles": ["SIMPLE", "STRUCTURED", "ENTERPRISE"],
            "environmentRules": {
                "production": ["ENTERPRISE"],
                "staging": ["STRUCTURED"],
                "development": ["SIMPLE"],
            },
        }

        validate_against_schema(data=policy, category="observability/logging", version="v1.0.0", name="logging-policy")

    def test_invalid_policy_version_fails(self):
        """Test policy with invalid version fails validation."""
        policy = {
            "version": "999.0",  # Invalid version
            "allowedProfiles": ["SIMPLE"],
        }

        with pytest.raises(Exception):
            validate_against_schema(
                data=policy,
                category="observability/logging",
                version="v1.0.0",
                name="logging-policy",
            )
