"""
Unit tests for schema metaschema validation.

Tests that schemas validate correctly against the schema-for-schemas metaschema.
"""

import pytest
import json
from pathlib import Path
try:
    from jsonschema import Draft7Validator
    JSONSCHEMA_AVAILABLE = True
except ImportError:
    JSONSCHEMA_AVAILABLE = False

from markitect.schema_loader import MarkdownSchemaLoader


@pytest.fixture
def loader():
    """Create a schema loader instance."""
    return MarkdownSchemaLoader()


@pytest.fixture
def metaschema(loader):
    """Load the metaschema."""
    metaschema_path = Path(__file__).parent.parent / 'markitect' / 'schemas' / 'schema-schema-v1.0.md'
    metaschema_data = loader.load_schema(metaschema_path)
    return metaschema_data['schema']


@pytest.mark.skipif(not JSONSCHEMA_AVAILABLE, reason="jsonschema not installed")
class TestMetaschemaValidation:
    """Tests for validating schemas against the metaschema."""

    def test_metaschema_self_validation(self, loader, metaschema):
        """Test that metaschema validates itself."""
        validator = Draft7Validator(metaschema)
        errors = list(validator.iter_errors(metaschema))

        assert len(errors) == 0, f"Metaschema should validate itself, but got errors: {errors}"

    def test_manpage_schema_validation(self, loader, metaschema):
        """Test that manpage schema validates against metaschema."""
        manpage_path = Path(__file__).parent.parent / 'markitect' / 'schemas' / 'manpage-schema-v1.0.md'
        manpage_data = loader.load_schema(manpage_path)
        manpage_schema = manpage_data['schema']

        validator = Draft7Validator(metaschema)
        errors = list(validator.iter_errors(manpage_schema))

        assert len(errors) == 0, f"Manpage schema should be valid, but got errors: {[e.message for e in errors]}"

    def test_required_fields_enforced(self, metaschema):
        """Test that metaschema enforces required fields."""
        # Schema missing required fields
        invalid_schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            # Missing: $id, title, description, version
        }

        validator = Draft7Validator(metaschema)
        errors = list(validator.iter_errors(invalid_schema))

        # Should have errors for missing required fields
        assert len(errors) > 0
        error_messages = [e.message for e in errors]

        # Check that required fields are mentioned
        required_fields = ['$id', 'title', 'description', 'version']
        for field in required_fields:
            assert any(field in msg for msg in error_messages), \
                f"Should report missing required field: {field}"

    def test_version_format_validation(self, metaschema):
        """Test that metaschema validates version format."""
        # Invalid version formats
        invalid_versions = [
            "1.0",        # Missing patch
            "v1.0.0",     # Has v prefix
            "1",          # Only major
            "1.0.0.0",    # Too many parts
        ]

        for invalid_version in invalid_versions:
            schema = {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "$id": "https://markitect.dev/schemas/test/v1.0",
                "title": "Test Schema",
                "description": "Test schema for validation",
                "version": invalid_version
            }

            validator = Draft7Validator(metaschema)
            errors = list(validator.iter_errors(schema))

            assert len(errors) > 0, f"Should reject invalid version: {invalid_version}"
            assert any('pattern' in str(e.schema_path) for e in errors), \
                f"Should be a pattern error for version: {invalid_version}"

    def test_valid_version_format(self, metaschema):
        """Test that valid version formats are accepted."""
        valid_versions = [
            "1.0.0",
            "2.5.3",
            "10.25.99",
            "0.0.1",
        ]

        for valid_version in valid_versions:
            schema = {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "$id": "https://markitect.dev/schemas/test/v1.0",
                "title": "Test Schema",
                "description": "Test schema for validation",
                "version": valid_version
            }

            validator = Draft7Validator(metaschema)
            errors = list(validator.iter_errors(schema))

            # Filter out errors not related to version
            version_errors = [e for e in errors if 'version' in str(e.path)]
            assert len(version_errors) == 0, \
                f"Should accept valid version: {valid_version}, but got errors: {version_errors}"

    def test_id_format_validation(self, metaschema):
        """Test that metaschema validates $id format."""
        invalid_ids = [
            "http://example.com/schema",  # Not HTTPS
            "https://example.com/schema", # No version
            "schema/v1.0",                # Not a URL
            "https://example.com/schemas/test/1.0",  # No 'v' prefix
        ]

        for invalid_id in invalid_ids:
            schema = {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "$id": invalid_id,
                "title": "Test Schema",
                "description": "Test schema for validation",
                "version": "1.0.0"
            }

            validator = Draft7Validator(metaschema)
            errors = list(validator.iter_errors(schema))

            assert len(errors) > 0, f"Should reject invalid $id: {invalid_id}"

    def test_valid_id_format(self, metaschema):
        """Test that valid $id formats are accepted."""
        valid_ids = [
            "https://markitect.dev/schemas/test/v1.0",
            "https://example.com/schemas/my-schema/v2.5",
            "https://api.example.com/schemas/domain/v10.25",
        ]

        for valid_id in valid_ids:
            schema = {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "$id": valid_id,
                "title": "Test Schema",
                "description": "Test schema for validation",
                "version": "1.0.0"
            }

            validator = Draft7Validator(metaschema)
            errors = list(validator.iter_errors(schema))

            # Filter out errors not related to $id
            id_errors = [e for e in errors if '$id' in str(e.path)]
            assert len(id_errors) == 0, \
                f"Should accept valid $id: {valid_id}, but got errors: {id_errors}"

    def test_section_classification_validation(self, metaschema):
        """Test that section classifications are validated."""
        # Invalid classification
        schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "$id": "https://markitect.dev/schemas/test/v1.0",
            "title": "Test Schema",
            "description": "Test schema for validation",
            "version": "1.0.0",
            "x-markitect-sections": {
                "SYNOPSIS": {
                    "classification": "mandatory",  # Invalid, should be 'required'
                    "heading_level": 2
                }
            }
        }

        validator = Draft7Validator(metaschema)
        errors = list(validator.iter_errors(schema))

        assert len(errors) > 0
        # Should have error about invalid enum value
        assert any('enum' in str(e.schema_path) or 'mandatory' in e.message for e in errors)

    def test_valid_section_classifications(self, metaschema):
        """Test that valid section classifications are accepted."""
        classifications = ['required', 'recommended', 'optional', 'discouraged', 'improper']

        for classification in classifications:
            schema = {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "$id": "https://markitect.dev/schemas/test/v1.0",
                "title": "Test Schema",
                "description": "Test schema for validation",
                "version": "1.0.0",
                "x-markitect-sections": {
                    "TEST_SECTION": {
                        "classification": classification,
                        "heading_level": 2
                    }
                }
            }

            validator = Draft7Validator(metaschema)
            errors = list(validator.iter_errors(schema))

            # Filter errors related to classification
            classification_errors = [e for e in errors if 'classification' in str(e.path)]
            assert len(classification_errors) == 0, \
                f"Should accept valid classification: {classification}"

    def test_schema_with_all_extensions(self, metaschema):
        """Test schema with all MarkiTect extensions."""
        schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "$id": "https://markitect.dev/schemas/test/v1.0",
            "title": "Complete Test Schema",
            "description": "Schema with all MarkiTect extensions",
            "version": "1.0.0",
            "type": "object",
            "x-markitect-sections": {
                "SYNOPSIS": {
                    "classification": "required",
                    "heading_level": 2,
                    "content_instruction": "Brief overview",
                    "min_paragraphs": 1,
                    "max_paragraphs": 3
                }
            },
            "x-markitect-content-control": {
                "synopsis": {
                    "required_patterns": ["\\*\\*.*\\*\\*"],
                    "content_quality": {
                        "min_words": 10,
                        "max_words": 100,
                        "readability_target": "technical"
                    }
                }
            },
            "x-markitect-metadata": {
                "status": "stable",
                "authors": ["Test Author <test@example.com>"],
                "tags": ["test", "example"]
            }
        }

        validator = Draft7Validator(metaschema)
        errors = list(validator.iter_errors(schema))

        assert len(errors) == 0, f"Complete schema should be valid, but got errors: {[e.message for e in errors]}"


