"""
Test end-to-end scenarios for Issue #139: Implode directory to a markdown file.

This test module covers comprehensive end-to-end testing including round-trip
testing with md-explode, processing of complex structures, and validation scenarios.
"""

import pytest
import tempfile
import shutil
import subprocess
from pathlib import Path
from unittest.mock import Mock, patch

# Import will fail initially (RED phase) until implementation exists
try:
    from markitect.plugins.builtin.markdown_commands import (
        explode_markdown_file,
        implode_directory,
        cli_implode_directory
    )
    from markitect.cli import cli
except ImportError:
    # Expected during RED phase - tests should fail initially
    explode_markdown_file = None
    implode_directory = None
    cli_implode_directory = None
    cli = None

# Note: cli_explode_markdown doesn't exist, we use explode_markdown_file directly
def cli_explode_markdown(input_file, output_dir):
    """Wrapper for explode_markdown_file for testing."""
    class MockResult:
        def __init__(self, success, output_dir=None):
            self.success = success
            self.output_dir = output_dir
    try:
        result_dir = explode_markdown_file(input_file, output_dir)
        return MockResult(True, result_dir)
    except Exception:
        return MockResult(False)


class TestEndToEndRoundTripTesting:
    """Test complete round-trip scenarios: original → explode → implode → compare."""

    def setup_method(self):
        """Set up temporary directory for each test."""
        self.temp_dir = Path(tempfile.mkdtemp())

    def teardown_method(self):
        """Clean up temporary directory after each test."""
        if self.temp_dir.exists():
            shutil.rmtree(self.temp_dir)

    def test_simple_document_round_trip(self):
        """Test round-trip with simple hierarchical document."""
        # This should fail initially (RED phase)

        original_content = """# Introduction
Welcome to the document.

## Chapter 1: Getting Started
This is the first chapter.

### Section 1.1: Installation
Install instructions here.

### Section 1.2: Configuration
Configuration details.

## Chapter 2: Advanced Topics
Advanced material here.

# Conclusion
Final thoughts.
"""

        # Create original file
        original_file = self.temp_dir / "original.md"
        original_file.write_text(original_content)

        # Step 1: Explode the document
        exploded_dir = self.temp_dir / "exploded"
        explode_result = cli_explode_markdown(
            input_file=original_file,
            output_dir=exploded_dir
        )
        assert explode_result.success == True

        # Step 2: Implode back to markdown
        imploded_file = self.temp_dir / "imploded.md"
        implode_result = cli_implode_directory(
            input_dir=exploded_dir,
            output_file=imploded_file
        )
        assert implode_result.success == True

        # Step 3: Compare results
        imploded_content = imploded_file.read_text()

        # Should preserve all major structural elements
        assert "# Introduction" in imploded_content
        assert "## Chapter 1: Getting Started" in imploded_content
        assert "### Section 1.1: Installation" in imploded_content
        assert "### Section 1.2: Configuration" in imploded_content
        assert "## Chapter 2: Advanced Topics" in imploded_content
        assert "# Conclusion" in imploded_content

        # Should preserve content
        assert "Welcome to the document." in imploded_content
        assert "Install instructions here." in imploded_content
        assert "Final thoughts." in imploded_content

    def test_document_with_front_matter_round_trip(self):
        """Test round-trip preservation of YAML front matter."""
        # This should fail initially (RED phase)

        original_content = """---
title: "Test Document"
author: "Test Author"
date: "2023-01-01"
tags: ["documentation", "test"]
---

# Main Content
Document content here.

## Section 1
Section content.
"""

        original_file = self.temp_dir / "with_frontmatter.md"
        original_file.write_text(original_content)

        # Explode → Implode
        exploded_dir = self.temp_dir / "exploded_fm"
        explode_result = cli_explode_markdown(original_file, exploded_dir)
        assert explode_result.success == True

        imploded_file = self.temp_dir / "imploded_fm.md"
        implode_result = cli_implode_directory(exploded_dir, imploded_file)
        assert implode_result.success == True

        imploded_content = imploded_file.read_text()

        # Should preserve front matter
        assert imploded_content.startswith("---")
        assert "title: \"Test Document\"" in imploded_content
        assert "author: \"Test Author\"" in imploded_content
        assert "tags:" in imploded_content

        # Should preserve content structure
        assert "# Main Content" in imploded_content
        assert "## Section 1" in imploded_content

    def test_complex_nested_structure_round_trip(self):
        """Test round-trip with deeply nested document structure."""
        # This should fail initially (RED phase)

        complex_content = """# Part 1: Fundamentals

Introduction to part 1.

## Chapter 1: Basics

Basic concepts.

### Section 1.1: Overview
Overview content.

#### Subsection 1.1.1: Details
Detailed information.

#### Subsection 1.1.2: Examples
Example content.

### Section 1.2: Implementation
Implementation details.

## Chapter 2: Intermediate

Intermediate concepts.

# Part 2: Advanced Topics

Advanced material.

## Chapter 3: Expert Level

Expert content here.
"""

        original_file = self.temp_dir / "complex.md"
        original_file.write_text(complex_content)

        # Round-trip process
        exploded_dir = self.temp_dir / "complex_exploded"
        explode_result = cli_explode_markdown(original_file, exploded_dir)
        assert explode_result.success == True

        imploded_file = self.temp_dir / "complex_imploded.md"
        implode_result = cli_implode_directory(exploded_dir, imploded_file)
        assert implode_result.success == True

        imploded_content = imploded_file.read_text()

        # Should preserve all heading levels
        assert "# Part 1: Fundamentals" in imploded_content
        assert "## Chapter 1: Basics" in imploded_content
        assert "### Section 1.1: Overview" in imploded_content
        assert "#### Subsection 1.1.1: Details" in imploded_content
        assert "#### Subsection 1.1.2: Examples" in imploded_content
        assert "# Part 2: Advanced Topics" in imploded_content

    def test_round_trip_preserves_markdown_formatting(self):
        """Test that round-trip preserves all markdown formatting elements."""
        # This should fail initially (RED phase)

        formatted_content = """# Document with Formatting

## Text Formatting
This has **bold text** and *italic text* and `inline code`.

## Code Blocks
Here's a code block:

```python
def example():
    return "formatted code"
```

## Lists and Tables
- Item 1
- Item 2
  - Nested item

| Header 1 | Header 2 |
|----------|----------|
| Cell 1   | Cell 2   |

## Links and Images
[Link text](http://example.com)
![Alt text](image.png)

> This is a blockquote

---

Horizontal rule above.
"""

        original_file = self.temp_dir / "formatted.md"
        original_file.write_text(formatted_content)

        # Round-trip
        exploded_dir = self.temp_dir / "formatted_exploded"
        explode_result = cli_explode_markdown(original_file, exploded_dir)
        assert explode_result.success == True

        imploded_file = self.temp_dir / "formatted_imploded.md"
        implode_result = cli_implode_directory(exploded_dir, imploded_file)
        assert implode_result.success == True

        imploded_content = imploded_file.read_text()

        # Should preserve all formatting
        assert "**bold text**" in imploded_content
        assert "*italic text*" in imploded_content
        assert "`inline code`" in imploded_content
        assert "```python" in imploded_content
        assert "- Item 1" in imploded_content
        assert "| Header 1 | Header 2 |" in imploded_content
        assert "[Link text]" in imploded_content
        assert "![Alt text]" in imploded_content
        assert "> This is a blockquote" in imploded_content
        assert "---" in imploded_content


