"""
Test for Issue #65: Template Engine Foundation - Variable Substitution

This test module validates the template variable substitution functionality
for the MarkiTect template engine, implementing TDD8 Cycle 2.

Tests focus on:
- Basic variable substitution with data
- Nested object access with dot notation
- Missing variable handling (strict vs lenient modes)
- Error handling and validation
"""

import pytest
from typing import Dict, Any


class TestTemplateVariableSubstitution:
    """Test suite for template variable substitution functionality."""

    def setup_method(self):
        """Set up test environment for each test."""
        # Import the template engine (will be implemented)
        try:
            from markitect.template.engine import TemplateEngine
            self.engine = TemplateEngine()
        except ImportError:
            self.engine = None

    def test_substitute_simple_variables(self):
        """Test basic variable substitution from template strings.

        Reference: Issue #65 - Template Engine Foundation
        TDD Phase: RED (test should fail initially)
        """
        # Arrange
        template_text = "Hello {{name}}!"
        data = {"name": "Alice"}
        expected_result = "Hello Alice!"

        # Act & Assert
        if self.engine is None:
            pytest.skip("TemplateEngine not implemented yet - TDD RED phase")

        result = self.engine.render(template_text, data)
        assert result == expected_result

    def test_substitute_nested_variables(self):
        """Test nested object variable substitution with dot notation.

        Reference: Issue #65 - Template Engine Foundation
        TDD Phase: RED (test should fail initially)
        """
        # Arrange
        template_text = "Customer: {{customer.name}}, Email: {{customer.contact.email}}"
        data = {
            "customer": {
                "name": "Acme Corp",
                "contact": {
                    "email": "info@acme.example"
                }
            }
        }
        expected_result = "Customer: Acme Corp, Email: info@acme.example"

        # Act & Assert
        if self.engine is None:
            pytest.skip("TemplateEngine not implemented yet - TDD RED phase")

        result = self.engine.render(template_text, data)
        assert result == expected_result

    def test_substitute_multiple_variables(self):
        """Test substitution of multiple variables in same template.

        Reference: Issue #65 - Template Engine Foundation
        """
        # Arrange
        template_text = "Invoice {{invoice_number}} for {{customer.name}} - Total: {{total}} {{currency}}"
        data = {
            "invoice_number": "INV-2025-001",
            "customer": {"name": "Acme Corp"},
            "total": 1500.00,
            "currency": "EUR"
        }
        expected_result = "Invoice INV-2025-001 for Acme Corp - Total: 1500.0 EUR"

        # Act & Assert
        if self.engine is None:
            pytest.skip("TemplateEngine not implemented yet - TDD RED phase")

        result = self.engine.render(template_text, data)
        assert result == expected_result

    def test_substitute_missing_variable_strict_mode(self):
        """Test handling of missing variables in strict mode (should raise error).

        Reference: Issue #65 - Template Engine Foundation
        """
        # Arrange
        template_text = "Hello {{name}}, welcome to {{missing}}!"
        data = {"name": "Alice"}

        # Act & Assert
        if self.engine is None:
            pytest.skip("TemplateEngine not implemented yet - TDD RED phase")

        # Strict mode should raise an exception for missing variables
        with pytest.raises(Exception) as exc_info:
            self.engine.render(template_text, data, strict=True)

        assert "missing" in str(exc_info.value).lower()

    def test_substitute_missing_variable_lenient_mode(self):
        """Test handling of missing variables in lenient mode (preserve placeholder).

        Reference: Issue #65 - Template Engine Foundation
        """
        # Arrange
        template_text = "Hello {{name}}, welcome to {{missing}}!"
        data = {"name": "Alice"}
        expected_result = "Hello Alice, welcome to {{missing}}!"

        # Act & Assert
        if self.engine is None:
            pytest.skip("TemplateEngine not implemented yet - TDD RED phase")

        result = self.engine.render(template_text, data, strict=False)
        assert result == expected_result

    def test_substitute_empty_template(self):
        """Test substitution with template containing no variables.

        Reference: Issue #65 - Template Engine Foundation
        """
        # Arrange
        template_text = "This is a regular markdown document with no variables."
        data = {"name": "Alice"}
        expected_result = template_text  # Should remain unchanged

        # Act & Assert
        if self.engine is None:
            pytest.skip("TemplateEngine not implemented yet - TDD RED phase")

        result = self.engine.render(template_text, data)
        assert result == expected_result

    def test_substitute_with_markdown_formatting(self):
        """Test that markdown formatting is preserved during substitution.

        Reference: Issue #65 - Template Engine Foundation
        """
        # Arrange
        template_text = """---
title: "Invoice {{invoice_number}}"
---

# Invoice {{invoice_number}}

**Bill To**: {{customer.name}}
*Email*: {{customer.email}}

## Summary
- Total: {{total}}
- Currency: {{currency}}
"""
        data = {
            "invoice_number": "INV-2025-001",
            "customer": {
                "name": "Acme Corp",
                "email": "billing@acme.example"
            },
            "total": 1500.00,
            "currency": "EUR"
        }

        # Act & Assert
        if self.engine is None:
            pytest.skip("TemplateEngine not implemented yet - TDD RED phase")

        result = self.engine.render(template_text, data)

        # Check that markdown structure is preserved
        assert "---" in result  # Frontmatter delimiters
        assert "# Invoice INV-2025-001" in result  # Header with substituted value
        assert "**Bill To**: Acme Corp" in result  # Bold formatting preserved
        assert "*Email*: billing@acme.example" in result  # Italic formatting preserved
        assert "- Total: 1500.0" in result  # List formatting preserved

    def test_substitute_duplicate_variables(self):
        """Test that duplicate variables are all substituted correctly.

        Reference: Issue #65 - Template Engine Foundation
        """
        # Arrange
        template_text = "{{name}} says hello to {{name}} and {{company}}"
        data = {"name": "Alice", "company": "Acme Corp"}
        expected_result = "Alice says hello to Alice and Acme Corp"

        # Act & Assert
        if self.engine is None:
            pytest.skip("TemplateEngine not implemented yet - TDD RED phase")

        result = self.engine.render(template_text, data)
        assert result == expected_result

    def test_substitute_with_special_characters(self):
        """Test substitution with special characters and unicode.

        Reference: Issue #65 - Template Engine Foundation
        """
        # Arrange
        template_text = "Grüße {{name}}, Café {{café.price}} €"
        data = {
            "name": "München",
            "café": {"price": "3.50"}
        }
        expected_result = "Grüße München, Café 3.50 €"

        # Act & Assert
        if self.engine is None:
            pytest.skip("TemplateEngine not implemented yet - TDD RED phase")

        result = self.engine.render(template_text, data)
        assert result == expected_result