class TestSchemaLoaderIntegration:
    """Integration tests for schema loader with metaschema."""

    def test_load_and_validate_manpage_schema(self, loader, metaschema):
        """Test loading and validating manpage schema."""
        manpage_path = Path(__file__).parent.parent / 'markitect' / 'schemas' / 'manpage-schema-v1.0.md'

        # Load schema
        schema_data = loader.load_schema(manpage_path)
        schema = schema_data['schema']

        # Check metadata was merged
        assert 'x-markitect-source' in schema
        assert schema['x-markitect-source']['format'] == 'markdown'
        assert schema['x-markitect-source']['filename'] == 'manpage-schema-v1.0.md'

        # Validate structure
        issues = loader.validate_schema_structure(schema)
        # Should have no critical issues
        assert all('Missing' not in issue or 'recommended' in issue.lower() for issue in issues)

    def test_metaschema_structure_validation(self, loader):
        """Test metaschema structure with loader's validator."""
        metaschema_path = Path(__file__).parent.parent / 'markitect' / 'schemas' / 'schema-schema-v1.0.md'
        metaschema_data = loader.load_schema(metaschema_path)
        metaschema = metaschema_data['schema']

        # Validate structure
        issues = loader.validate_schema_structure(metaschema)

        # Metaschema should have minimal issues
        critical_issues = [i for i in issues if 'Missing required field' in i]
        assert len(critical_issues) == 0, f"Metaschema has critical issues: {critical_issues}"
