"""
Test suite for Issue #149 - Phase 2: Implement Explode-Implode Variants

Tests all three variant implementations (flat, hierarchical, semantic) with
comprehensive explode-implode operations, roundtrip validation, and CLI integration.
"""

import pytest
import tempfile
from pathlib import Path

from markitect.explode_variants import (
    ExplodeVariant, ExplodeOptions, ImplodeOptions,
    FlatVariant, HierarchicalVariant, SemanticVariant,
    VariantFactory, get_variant_factory, create_variant
)


class TestFlatVariant:
    """Test the FlatVariant implementation."""

    def test_flat_variant_initialization(self):
        """Test FlatVariant initialization."""
        variant = FlatVariant()
        assert variant.variant_type == ExplodeVariant.FLAT
        assert variant.name == "Flat Structure"
        assert "directories based on h1 headings" in variant.description

    def test_flat_variant_explode_basic(self):
        """Test basic explosion with flat variant."""
        with tempfile.TemporaryDirectory() as temp_dir:
            temp_path = Path(temp_dir)

            # Create test markdown file
            test_content = """# Introduction

This is the introduction.

## Overview

Some overview content.

# Chapter 1

First chapter content.

## Section 1.1

Section content here.

# Conclusion

Final thoughts.
"""

            input_file = temp_path / "test.md"
            input_file.write_text(test_content, encoding='utf-8')

            variant = FlatVariant()
            options = ExplodeOptions(
                variant=ExplodeVariant.FLAT,
                create_manifest=True
            )

            result = variant.explode(input_file, options)

            assert result.success
            assert result.variant_used == ExplodeVariant.FLAT
            assert result.output_directory.exists()
            assert result.manifest_path is not None
            assert result.manifest_path.exists()
            assert len(result.files_created) > 0

    def test_flat_variant_can_handle_directory(self):
        """Test flat variant directory detection."""
        with tempfile.TemporaryDirectory() as temp_dir:
            temp_path = Path(temp_dir)

            # Create flat structure
            (temp_path / "introduction").mkdir()
            (temp_path / "introduction" / "index.md").write_text("# Introduction")
            (temp_path / "chapter_1").mkdir()
            (temp_path / "chapter_1" / "index.md").write_text("# Chapter 1")

            variant = FlatVariant()
            assert variant.can_handle_directory(temp_path)

    def test_flat_variant_detection_patterns(self):
        """Test flat variant detection patterns."""
        variant = FlatVariant()
        patterns = variant.get_detection_patterns()

        assert patterns["manifest_type"] == "flat"
        assert "numbered_directory_ratio" in patterns
        assert "fallback_score" in patterns


class TestHierarchicalVariant:
    """Test the HierarchicalVariant implementation."""

    def test_hierarchical_variant_initialization(self):
        """Test HierarchicalVariant initialization."""
        variant = HierarchicalVariant()
        assert variant.variant_type == ExplodeVariant.HIERARCHICAL
        assert variant.name == "Hierarchical Structure"
        assert "numbered directory structures" in variant.description

    def test_hierarchical_variant_explode_basic(self):
        """Test basic explosion with hierarchical variant."""
        with tempfile.TemporaryDirectory() as temp_dir:
            temp_path = Path(temp_dir)

            # Create test markdown file
            test_content = """# Getting Started

Introduction to the system.

## Installation

How to install.

## Configuration

How to configure.

# Advanced Topics

Advanced material.

## Performance

Performance considerations.

# Conclusion

Final notes.
"""

            input_file = temp_path / "guide.md"
            input_file.write_text(test_content, encoding='utf-8')

            variant = HierarchicalVariant()
            options = ExplodeOptions(
                variant=ExplodeVariant.HIERARCHICAL,
                create_manifest=True
            )

            result = variant.explode(input_file, options)

            assert result.success
            assert result.variant_used == ExplodeVariant.HIERARCHICAL
            assert result.output_directory.exists()
            assert result.manifest_path is not None

            # Check for numbered directories
            subdirs = [d for d in result.output_directory.iterdir() if d.is_dir()]
            numbered_dirs = [d for d in subdirs if d.name.startswith(('01_', '02_', '03_'))]
            assert len(numbered_dirs) > 0

    def test_hierarchical_variant_can_handle_directory(self):
        """Test hierarchical variant directory detection."""
        with tempfile.TemporaryDirectory() as temp_dir:
            temp_path = Path(temp_dir)

            # Create hierarchical structure
            (temp_path / "01_introduction").mkdir()
            (temp_path / "01_introduction" / "index.md").write_text("# Introduction")
            (temp_path / "02_chapter_one").mkdir()
            (temp_path / "02_chapter_one" / "index.md").write_text("# Chapter One")

            variant = HierarchicalVariant()
            assert variant.can_handle_directory(temp_path)

    def test_hierarchical_variant_detection_patterns(self):
        """Test hierarchical variant detection patterns."""
        variant = HierarchicalVariant()
        patterns = variant.get_detection_patterns()

        assert patterns["manifest_type"] == "hierarchical"
        assert "numbered_directory_ratio" in patterns
        assert patterns["numbered_directory_ratio"]["min"] == 0.6


