"""
Tests for Issue #40: Associated Files Management.

This module tests the functionality for managing associated markdown and schema files
with convention-based naming and automatic file placement.
"""

import pytest
from pathlib import Path
from tempfile import TemporaryDirectory

from markitect.associated_files import AssociatedFilesManager


class TestIssue40AssociatedFiles:
    """Test suite for associated files management."""

    @pytest.fixture
    def manager(self):
        """Create an AssociatedFilesManager instance."""
        return AssociatedFilesManager()

    @pytest.fixture
    def temp_dir(self):
        """Create a temporary directory for testing."""
        with TemporaryDirectory() as temp_dir:
            yield Path(temp_dir)

    def test_associated_files_manager_can_be_created(self, manager):
        """AssociatedFilesManager class should be importable and instantiable."""
        assert manager is not None
        assert isinstance(manager, AssociatedFilesManager)

    def test_get_associated_schema_path(self, manager, temp_dir):
        """Should generate correct associated schema path for markdown file."""
        md_file = temp_dir / "document.md"
        md_file.write_text("# Test Document")

        schema_path = manager.get_associated_schema_path(md_file)

        assert schema_path == temp_dir / "document.json"
        assert schema_path.parent == md_file.parent
        assert schema_path.stem == md_file.stem

    def test_get_associated_markdown_path(self, manager, temp_dir):
        """Should generate correct associated markdown path for schema file."""
        schema_file = temp_dir / "document.json"
        schema_file.write_text('{"type": "object"}')

        md_path = manager.get_associated_markdown_path(schema_file)

        assert md_path == temp_dir / "document.md"
        assert md_path.parent == schema_file.parent
        assert md_path.stem == schema_file.stem

    def test_find_associated_schema(self, manager, temp_dir):
        """Should find existing associated schema file."""
        md_file = temp_dir / "blog_post.md"
        schema_file = temp_dir / "blog_post.json"

        md_file.write_text("# Blog Post")
        schema_file.write_text('{"type": "object"}')

        found_schema = manager.find_associated_schema(md_file)

        assert found_schema == schema_file
        assert found_schema.exists()

    def test_find_associated_markdown(self, manager, temp_dir):
        """Should find existing associated markdown file."""
        md_file = temp_dir / "article.md"
        schema_file = temp_dir / "article.json"

        md_file.write_text("# Article")
        schema_file.write_text('{"type": "object"}')

        found_md = manager.find_associated_markdown(schema_file)

        assert found_md == md_file
        assert found_md.exists()

    def test_find_associated_files_returns_none_when_not_found(self, manager, temp_dir):
        """Should return None when associated files don't exist."""
        md_file = temp_dir / "lonely.md"
        md_file.write_text("# Lonely Document")

        schema_file = temp_dir / "orphan.json"
        schema_file.write_text('{"type": "object"}')

        assert manager.find_associated_schema(md_file) is None
        assert manager.find_associated_markdown(schema_file) is None

    def test_has_associated_schema(self, manager, temp_dir):
        """Should correctly detect if markdown file has associated schema."""
        md_file = temp_dir / "test.md"
        schema_file = temp_dir / "test.json"

        md_file.write_text("# Test")

        # No schema initially
        assert not manager.has_associated_schema(md_file)

        # Create schema
        schema_file.write_text('{"type": "object"}')
        assert manager.has_associated_schema(md_file)

    def test_has_associated_markdown(self, manager, temp_dir):
        """Should correctly detect if schema file has associated markdown."""
        md_file = temp_dir / "guide.md"
        schema_file = temp_dir / "guide.json"

        schema_file.write_text('{"type": "object"}')

        # No markdown initially
        assert not manager.has_associated_markdown(schema_file)

        # Create markdown
        md_file.write_text("# Guide")
        assert manager.has_associated_markdown(schema_file)

    def test_list_file_pairs(self, manager, temp_dir):
        """Should list all associated file pairs in directory."""
        # Create some paired files
        (temp_dir / "doc1.md").write_text("# Doc 1")
        (temp_dir / "doc1.json").write_text('{"type": "object"}')

        (temp_dir / "doc2.md").write_text("# Doc 2")
        (temp_dir / "doc2.json").write_text('{"type": "object"}')

        # Create orphaned files
        (temp_dir / "orphan.md").write_text("# Orphan")
        (temp_dir / "lonely.json").write_text('{"type": "object"}')

        pairs = manager.list_file_pairs(temp_dir)

        assert len(pairs) == 2
        pair_names = {pair['basename'] for pair in pairs}
        assert 'doc1' in pair_names
        assert 'doc2' in pair_names

    def test_get_file_pair_info(self, manager, temp_dir):
        """Should provide detailed information about file pairs."""
        md_file = temp_dir / "example.md"
        schema_file = temp_dir / "example.json"

        md_file.write_text("# Example Document\n\nContent here.")
        schema_file.write_text('{"type": "object", "title": "Example Schema"}')

        pair_info = manager.get_file_pair_info(md_file)

        assert pair_info['basename'] == 'example'
        assert pair_info['markdown_file'] == md_file
        assert pair_info['schema_file'] == schema_file
        assert pair_info['both_exist'] is True
        assert 'markdown_size' in pair_info
        assert 'schema_size' in pair_info

    def test_supports_nested_directories(self, manager, temp_dir):
        """Should work correctly with nested directory structures."""
        nested_dir = temp_dir / "docs" / "architecture"
        nested_dir.mkdir(parents=True)

        md_file = nested_dir / "system.md"
        schema_file = nested_dir / "system.json"

        md_file.write_text("# System Architecture")

        schema_path = manager.get_associated_schema_path(md_file)
        assert schema_path == schema_file
        assert not manager.has_associated_schema(md_file)

        schema_file.write_text('{"type": "object"}')
        assert manager.has_associated_schema(md_file)

    def test_handles_complex_filenames(self, manager, temp_dir):
        """Should handle complex filenames with special characters."""
        complex_name = "my-complex_file.name-v2"
        md_file = temp_dir / f"{complex_name}.md"

        md_file.write_text("# Complex File")

        schema_path = manager.get_associated_schema_path(md_file)
        expected_schema = temp_dir / f"{complex_name}.json"

        assert schema_path == expected_schema
        assert schema_path.stem == complex_name

    def test_validate_file_extensions(self, manager, temp_dir):
        """Should validate that files have correct extensions."""
        txt_file = temp_dir / "document.txt"
        txt_file.write_text("Not markdown")

        from markitect.associated_files import InvalidFileTypeError

        with pytest.raises(InvalidFileTypeError, match="Expected markdown file"):
            manager.get_associated_schema_path(txt_file)

        xml_file = temp_dir / "schema.xml"
        xml_file.write_text("<schema/>")

        with pytest.raises(InvalidFileTypeError, match="Expected schema file"):
            manager.get_associated_markdown_path(xml_file)