class TestBookLikeStructureProcessing:
    """Test processing book-like structures with parts, chapters, and sections."""

    def setup_method(self):
        """Set up temporary directory for each test."""
        self.temp_dir = Path(tempfile.mkdtemp())

    def teardown_method(self):
        """Clean up temporary directory after each test."""
        if self.temp_dir.exists():
            shutil.rmtree(self.temp_dir)

    def test_process_book_structure_from_explode_output(self):
        """Test processing a book-like directory structure created by md-explode."""
        # This should fail initially (RED phase)

        # Simulate structure created by md-explode for a book
        self._create_book_structure()

        # Implode the structure
        imploded_file = self.temp_dir / "reconstructed_book.md"
        result = cli_implode_directory(
            input_dir=self.temp_dir,
            output_file=imploded_file
        )

        assert result.success == True

        content = imploded_file.read_text()

        # Should reconstruct proper book hierarchy
        assert "# Part 1: Introduction" in content
        assert "## Chapter 1: Getting Started" in content
        assert "### Section 1.1: Installation" in content
        assert "### Section 1.2: Setup" in content
        assert "## Chapter 2: Basic Concepts" in content
        assert "# Part 2: Advanced Topics" in content
        assert "## Chapter 3: Expert Techniques" in content

    def test_handle_book_with_mixed_content_types(self):
        """Test handling books with various content types (code, tables, images)."""
        # This should fail initially (RED phase)

        # Create structure with mixed content
        self._create_mixed_content_book_structure()

        imploded_file = self.temp_dir / "mixed_content_book.md"
        result = cli_implode_directory(self.temp_dir, imploded_file)

        assert result.success == True

        content = imploded_file.read_text()

        # Should preserve all content types
        assert "```python" in content
        assert "| Feature | Description |" in content
        assert "![Architecture](diagram.png)" in content
        assert "1. First step" in content

    def _create_book_structure(self):
        """Create a realistic book directory structure."""
        # Part 1
        part1_dir = self.temp_dir / "part_1_introduction"
        part1_dir.mkdir()
        (part1_dir / "index.md").write_text("# Part 1: Introduction\nIntroduction to the book.")

        # Chapter 1
        ch1_dir = part1_dir / "chapter_1_getting_started"
        ch1_dir.mkdir()
        (ch1_dir / "index.md").write_text("## Chapter 1: Getting Started\nGetting started content.")
        (ch1_dir / "section_11_installation.md").write_text("### Section 1.1: Installation\nInstallation instructions.")
        (ch1_dir / "section_12_setup.md").write_text("### Section 1.2: Setup\nSetup procedures.")

        # Chapter 2
        ch2_dir = part1_dir / "chapter_2_basic_concepts"
        ch2_dir.mkdir()
        (ch2_dir / "index.md").write_text("## Chapter 2: Basic Concepts\nBasic concepts explanation.")

        # Part 2
        part2_dir = self.temp_dir / "part_2_advanced_topics"
        part2_dir.mkdir()
        (part2_dir / "index.md").write_text("# Part 2: Advanced Topics\nAdvanced topics introduction.")
        (part2_dir / "chapter_3_expert_techniques.md").write_text("## Chapter 3: Expert Techniques\nExpert level content.")

    def _create_mixed_content_book_structure(self):
        """Create book structure with mixed content types."""
        tech_dir = self.temp_dir / "technical_guide"
        tech_dir.mkdir()
        (tech_dir / "index.md").write_text("# Technical Guide\nGuide introduction.")

        # Code examples chapter
        code_dir = tech_dir / "chapter_1_code_examples"
        code_dir.mkdir()
        code_content = """## Chapter 1: Code Examples

Example implementation:

```python
def process_data(data):
    return data.strip().lower()
```

And configuration:

```yaml
settings:
  debug: true
  port: 8080
```
"""
        (code_dir / "index.md").write_text(code_content)

        # Tables and data chapter
        data_dir = tech_dir / "chapter_2_data_reference"
        data_dir.mkdir()
        data_content = """## Chapter 2: Data Reference

| Feature | Description | Available |
|---------|-------------|-----------|
| API     | REST API    | Yes       |
| CLI     | Command Line| Yes       |
| Web UI  | Web Interface| No      |

### Steps to follow:
1. First step
2. Second step
   - Sub-step A
   - Sub-step B
"""
        (data_dir / "index.md").write_text(data_content)

        # Images and media chapter
        media_content = """## Chapter 3: Architecture

System overview:

![Architecture](diagram.png)

> Note: The diagram shows the complete system architecture.

For more details, see [documentation](https://example.com).
"""
        (tech_dir / "chapter_3_architecture.md").write_text(media_content)