class TestSemanticVariant:
    """Test the SemanticVariant implementation."""

    def test_semantic_variant_initialization(self):
        """Test SemanticVariant initialization."""
        variant = SemanticVariant()
        assert variant.variant_type == ExplodeVariant.SEMANTIC
        assert variant.name == "Semantic Structure"
        assert "content-based directory groupings" in variant.description

    def test_semantic_variant_explode_basic(self):
        """Test basic explosion with semantic variant."""
        with tempfile.TemporaryDirectory() as temp_dir:
            temp_path = Path(temp_dir)

            # Create test markdown file with semantic content
            test_content = """# Introduction

Welcome to this comprehensive guide.

# Tutorial: Getting Started

This tutorial will walk you through the basics.

## Step 1: Installation

Install the software.

## Step 2: Configuration

Configure your environment.

# Reference: API Documentation

Complete API reference.

## Function Listing

List of all functions.

# Appendix A: Troubleshooting

Common issues and solutions.

# Conclusion

Final thoughts and summary.
"""

            input_file = temp_path / "manual.md"
            input_file.write_text(test_content, encoding='utf-8')

            variant = SemanticVariant()
            options = ExplodeOptions(
                variant=ExplodeVariant.SEMANTIC,
                create_manifest=True
            )

            result = variant.explode(input_file, options)

            assert result.success
            assert result.variant_used == ExplodeVariant.SEMANTIC
            assert result.output_directory.exists()
            assert result.manifest_path is not None

            # Check for semantic directories
            subdirs = [d.name for d in result.output_directory.iterdir() if d.is_dir()]
            semantic_dirs = [d for d in subdirs if d in ['introduction', 'tutorials', 'reference', 'appendices', 'conclusion']]
            assert len(semantic_dirs) > 0

    def test_semantic_variant_can_handle_directory(self):
        """Test semantic variant directory detection."""
        with tempfile.TemporaryDirectory() as temp_dir:
            temp_path = Path(temp_dir)

            # Create semantic structure
            (temp_path / "introduction").mkdir()
            (temp_path / "introduction" / "overview.md").write_text("# Overview")
            (temp_path / "chapters").mkdir()
            (temp_path / "chapters" / "basics.md").write_text("# Basics")
            (temp_path / "appendices").mkdir()
            (temp_path / "appendices" / "glossary.md").write_text("# Glossary")

            variant = SemanticVariant()
            assert variant.can_handle_directory(temp_path)

    def test_semantic_variant_detection_patterns(self):
        """Test semantic variant detection patterns."""
        variant = SemanticVariant()
        patterns = variant.get_detection_patterns()

        assert patterns["manifest_type"] == "semantic"
        assert "semantic_directory_ratio" in patterns
        assert patterns["semantic_directory_ratio"]["min"] == 0.4


