"""
Tests for Issue #56: Data-driven multiple draft generation

This test module implements comprehensive tests for data-driven draft generation
that creates multiple documents from a schema and data source with field mapping.

Following TDD8 methodology - these tests are written before implementation.
"""

import json
import csv
import pytest
from pathlib import Path
from tempfile import NamedTemporaryFile, TemporaryDirectory
from click.testing import CliRunner

from markitect.cli import cli


class TestIssue56DataDrivenDraftGeneration:
    """Test suite for data-driven multiple draft generation functionality."""

    def setup_method(self):
        """Set up test fixtures."""
        self.runner = CliRunner()

    def test_cli_has_generate_drafts_command(self):
        """Test that CLI has a generate-drafts command for data-driven generation."""
        # Act
        result = self.runner.invoke(cli, ['--help'])

        # Assert
        assert result.exit_code == 0
        assert 'generate-drafts' in result.output, "CLI should have generate-drafts command"

    def test_generate_drafts_command_help(self):
        """Test that generate-drafts command has proper help documentation."""
        # Act
        result = self.runner.invoke(cli, ['generate-drafts', '--help'])

        # Assert
        assert result.exit_code == 0
        help_text = result.output.lower()
        assert 'data source' in help_text
        assert 'schema' in help_text
        assert 'multiple' in help_text or 'batch' in help_text

    def test_generate_drafts_supports_json_data_source(self):
        """Test that generate-drafts supports JSON data sources."""
        # Arrange
        schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "title": "Employee Profile",
            "x-markitect-content-instructions-enabled": True,
            "properties": {
                "headings": {
                    "type": "object",
                    "properties": {
                        "level_1": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "content": {"type": "string"},
                                    "x-markitect-content-instructions": {
                                        "type": "string",
                                        "const": "Employee name: {name}"
                                    },
                                    "x-markitect-field-mapping": {
                                        "type": "string",
                                        "const": "name"
                                    }
                                }
                            },
                            "minItems": 1,
                            "maxItems": 1
                        },
                        "level_2": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "content": {"type": "string"},
                                    "x-markitect-content-instructions": {
                                        "type": "string",
                                        "const": "Role: {role}"
                                    },
                                    "x-markitect-field-mapping": {
                                        "type": "string",
                                        "const": "role"
                                    }
                                }
                            },
                            "minItems": 1,
                            "maxItems": 1
                        }
                    }
                }
            }
        }

        data = [
            {"name": "Alice Johnson", "role": "Software Engineer", "department": "Engineering"},
            {"name": "Bob Smith", "role": "Product Manager", "department": "Product"}
        ]

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as schema_f:
            json.dump(schema, schema_f, indent=2)
            schema_file = Path(schema_f.name)

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as data_f:
            json.dump(data, data_f, indent=2)
            data_file = Path(data_f.name)

        with TemporaryDirectory() as output_dir:
            try:
                # Act
                result = self.runner.invoke(cli, [
                    'generate-drafts',
                    str(schema_file),
                    str(data_file),
                    '--output-dir', output_dir
                ])

                # Assert
                assert result.exit_code == 0, f"Command should succeed, got: {result.output}"

                # Check that multiple files were generated
                output_path = Path(output_dir)
                generated_files = list(output_path.glob('*.md'))
                assert len(generated_files) >= 2, "Should generate multiple draft files"

                # Check content of generated files
                for file in generated_files:
                    content = file.read_text()
                    # Should contain mapped data
                    assert any(name in content for name in ["Alice Johnson", "Bob Smith"])
                    assert any(role in content for role in ["Software Engineer", "Product Manager"])

            finally:
                schema_file.unlink()
                data_file.unlink()

    def test_generate_drafts_supports_csv_data_source(self):
        """Test that generate-drafts supports CSV data sources."""
        # Arrange
        schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "title": "Product Description",
            "x-markitect-content-instructions-enabled": True,
            "properties": {
                "headings": {
                    "type": "object",
                    "properties": {
                        "level_1": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "content": {"type": "string"},
                                    "x-markitect-content-instructions": {
                                        "type": "string",
                                        "const": "Product: {product_name}"
                                    },
                                    "x-markitect-field-mapping": {
                                        "type": "string",
                                        "const": "product_name"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as schema_f:
            json.dump(schema, schema_f, indent=2)
            schema_file = Path(schema_f.name)

        with NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as csv_f:
            writer = csv.writer(csv_f)
            writer.writerow(['product_name', 'price', 'category'])
            writer.writerow(['Laptop Pro', '1299.99', 'Electronics'])
            writer.writerow(['Office Chair', '249.99', 'Furniture'])
            csv_file = Path(csv_f.name)

        with TemporaryDirectory() as output_dir:
            try:
                # Act
                result = self.runner.invoke(cli, [
                    'generate-drafts',
                    str(schema_file),
                    str(csv_file),
                    '--output-dir', output_dir
                ])

                # Assert
                assert result.exit_code == 0, f"CSV processing should work, got: {result.output}"

                # Check generated files
                output_path = Path(output_dir)
                generated_files = list(output_path.glob('*.md'))
                assert len(generated_files) >= 2, "Should generate files for each CSV row"

                # Check content contains mapped CSV data
                all_content = ""
                for file in generated_files:
                    all_content += file.read_text()

                assert "Laptop Pro" in all_content
                assert "Office Chair" in all_content

            finally:
                schema_file.unlink()
                csv_file.unlink()

    def test_generate_drafts_field_mapping_functionality(self):
        """Test that field mapping works correctly between data and schema."""
        # Arrange
        schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "title": "Blog Post",
            "x-markitect-content-instructions-enabled": True,
            "properties": {
                "headings": {
                    "type": "object",
                    "properties": {
                        "level_1": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "content": {"type": "string"},
                                    "x-markitect-content-instructions": {
                                        "type": "string",
                                        "const": "{title}"
                                    },
                                    "x-markitect-field-mapping": {
                                        "type": "string",
                                        "const": "title"
                                    }
                                }
                            }
                        },
                        "level_2": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "content": {"type": "string"},
                                    "x-markitect-content-instructions": {
                                        "type": "string",
                                        "const": "Author: {author_name}"
                                    },
                                    "x-markitect-field-mapping": {
                                        "type": "string",
                                        "const": "author_name"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        data = [
            {"title": "Getting Started with Python", "author_name": "Jane Doe", "tags": ["python", "beginner"]},
            {"title": "Advanced JavaScript Patterns", "author_name": "John Smith", "tags": ["javascript", "advanced"]}
        ]

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as schema_f:
            json.dump(schema, schema_f, indent=2)
            schema_file = Path(schema_f.name)

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as data_f:
            json.dump(data, data_f, indent=2)
            data_file = Path(data_f.name)

        with TemporaryDirectory() as output_dir:
            try:
                # Act
                result = self.runner.invoke(cli, [
                    'generate-drafts',
                    str(schema_file),
                    str(data_file),
                    '--output-dir', output_dir
                ])

                # Assert
                assert result.exit_code == 0

                # Verify field mapping worked correctly
                generated_files = list(Path(output_dir).glob('*.md'))
                assert len(generated_files) == 2

                contents = [file.read_text() for file in generated_files]

                # Check that titles and authors are properly mapped
                assert any("Getting Started with Python" in content for content in contents)
                assert any("Advanced JavaScript Patterns" in content for content in contents)
                assert any("Author: Jane Doe" in content for content in contents)
                assert any("Author: John Smith" in content for content in contents)

            finally:
                schema_file.unlink()
                data_file.unlink()

    def test_generate_drafts_maintains_schema_references(self):
        """Test that generated drafts maintain schema references for validation."""
        # Arrange
        schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "title": "Meeting Notes",
            "x-markitect-content-instructions-enabled": True,
            "properties": {
                "headings": {
                    "type": "object",
                    "properties": {
                        "level_1": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "content": {"type": "string"},
                                    "x-markitect-content-instructions": {
                                        "type": "string",
                                        "const": "Meeting: {meeting_title}"
                                    },
                                    "x-markitect-field-mapping": {
                                        "type": "string",
                                        "const": "meeting_title"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        data = [{"meeting_title": "Weekly Standup", "date": "2024-01-15"}]

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as schema_f:
            json.dump(schema, schema_f, indent=2)
            schema_file = Path(schema_f.name)

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as data_f:
            json.dump(data, data_f, indent=2)
            data_file = Path(data_f.name)

        with TemporaryDirectory() as output_dir:
            try:
                # Act
                result = self.runner.invoke(cli, [
                    'generate-drafts',
                    str(schema_file),
                    str(data_file),
                    '--output-dir', output_dir
                ])

                # Assert
                assert result.exit_code == 0

                # Check schema reference is maintained
                generated_files = list(Path(output_dir).glob('*.md'))
                assert len(generated_files) >= 1

                for file in generated_files:
                    content = file.read_text()
                    assert f"Generated from schema: {schema_file}" in content

            finally:
                schema_file.unlink()
                data_file.unlink()

    def test_generate_drafts_output_directory_specification(self):
        """Test that CLI supports output directory specification for batch generation."""
        # Arrange
        schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "title": "Test Document",
            "x-markitect-content-instructions-enabled": True,
            "properties": {
                "headings": {
                    "type": "object",
                    "properties": {
                        "level_1": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "content": {"type": "string"},
                                    "x-markitect-content-instructions": {
                                        "type": "string",
                                        "const": "{name}"
                                    },
                                    "x-markitect-field-mapping": {
                                        "type": "string",
                                        "const": "name"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        data = [{"name": "Test1"}, {"name": "Test2"}]

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as schema_f:
            json.dump(schema, schema_f, indent=2)
            schema_file = Path(schema_f.name)

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as data_f:
            json.dump(data, data_f, indent=2)
            data_file = Path(data_f.name)

        with TemporaryDirectory() as temp_dir:
            output_dir = Path(temp_dir) / "custom_output"

            try:
                # Act
                result = self.runner.invoke(cli, [
                    'generate-drafts',
                    str(schema_file),
                    str(data_file),
                    '--output-dir', str(output_dir)
                ])

                # Assert
                assert result.exit_code == 0
                assert output_dir.exists(), "Output directory should be created"

                generated_files = list(output_dir.glob('*.md'))
                assert len(generated_files) >= 2, "Should generate files in specified directory"

            finally:
                schema_file.unlink()
                data_file.unlink()

    def test_generate_drafts_data_validation_compatibility(self):
        """Test that data validation ensures compatibility with schema requirements."""
        # Arrange - Schema requires specific fields
        schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "title": "Validated Document",
            "x-markitect-content-instructions-enabled": True,
            "properties": {
                "headings": {
                    "type": "object",
                    "properties": {
                        "level_1": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "content": {"type": "string"},
                                    "x-markitect-content-instructions": {
                                        "type": "string",
                                        "const": "Required field: {required_field}"
                                    },
                                    "x-markitect-field-mapping": {
                                        "type": "string",
                                        "const": "required_field"
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "x-markitect-required-fields": ["required_field"]
        }

        # Data missing required field
        invalid_data = [{"optional_field": "value"}]

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as schema_f:
            json.dump(schema, schema_f, indent=2)
            schema_file = Path(schema_f.name)

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as data_f:
            json.dump(invalid_data, data_f, indent=2)
            data_file = Path(data_f.name)

        with TemporaryDirectory() as output_dir:
            try:
                # Act
                result = self.runner.invoke(cli, [
                    'generate-drafts',
                    str(schema_file),
                    str(data_file),
                    '--output-dir', output_dir
                ])

                # Assert - Should fail validation or provide warning
                # Could be exit code != 0 or warning in output
                assert result.exit_code != 0 or "warning" in result.output.lower() or "missing" in result.output.lower()

            finally:
                schema_file.unlink()
                data_file.unlink()

    def test_generate_drafts_error_handling_data_schema_mismatch(self):
        """Test error handling for data-schema mismatches."""
        # Arrange
        schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "title": "Test Schema",
            "x-markitect-content-instructions-enabled": True,
            "properties": {
                "headings": {
                    "type": "object",
                    "properties": {
                        "level_1": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "content": {"type": "string"},
                                    "x-markitect-field-mapping": {
                                        "type": "string",
                                        "const": "name"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        # Data with different field names
        mismatched_data = [{"different_field": "value"}]

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as schema_f:
            json.dump(schema, schema_f, indent=2)
            schema_file = Path(schema_f.name)

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as data_f:
            json.dump(mismatched_data, data_f, indent=2)
            data_file = Path(data_f.name)

        with TemporaryDirectory() as output_dir:
            try:
                # Act
                result = self.runner.invoke(cli, [
                    'generate-drafts',
                    str(schema_file),
                    str(data_file),
                    '--output-dir', output_dir
                ])

                # Assert - Should handle mismatch gracefully
                # Either succeed with warnings or fail with clear error
                if result.exit_code != 0:
                    assert len(result.output) > 0  # Should have error message
                else:
                    # If succeeded, should have warnings or default handling
                    assert "warning" in result.output.lower() or len(list(Path(output_dir).glob('*.md'))) > 0

            finally:
                schema_file.unlink()
                data_file.unlink()

    def test_generate_drafts_file_naming_convention(self):
        """Test that generated files follow a consistent naming convention."""
        # Arrange
        schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "title": "Item Description",
            "x-markitect-content-instructions-enabled": True,
            "properties": {
                "headings": {
                    "type": "object",
                    "properties": {
                        "level_1": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "content": {"type": "string"},
                                    "x-markitect-content-instructions": {
                                        "type": "string",
                                        "const": "Item: {id}"
                                    },
                                    "x-markitect-field-mapping": {
                                        "type": "string",
                                        "const": "id"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        data = [
            {"id": "item-001", "name": "First Item"},
            {"id": "item-002", "name": "Second Item"}
        ]

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as schema_f:
            json.dump(schema, schema_f, indent=2)
            schema_file = Path(schema_f.name)

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as data_f:
            json.dump(data, data_f, indent=2)
            data_file = Path(data_f.name)

        with TemporaryDirectory() as output_dir:
            try:
                # Act
                result = self.runner.invoke(cli, [
                    'generate-drafts',
                    str(schema_file),
                    str(data_file),
                    '--output-dir', output_dir
                ])

                # Assert
                assert result.exit_code == 0

                generated_files = list(Path(output_dir).glob('*.md'))
                assert len(generated_files) == 2

                # Check naming convention
                filenames = [f.name for f in generated_files]
                for filename in filenames:
                    assert filename.endswith('.md')
                    # Should contain identifier or be sequentially named
                    assert len(filename) > 3  # At least "x.md"

            finally:
                schema_file.unlink()
                data_file.unlink()

    def test_generate_drafts_integration_with_existing_stub_generation(self):
        """Test that generate-drafts integrates properly with existing stub generation from Issue #55."""
        # Arrange - Use schema that works with single draft generation
        schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "title": "Integration Test",
            "x-markitect-content-instructions-enabled": True,
            "properties": {
                "headings": {
                    "type": "object",
                    "properties": {
                        "level_1": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "content": {"type": "string"},
                                    "x-markitect-content-instructions": {
                                        "type": "string",
                                        "const": "Title: {title}"
                                    },
                                    "x-markitect-field-mapping": {
                                        "type": "string",
                                        "const": "title"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        data = [{"title": "Test Document"}]

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as schema_f:
            json.dump(schema, schema_f, indent=2)
            schema_file = Path(schema_f.name)

        with NamedTemporaryFile(mode='w', suffix='.json', delete=False) as data_f:
            json.dump(data, data_f, indent=2)
            data_file = Path(data_f.name)

        with NamedTemporaryFile(mode='w', suffix='.md', delete=False) as single_output_f:
            single_output_file = Path(single_output_f.name)

        with TemporaryDirectory() as batch_output_dir:
            try:
                # Act - Test both single and batch generation
                single_result = self.runner.invoke(cli, [
                    'generate-stub',
                    str(schema_file),
                    '--output', str(single_output_file)
                ])

                batch_result = self.runner.invoke(cli, [
                    'generate-drafts',
                    str(schema_file),
                    str(data_file),
                    '--output-dir', batch_output_dir
                ])

                # Assert
                assert single_result.exit_code == 0
                assert batch_result.exit_code == 0

                # Check single output
                single_content = single_output_file.read_text()
                assert "Integration Test" in single_content

                # Check batch output
                batch_files = list(Path(batch_output_dir).glob('*.md'))
                assert len(batch_files) >= 1

                batch_content = batch_files[0].read_text()
                assert "Test Document" in batch_content

                # Both should have schema references
                assert "Generated from schema:" in single_content
                assert "Generated from schema:" in batch_content

            finally:
                schema_file.unlink()
                data_file.unlink()
                if single_output_file.exists():
                    single_output_file.unlink()