class TestTechnicalDocumentationProcessing:
    """Test processing technical documentation with deep nesting."""

    def setup_method(self):
        """Set up temporary directory for each test."""
        self.temp_dir = Path(tempfile.mkdtemp())

    def teardown_method(self):
        """Clean up temporary directory after each test."""
        if self.temp_dir.exists():
            shutil.rmtree(self.temp_dir)

    def test_process_api_documentation_structure(self):
        """Test processing API documentation with deep hierarchical structure."""
        # This should fail initially (RED phase)

        self._create_api_documentation_structure()

        imploded_file = self.temp_dir / "api_docs.md"
        result = cli_implode_directory(self.temp_dir, imploded_file)

        assert result.success == True

        content = imploded_file.read_text()

        # Should maintain API documentation structure
        assert "# API Documentation" in content
        assert "## Authentication" in content
        assert "### OAuth2 Flow" in content
        assert "#### Token Validation" in content
        assert "## Endpoints" in content
        assert "### Users API" in content

    def test_handle_very_deep_nesting(self):
        """Test handling documentation with very deep nesting levels."""
        # This should fail initially (RED phase)

        self._create_deep_nested_structure()

        imploded_file = self.temp_dir / "deep_nested.md"
        result = cli_implode_directory(self.temp_dir, imploded_file)

        assert result.success == True

        content = imploded_file.read_text()

        # Should handle deep nesting appropriately
        assert "# Level 1" in content
        assert "## Level 2" in content
        assert "### Level 3" in content
        assert "#### Level 4" in content
        assert "##### Level 5" in content

    def _create_api_documentation_structure(self):
        """Create realistic API documentation structure."""
        api_dir = self.temp_dir / "api_documentation"
        api_dir.mkdir()
        (api_dir / "index.md").write_text("# API Documentation\nComplete API reference.")

        # Authentication section
        auth_dir = api_dir / "authentication"
        auth_dir.mkdir()
        (auth_dir / "index.md").write_text("## Authentication\nAuthentication overview.")

        oauth_dir = auth_dir / "oauth2_flow"
        oauth_dir.mkdir()
        (oauth_dir / "index.md").write_text("### OAuth2 Flow\nOAuth2 implementation details.")
        (oauth_dir / "token_validation.md").write_text("#### Token Validation\nHow to validate tokens.")

        # Endpoints section
        endpoints_dir = api_dir / "endpoints"
        endpoints_dir.mkdir()
        (endpoints_dir / "index.md").write_text("## Endpoints\nAPI endpoints reference.")
        (endpoints_dir / "users_api.md").write_text("### Users API\nUser management endpoints.")

    def _create_deep_nested_structure(self):
        """Create structure with very deep nesting."""
        current_dir = self.temp_dir
        content_parts = []

        for level in range(1, 6):
            dir_name = f"level_{level}"
            current_dir = current_dir / dir_name
            current_dir.mkdir(parents=True, exist_ok=True)

            heading = "#" * level
            content = f"{heading} Level {level}\nContent for level {level}."
            (current_dir / "index.md").write_text(content)


