"""
Tests for MarkiTect cost report template generator.

This module tests the complete cost report generation functionality including:
- Report generation in different formats (summary, detailed, audit)
- Markdown output with frontmatter and contentmatter
- CLI integration and command functionality
- Template structure validation
"""

import pytest
import tempfile
import os
import json
from datetime import date, datetime
from decimal import Decimal

from markitect.finance.cost_manager import CostItemManager, CostItem
from markitect.finance.report_generator import CostReportGenerator, ReportConfig
from markitect.finance.models import FinanceModels


class TestCostReportGenerator:
    """Test suite for cost report generation system."""

    @pytest.fixture
    def temp_db(self):
        """Create temporary database for testing."""
        fd, path = tempfile.mkstemp(suffix='.db')
        os.close(fd)
        yield path
        os.unlink(path)

    @pytest.fixture
    def setup_test_data(self, temp_db):
        """Setup test database with sample cost data."""
        finance_models = FinanceModels(temp_db)
        finance_models.initialize_finance_schema()

        cost_manager = CostItemManager(temp_db)

        # Get categories
        infra_cat = cost_manager.get_category_by_name('Infrastructure')
        software_cat = cost_manager.get_category_by_name('Software')

        # Create sample cost items
        cost_items = [
            CostItem(
                category_id=infra_cat['id'],
                name='Hosteurope Server',
                description='Monthly server hosting',
                cost_type='monthly',
                amount_eur=Decimal('10.00'),
                starting_from_date=date(2025, 1, 1)
            ),
            CostItem(
                category_id=software_cat['id'],
                name='Bubble.io Plan',
                description='No-code platform subscription',
                cost_type='monthly',
                amount_eur=Decimal('32.00'),
                starting_from_date=date(2025, 1, 1)
            ),
            CostItem(
                category_id=infra_cat['id'],
                name='SSL Certificate',
                description='Annual SSL certificate',
                cost_type='one_time',
                amount_eur=Decimal('45.00'),
                starting_from_date=date(2025, 1, 15)
            )
        ]

        for item in cost_items:
            cost_manager.create_cost_item(item)

        return temp_db

    @pytest.fixture
    def report_generator(self, setup_test_data):
        """Create report generator with test data."""
        return CostReportGenerator(setup_test_data)

    def test_report_config_creation(self):
        """Test ReportConfig dataclass creation."""
        config = ReportConfig(
            format="summary",
            period_start=date(2025, 1, 1),
            period_end=date(2025, 1, 31),
            currency="EUR"
        )

        assert config.format == "summary"
        assert config.period_start == date(2025, 1, 1)
        assert config.period_end == date(2025, 1, 31)
        assert config.currency == "EUR"
        assert config.include_inactive is False
        assert config.output_path is None

    def test_generate_summary_report(self, report_generator):
        """Test generation of summary cost report."""
        config = ReportConfig(
            format="summary",
            period_start=date(2025, 1, 1),
            period_end=date(2025, 1, 31)
        )

        report = report_generator.generate_report(config)

        # Check that it's valid markdown with frontmatter
        assert report.startswith("---")
        assert "Cost Summary Report - January 2025" in report
        assert "total_costs: 87.0" in report
        assert "report_type: \"cost_summary\"" in report

        # Check contentmatter is present
        assert "contentmatter:" in report
        assert "cost_data" in report

        # Verify total costs are correct (10 + 32 + 45 = 87)
        assert "€87.00" in report

    def test_generate_detailed_report(self, report_generator):
        """Test generation of detailed cost report."""
        config = ReportConfig(
            format="detailed",
            period_start=date(2025, 1, 1),
            period_end=date(2025, 1, 31)
        )

        report = report_generator.generate_report(config)

        # Check report structure
        assert "Detailed Cost Report - January 2025" in report
        assert "Executive Summary" in report
        assert "report_type: \"cost_detailed\"" in report

        # Check category sections are present
        assert "Infrastructure" in report
        assert "Software" in report

        # Check individual items are listed
        assert "Hosteurope Server" in report
        assert "Bubble.io Plan" in report
        assert "SSL Certificate" in report

        # Check table format
        assert "| Name | Type | Amount | Status | Start Date |" in report

    def test_generate_audit_report(self, report_generator):
        """Test generation of audit trail report."""
        config = ReportConfig(
            format="audit",
            period_start=date(2025, 1, 1),
            period_end=date(2025, 1, 31)
        )

        report = report_generator.generate_report(config)

        # Check report structure
        assert "Cost Audit Report - January 2025" in report
        assert "Audit Summary" in report
        assert "report_type: \"cost_audit\"" in report
        assert "audit_trail: True" in report

        # Check audit sections
        assert "Cost Verification" in report
        assert "Active Cost Items" in report
        assert "Transaction History" in report
        assert "Audit Trail" in report

        # Check contentmatter includes audit data
        assert "audit_data" in report

    def test_generate_period_report_convenience_method(self, report_generator):
        """Test convenience method for generating monthly reports."""
        report = report_generator.generate_period_report(2025, 1, "summary")

        assert "Cost Summary Report - January 2025" in report
        assert "2025-01-01" in report
        assert "2025-01-31" in report

    def test_invalid_report_format_raises_error(self, report_generator):
        """Test that invalid report format raises ValueError."""
        config = ReportConfig(
            format="invalid",
            period_start=date(2025, 1, 1),
            period_end=date(2025, 1, 31)
        )

        with pytest.raises(ValueError, match="Unknown report format"):
            report_generator.generate_report(config)

    def test_frontmatter_structure(self, report_generator):
        """Test frontmatter structure in generated reports."""
        config = ReportConfig(
            format="summary",
            period_start=date(2025, 1, 1),
            period_end=date(2025, 1, 31)
        )

        report = report_generator.generate_report(config)

        # Extract frontmatter (between first two ---)
        lines = report.split('\n')
        frontmatter_lines = []
        in_frontmatter = False

        for line in lines:
            if line.strip() == "---":
                if not in_frontmatter:
                    in_frontmatter = True
                    continue
                else:
                    break
            if in_frontmatter:
                frontmatter_lines.append(line)

        frontmatter_text = '\n'.join(frontmatter_lines)

        # Check required frontmatter fields
        assert 'report_type:' in frontmatter_text
        assert 'period_start:' in frontmatter_text
        assert 'period_end:' in frontmatter_text
        assert 'total_costs:' in frontmatter_text
        assert 'currency:' in frontmatter_text
        assert 'generated_at:' in frontmatter_text

    def test_contentmatter_structure(self, report_generator):
        """Test contentmatter structure in generated reports."""
        config = ReportConfig(
            format="summary",
            period_start=date(2025, 1, 1),
            period_end=date(2025, 1, 31)
        )

        report = report_generator.generate_report(config)

        # Extract contentmatter (JSON in HTML comment)
        assert "<!--" in report
        assert "contentmatter:" in report
        assert "-->" in report

        # Find and extract JSON
        start = report.find("contentmatter:\n") + len("contentmatter:\n")
        end = report.find("\n-->")
        json_text = report[start:end].strip()

        # Parse JSON to verify structure
        contentmatter = json.loads(json_text)

        assert "cost_data" in contentmatter
        assert "total_monthly" in contentmatter["cost_data"]
        assert "total_one_time" in contentmatter["cost_data"]
        assert "categories" in contentmatter["cost_data"]
        assert "active_items" in contentmatter["cost_data"]

        # Verify totals
        assert contentmatter["cost_data"]["total_monthly"] == 42.0
        assert contentmatter["cost_data"]["total_one_time"] == 45.0

    def test_save_report_to_file(self, report_generator, temp_db):
        """Test saving report to file."""
        config = ReportConfig(
            format="summary",
            period_start=date(2025, 1, 1),
            period_end=date(2025, 1, 31)
        )

        report = report_generator.generate_report(config)

        # Save to temporary file
        with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.md') as f:
            output_path = f.name

        try:
            report_generator.save_report(report, output_path)

            # Verify file was created and contains expected content
            with open(output_path, 'r', encoding='utf-8') as f:
                saved_content = f.read()

            assert saved_content == report
            assert "Cost Summary Report" in saved_content

        finally:
            os.unlink(output_path)

    def test_empty_database_report(self, temp_db):
        """Test report generation with empty database."""
        # Initialize empty database
        finance_models = FinanceModels(temp_db)
        finance_models.initialize_finance_schema()

        report_generator = CostReportGenerator(temp_db)
        config = ReportConfig(
            format="summary",
            period_start=date(2025, 1, 1),
            period_end=date(2025, 1, 31)
        )

        report = report_generator.generate_report(config)

        # Should still generate valid report with zero costs
        assert "total_costs: 0.0" in report
        assert "€0.00" in report

    def test_different_currency(self, report_generator):
        """Test report generation with different currency."""
        config = ReportConfig(
            format="summary",
            period_start=date(2025, 1, 1),
            period_end=date(2025, 1, 31),
            currency="USD"
        )

        report = report_generator.generate_report(config)

        assert 'currency: "USD"' in report
        # Note: amounts are still in EUR from database, currency is just metadata

    def test_report_with_inactive_items(self, setup_test_data):
        """Test report behavior with inactive cost items."""
        cost_manager = CostItemManager(setup_test_data)

        # Deactivate one item
        items = cost_manager.list_cost_items()
        if items:
            cost_manager.deactivate_cost_item(items[0]['id'], date(2025, 1, 15))

        report_generator = CostReportGenerator(setup_test_data)
        config = ReportConfig(
            format="detailed",
            period_start=date(2025, 1, 1),
            period_end=date(2025, 1, 31),
            include_inactive=False
        )

        report = report_generator.generate_report(config)

        # Should still generate valid report, potentially with fewer active items
        assert "Detailed Cost Report" in report
        assert "contentmatter:" in report

    def test_cross_month_period(self, report_generator):
        """Test report generation across multiple months."""
        config = ReportConfig(
            format="summary",
            period_start=date(2025, 1, 15),
            period_end=date(2025, 2, 15)
        )

        report = report_generator.generate_report(config)

        assert "2025-01-15" in report
        assert "2025-02-15" in report
        # Should include items active during this period