class TestVariantFactory:
    """Test the VariantFactory functionality."""

    def test_variant_factory_initialization(self):
        """Test VariantFactory initialization."""
        factory = VariantFactory()
        assert factory is not None

        # Test that all built-in variants are registered
        stats = factory.get_variant_statistics()
        assert stats['total_variants'] >= 3
        assert ExplodeVariant.FLAT in stats['variant_types']
        assert ExplodeVariant.HIERARCHICAL in stats['variant_types']
        assert ExplodeVariant.SEMANTIC in stats['variant_types']

    def test_variant_factory_create_variant(self):
        """Test creating variants through factory."""
        factory = VariantFactory()

        flat_variant = factory.create_variant(ExplodeVariant.FLAT)
        assert isinstance(flat_variant, FlatVariant)

        hierarchical_variant = factory.create_variant(ExplodeVariant.HIERARCHICAL)
        assert isinstance(hierarchical_variant, HierarchicalVariant)

        semantic_variant = factory.create_variant(ExplodeVariant.SEMANTIC)
        assert isinstance(semantic_variant, SemanticVariant)

    def test_variant_factory_detect_variant(self):
        """Test variant detection through factory."""
        with tempfile.TemporaryDirectory() as temp_dir:
            temp_path = Path(temp_dir)

            # Create a numbered directory structure
            (temp_path / "01_intro").mkdir()
            (temp_path / "02_main").mkdir()
            (temp_path / "03_end").mkdir()

            factory = VariantFactory()
            result = factory.detect_variant(temp_path)

            assert result.variant is not None
            # Should detect hierarchical due to numbered directories
            assert result.variant in [ExplodeVariant.HIERARCHICAL, ExplodeVariant.FLAT]

    def test_variant_factory_convenience_functions(self):
        """Test convenience functions."""
        # Test global factory
        factory = get_variant_factory()
        assert isinstance(factory, VariantFactory)

        # Test create_variant convenience function
        variant = create_variant(ExplodeVariant.FLAT)
        assert isinstance(variant, FlatVariant)

    def test_variant_factory_list_available_variants(self):
        """Test listing available variants."""
        factory = VariantFactory()
        variants_info = factory.list_available_variants()

        assert len(variants_info) >= 3

        # Check that required fields are present
        for info in variants_info:
            assert 'type' in info
            assert 'name' in info
            assert 'description' in info
            assert 'detection_patterns' in info

    def test_variant_factory_get_best_variant_for_content(self):
        """Test content-based variant recommendation."""
        factory = VariantFactory()

        # Content with numbered sections (should suggest hierarchical)
        numbered_content = """# 1. Introduction
# 2. Main Content
# 3. Conclusion"""

        result = factory.get_best_variant_for_content(numbered_content)
        assert result in [ExplodeVariant.HIERARCHICAL, ExplodeVariant.FLAT]

        # Content with semantic keywords (should suggest semantic)
        semantic_content = """# Introduction
# Tutorial: Getting Started
# Reference Manual
# Appendix A"""

        result = factory.get_best_variant_for_content(semantic_content)
        assert result in [ExplodeVariant.SEMANTIC, ExplodeVariant.FLAT]


class TestVariantIntegration:
    """Test integration between variants and CLI commands."""

    def test_explode_options_validation(self):
        """Test ExplodeOptions validation."""
        # Valid options
        options = ExplodeOptions(variant=ExplodeVariant.FLAT)
        assert options.variant == ExplodeVariant.FLAT
        assert options.create_manifest is True  # default

        # Custom options
        custom_options = ExplodeOptions(
            variant=ExplodeVariant.HIERARCHICAL,
            max_depth=5,
            create_manifest=False,
            dry_run=True
        )
        assert custom_options.max_depth == 5
        assert custom_options.create_manifest is False
        assert custom_options.dry_run is True

    def test_implode_options_validation(self):
        """Test ImplodeOptions validation."""
        # Default options
        options = ImplodeOptions()
        assert options.preserve_front_matter is True  # default
        assert options.section_spacing == 2  # default

        # Custom options
        custom_options = ImplodeOptions(
            output_file=Path("/tmp/output.md"),
            section_spacing=3,
            dry_run=True
        )
        assert custom_options.output_file == Path("/tmp/output.md")
        assert custom_options.section_spacing == 3
        assert custom_options.dry_run is True

    def test_error_handling(self):
        """Test error handling in variants."""
        variant = FlatVariant()

        # Test with non-existent file
        options = ExplodeOptions(variant=ExplodeVariant.FLAT)
        result = variant.explode(Path("/nonexistent/file.md"), options)

        assert not result.success
        assert len(result.errors) > 0
        assert "does not exist" in result.errors[0].lower()

    def test_manifest_integration(self):
        """Test manifest creation and reading integration."""
        with tempfile.TemporaryDirectory() as temp_dir:
            temp_path = Path(temp_dir)

            # Create test file
            test_content = "# Test\n\nContent here."
            input_file = temp_path / "test.md"
            input_file.write_text(test_content, encoding='utf-8')

            # Test each variant creates a manifest
            for variant_type in [ExplodeVariant.FLAT, ExplodeVariant.HIERARCHICAL, ExplodeVariant.SEMANTIC]:
                variant = create_variant(variant_type)
                options = ExplodeOptions(
                    variant=variant_type,
                    output_dir=temp_path / f"test_{variant_type.value}",
                    create_manifest=True
                )

                result = variant.explode(input_file, options)

                assert result.success
                assert result.manifest_path is not None
                assert result.manifest_path.exists()

                # Verify manifest contains correct variant type
                manifest_content = result.manifest_path.read_text(encoding='utf-8')
                assert f"explosion_type: {variant_type.value}" in manifest_content


if __name__ == '__main__':
    pytest.main([__file__, "-v"])