class TestAssociatedFilesIntegration:
    """Test integration of associated files with existing commands."""

    @pytest.fixture
    def manager(self):
        return AssociatedFilesManager()

    @pytest.fixture
    def temp_dir(self):
        with TemporaryDirectory() as temp_dir:
            yield Path(temp_dir)

    def test_schema_generate_default_output_placement(self, manager, temp_dir):
        """Schema generation should default to placing output next to source."""
        md_file = temp_dir / "article.md"
        md_file.write_text("# Article\n\n## Introduction\n\nContent here.")

        expected_schema_path = manager.get_associated_schema_path(md_file)

        # This would be the expected behavior for schema-generate command
        assert expected_schema_path == temp_dir / "article.json"

    def test_stub_generate_default_output_placement(self, manager, temp_dir):
        """Stub generation should default to placing output next to schema."""
        schema_file = temp_dir / "template.json"
        schema_file.write_text('''{
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "title": "Template Schema"
        }''')

        expected_md_path = manager.get_associated_markdown_path(schema_file)

        # This would be the expected behavior for generate-stub command
        assert expected_md_path == temp_dir / "template.md"

    def test_validation_auto_discovery(self, manager, temp_dir):
        """Validation should auto-discover associated schema files."""
        md_file = temp_dir / "document.md"
        schema_file = temp_dir / "document.json"

        md_file.write_text("# Document")
        schema_file.write_text('{"type": "object"}')

        # Validation command should find schema automatically
        found_schema = manager.find_associated_schema(md_file)
        assert found_schema == schema_file

    def test_workflow_roundtrip(self, manager, temp_dir):
        """Test complete workflow: markdown → schema → stub."""
        # Start with markdown
        original_md = temp_dir / "workflow_test.md"
        original_md.write_text("# Workflow Test\n\n## Section 1\n\nContent.")

        # Generate schema (should place next to original)
        schema_path = manager.get_associated_schema_path(original_md)
        assert schema_path == temp_dir / "workflow_test.json"

        # Create the schema (simulating schema-generate command)
        schema_path.write_text('{"type": "object", "title": "Workflow Test"}')

        # Generate stub from schema (should use different name to avoid conflict)
        stub_path = temp_dir / "workflow_test_stub.md"  # Avoiding conflict with original

        # Verify the association logic works
        assert manager.has_associated_schema(original_md)
        assert manager.has_associated_markdown(schema_path)