class TestValidationAndErrorScenarios:
    """Test validation scenarios and error handling in end-to-end workflows."""

    def setup_method(self):
        """Set up temporary directory for each test."""
        self.temp_dir = Path(tempfile.mkdtemp())

    def teardown_method(self):
        """Clean up temporary directory after each test."""
        if self.temp_dir.exists():
            shutil.rmtree(self.temp_dir)

    def test_validate_against_md_explode_output(self):
        """Test that implode works correctly with actual md-explode output."""
        # This should fail initially (RED phase)

        # Create original document
        original_content = """# User Guide

## Getting Started
Start here.

### Installation
Install steps.

## Advanced Usage
Advanced topics.
"""

        original_file = self.temp_dir / "user_guide.md"
        original_file.write_text(original_content)

        # Use actual md-explode command
        exploded_dir = self.temp_dir / "user_guide_exploded"

        explode_result = cli_explode_markdown(original_file, exploded_dir)
        assert explode_result.success == True

        # Verify exploded structure exists
        assert exploded_dir.exists()
        assert (exploded_dir / "user_guide" / "getting_started").exists()

        # Now implode it back
        imploded_file = self.temp_dir / "reconstructed.md"
        implode_result = cli_implode_directory(exploded_dir, imploded_file)

        assert implode_result.success == True

        # Validate result
        reconstructed = imploded_file.read_text()
        assert "# User Guide" in reconstructed
        assert "## Getting Started" in reconstructed
        assert "### Installation" in reconstructed

    def test_handle_malformed_directory_structures(self):
        """Test handling malformed or incomplete directory structures."""
        # This should fail initially (RED phase)

        # Create malformed structure (missing index files, irregular naming)
        malformed_dir = self.temp_dir / "malformed"
        malformed_dir.mkdir()

        # Regular file at root
        (malformed_dir / "introduction.md").write_text("# Introduction\nIntro content")

        # Directory with no index file
        orphan_dir = malformed_dir / "orphan_section"
        orphan_dir.mkdir()
        (orphan_dir / "content.md").write_text("Content without proper heading structure")

        # Directory with mixed conventions
        mixed_dir = malformed_dir / "mixed_conventions"
        mixed_dir.mkdir()
        (mixed_dir / "index.md").write_text("## Mixed Section\nSection content")
        (mixed_dir / "irregular_file_name.md").write_text("Some content")

        # Should handle gracefully
        imploded_file = self.temp_dir / "malformed_result.md"
        result = cli_implode_directory(malformed_dir, imploded_file)

        # Should either succeed with best-effort result or fail gracefully
        if result.success:
            content = imploded_file.read_text()
            assert len(content) > 0
        else:
            assert result.error_message is not None

    def test_handle_empty_and_edge_case_directories(self):
        """Test handling empty directories and edge cases."""
        # This should fail initially (RED phase)

        # Completely empty directory
        empty_dir = self.temp_dir / "empty"
        empty_dir.mkdir()

        result = cli_implode_directory(empty_dir, self.temp_dir / "empty_result.md")

        # Should handle empty directory appropriately
        assert result.success == False or (result.success == True and result.warning is not None)

        # Directory with only non-markdown files
        non_md_dir = self.temp_dir / "non_markdown"
        non_md_dir.mkdir()
        (non_md_dir / "readme.txt").write_text("Not markdown")
        (non_md_dir / "data.json").write_text("{}")

        result = cli_implode_directory(non_md_dir, self.temp_dir / "non_md_result.md")

        # Should handle appropriately
        assert result.success == False or result.warning is not None