"""
Test for Issue #7: Validate a Markdown File Against a Schema.

Tests the ability to validate markdown documents against JSON schemas for
arc42 architecture documentation compliance checking - critical for intelligent
document analysis and plan-actual comparison capabilities.
"""

import json
import pytest
from pathlib import Path
from tempfile import NamedTemporaryFile

from markitect.schema_validator import SchemaValidator
from markitect.schema_generator import SchemaGenerator
from markitect.exceptions import FileNotFoundError, SchemaValidationError, InvalidSchemaError


class TestIssue7SchemaValidation:
    """Test suite for schema validation of markdown files."""

    def setup_method(self):
        """Set up test environment."""
        self.schema_validator = SchemaValidator()
        self.schema_generator = SchemaGenerator()

    def teardown_method(self):
        """Clean up after tests."""
        pass

    def test_validate_markdown_against_matching_schema_returns_true(self):
        """
        ISSUE #7: Test markdown validation against matching schema returns True.

        Verifies that a markdown document that matches its generated schema
        returns True for compliance - essential for arc42 document validation.
        """
        # Arrange - Create markdown with known structure
        markdown_content = """# Architecture Document

This document describes the system architecture.

## Overview

The system consists of several components:

- Component A
- Component B

## Details

More detailed information here.
"""

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Generate schema from the same content
            schema = self.schema_generator.generate_schema_from_file(temp_file)

            # Act - Validate the document against its own schema
            is_valid = self.schema_validator.validate_file_against_schema(temp_file, schema)

            # Assert - Document should match its own schema
            assert is_valid is True

        finally:
            temp_file.unlink()

    def test_validate_markdown_against_non_matching_schema_returns_false(self):
        """
        ISSUE #7: Test markdown validation against non-matching schema returns False.

        Verifies that a markdown document that doesn't match the schema structure
        returns False - critical for detecting arc42 compliance violations.
        """
        # Arrange - Create markdown document
        markdown_content = """# Single Heading

Just one paragraph of content.
"""

        # Create schema that expects different structure (multiple headings)
        expected_schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "properties": {
                "headings": {
                    "type": "object",
                    "properties": {
                        "level_1": {
                            "type": "array",
                            "minItems": 2,  # Expect at least 2 level-1 headings
                            "maxItems": 2
                        },
                        "level_2": {
                            "type": "array",
                            "minItems": 1   # Expect at least 1 level-2 heading
                        }
                    },
                    "required": ["level_1", "level_2"]
                }
            },
            "required": ["headings"]
        }

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Act - Validate against non-matching schema
            is_valid = self.schema_validator.validate_file_against_schema(temp_file, expected_schema)

            # Assert - Document should not match the schema
            assert is_valid is False

        finally:
            temp_file.unlink()

    def test_validate_markdown_with_depth_limited_schema(self):
        """
        ISSUE #7: Test validation with depth-limited schemas for arc42 sections.

        Ensures validation works correctly with depth-limited schemas,
        essential for arc42 section-specific compliance checking.
        """
        # Arrange - Markdown with multiple heading levels
        markdown_content = """# Main Architecture

## System Overview

Content here.

### Implementation Details

Deep content.

#### Technical Notes

Very deep content.
"""

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Generate schema with depth limit of 2
            schema_depth_2 = self.schema_generator.generate_schema_from_file(temp_file, max_depth=2)

            # Act - Validate against depth-limited schema
            is_valid = self.schema_validator.validate_file_against_schema(temp_file, schema_depth_2)

            # Assert - Document should match depth-limited schema
            assert is_valid is True

        finally:
            temp_file.unlink()

    def test_validate_file_not_found_raises_exception(self):
        """
        ISSUE #7: Test error handling when markdown file doesn't exist.
        """
        # Arrange - Non-existent file and valid schema
        non_existent_file = Path("/tmp/non_existent_file.md")
        valid_schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object"
        }

        # Act & Assert - Should raise FileNotFoundError
        with pytest.raises(FileNotFoundError):
            self.schema_validator.validate_file_against_schema(non_existent_file, valid_schema)

    def test_validate_with_invalid_schema_raises_exception(self):
        """
        ISSUE #7: Test error handling for invalid JSON schema.
        """
        # Arrange - Valid markdown file and invalid schema
        markdown_content = "# Test\n\nContent."

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        invalid_schema = {
            # Missing required $schema and type fields
            "properties": {}
        }

        try:
            # Act & Assert - Should raise InvalidSchemaError
            with pytest.raises(InvalidSchemaError):
                self.schema_validator.validate_file_against_schema(temp_file, invalid_schema)

        finally:
            temp_file.unlink()

    def test_validate_markdown_with_complex_schema_requirements(self):
        """
        ISSUE #7: Test validation against complex schema requirements.

        Validates comprehensive schema rules including specific content
        requirements, essential for arc42 template compliance.
        """
        # Arrange - Create markdown that should match complex requirements
        markdown_content = """# Architecture Decision Record

## Status

Accepted

## Context

This document describes architectural decisions.

## Decision

We decided to use microservices architecture.

## Consequences

- Benefit: Better scalability
- Cost: Increased complexity
"""

        # Create schema with specific structural requirements
        adr_schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "title": "Architecture Decision Record Schema",
            "properties": {
                "headings": {
                    "type": "object",
                    "properties": {
                        "level_1": {
                            "type": "array",
                            "minItems": 1,
                            "maxItems": 1  # Exactly one main title
                        },
                        "level_2": {
                            "type": "array",
                            "minItems": 4,  # Expect Status, Context, Decision, Consequences
                            "maxItems": 4
                        }
                    },
                    "required": ["level_1", "level_2"]
                },
                "paragraphs": {
                    "type": "array",
                    "minItems": 4  # Expect content under each section
                },
                "lists": {
                    "type": "array",
                    "minItems": 1  # Expect consequences list
                }
            },
            "required": ["headings", "paragraphs", "lists"]
        }

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Act - Validate against ADR schema
            is_valid = self.schema_validator.validate_file_against_schema(temp_file, adr_schema)

            # Assert - Document should match ADR schema requirements
            assert is_valid is True

        finally:
            temp_file.unlink()

    def test_validate_returns_false_for_missing_required_elements(self):
        """
        ISSUE #7: Test validation returns False when required elements are missing.

        Ensures strict compliance checking for arc42 architectural templates.
        """
        # Arrange - Incomplete markdown missing required elements
        incomplete_markdown = """# Incomplete Document

This document is missing required sections.
"""

        # Schema requiring multiple sections
        strict_schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "properties": {
                "headings": {
                    "type": "object",
                    "properties": {
                        "level_1": {
                            "type": "array",
                            "minItems": 1
                        },
                        "level_2": {
                            "type": "array",
                            "minItems": 3  # Require at least 3 level-2 headings
                        }
                    },
                    "required": ["level_1", "level_2"]
                },
                "lists": {
                    "type": "array",
                    "minItems": 2  # Require at least 2 lists
                }
            },
            "required": ["headings", "lists"]
        }

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(incomplete_markdown)
            temp_file = Path(f.name)

        try:
            # Act - Validate incomplete document
            is_valid = self.schema_validator.validate_file_against_schema(temp_file, strict_schema)

            # Assert - Should return False due to missing required elements
            assert is_valid is False

        finally:
            temp_file.unlink()

    def test_validate_with_schema_from_json_string(self):
        """
        ISSUE #7: Test validation using schema provided as JSON string.

        Supports flexible schema input for CLI and API integration.
        """
        # Arrange - Simple markdown and schema as JSON string
        markdown_content = """# Test Document

Simple test content.
"""

        schema_json = """{
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "properties": {
                "headings": {
                    "type": "object",
                    "properties": {
                        "level_1": {
                            "type": "array",
                            "minItems": 1,
                            "maxItems": 1
                        }
                    }
                }
            }
        }"""

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
            f.write(markdown_content)
            temp_file = Path(f.name)

        try:
            # Act - Validate using JSON string schema
            is_valid = self.schema_validator.validate_file_against_schema_string(temp_file, schema_json)

            # Assert - Should successfully validate
            assert is_valid is True

        finally:
            temp_file.unlink()