class TestTemplateSubstitutionEdgeCases:
    """Test edge cases and error conditions for template substitution."""

    def setup_method(self):
        """Set up test environment."""
        try:
            from markitect.template.engine import TemplateEngine
            self.engine = TemplateEngine()
        except ImportError:
            self.engine = None

    def test_substitute_deeply_nested_objects(self):
        """Test substitution with deeply nested object access.

        Reference: Issue #65 - Template Engine Foundation
        """
        # Arrange
        template_text = "{{level1.level2.level3.level4.value}}"
        data = {
            "level1": {
                "level2": {
                    "level3": {
                        "level4": {
                            "value": "deep_value"
                        }
                    }
                }
            }
        }
        expected_result = "deep_value"

        # Act & Assert
        if self.engine is None:
            pytest.skip("TemplateEngine not implemented yet - TDD RED phase")

        result = self.engine.render(template_text, data)
        assert result == expected_result

    def test_substitute_with_none_values(self):
        """Test substitution when data contains None values.

        Reference: Issue #65 - Template Engine Foundation
        """
        # Arrange
        template_text = "Value: {{value}}, None: {{none_value}}"
        data = {"value": "exists", "none_value": None}
        expected_result = "Value: exists, None: None"

        # Act & Assert
        if self.engine is None:
            pytest.skip("TemplateEngine not implemented yet - TDD RED phase")

        result = self.engine.render(template_text, data)
        assert result == expected_result

    def test_substitute_with_numeric_types(self):
        """Test substitution with various numeric data types.

        Reference: Issue #65 - Template Engine Foundation
        """
        # Arrange
        template_text = "Int: {{int_val}}, Float: {{float_val}}, Bool: {{bool_val}}"
        data = {
            "int_val": 42,
            "float_val": 3.14159,
            "bool_val": True
        }
        expected_result = "Int: 42, Float: 3.14159, Bool: True"

        # Act & Assert
        if self.engine is None:
            pytest.skip("TemplateEngine not implemented yet - TDD RED phase")

        result = self.engine.render(template_text, data)
        assert result == expected_result

    def test_substitute_performance_large_template(self):
        """Test substitution performance with large templates.

        Reference: Issue #65 - Performance Requirements
        """
        # Arrange
        variables = [f"{{{{field_{i}}}}}" for i in range(100)]
        template_text = " ".join(variables)
        data = {f"field_{i}": f"value_{i}" for i in range(100)}

        # Act & Assert
        if self.engine is None:
            pytest.skip("TemplateEngine not implemented yet - TDD RED phase")

        import time
        start_time = time.time()
        result = self.engine.render(template_text, data)
        render_time = time.time() - start_time

        # Performance requirement: <50ms for 100+ variables
        assert render_time < 0.05
        assert "value_0" in result
        assert "value_99" in result

    def test_substitute_invalid_data_type(self):
        """Test error handling when data is not a dictionary.

        Reference: Issue #65 - Template Engine Foundation
        """
        # Arrange
        template_text = "Hello {{name}}!"
        invalid_data = "not a dictionary"

        # Act & Assert
        if self.engine is None:
            pytest.skip("TemplateEngine not implemented yet - TDD RED phase")

        with pytest.raises(TypeError):
            self.engine.render(template_text, invalid_data)


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