"""
Cost Report Template Generator for MarkiTect.

This module generates professional markdown cost reports from database data
with proper frontmatter/contentmatter structure. Reports include cost breakdowns,
issue allocations, and audit trails.

Supports multiple formats:
- Summary: High-level overview with totals
- Detailed: Complete breakdown by category and item
- Audit: Full transaction history and audit trail
"""

import json
import sqlite3
from datetime import date, datetime
from decimal import Decimal
from typing import Dict, Any, List, Optional, Union
from dataclasses import dataclass
from pathlib import Path

from .cost_manager import CostItemManager
from .models import FinanceModels


@dataclass
class ReportConfig:
    """Configuration for report generation."""
    format: str = "summary"  # summary, detailed, audit
    period_start: date = None
    period_end: date = None
    include_inactive: bool = False
    currency: str = "EUR"
    output_path: Optional[str] = None


class CostReportGenerator:
    """Generator for cost reports with MarkiTect integration."""

    def __init__(self, db_path: str):
        """
        Initialize report generator.

        Args:
            db_path: Path to SQLite database file
        """
        self.db_path = db_path
        self.cost_manager = CostItemManager(db_path)
        self.finance_models = FinanceModels(db_path)

    def generate_report(self, config: ReportConfig) -> str:
        """
        Generate a cost report based on configuration.

        Args:
            config: Report configuration

        Returns:
            Markdown content with frontmatter and contentmatter
        """
        if config.format == "summary":
            return self.generate_summary_report(config)
        elif config.format == "detailed":
            return self.generate_detailed_report(config)
        elif config.format == "audit":
            return self.generate_audit_report(config)
        else:
            raise ValueError(f"Unknown report format: {config.format}")

    def generate_summary_report(self, config: ReportConfig) -> str:
        """Generate a summary cost report."""
        # Calculate period costs
        calculations = self.cost_manager.calculate_period_costs(
            config.period_start, config.period_end
        )

        # Get active cost items for the period
        active_costs = self.cost_manager.get_active_costs_for_period(
            config.period_start, config.period_end
        )

        # Prepare frontmatter
        frontmatter = {
            "report_type": "cost_summary",
            "period_start": config.period_start.isoformat(),
            "period_end": config.period_end.isoformat(),
            "total_costs": calculations["total_period"],
            "currency": config.currency,
            "generated_at": datetime.now().isoformat(),
            "active_items": calculations["active_cost_items"]
        }

        # Prepare contentmatter
        contentmatter = {
            "cost_data": {
                "total_monthly": calculations["total_monthly"],
                "total_one_time": calculations["total_one_time"],
                "total": calculations["total_period"],
                "categories": [
                    {
                        "name": name,
                        "monthly": breakdown["monthly"],
                        "one_time": breakdown["one_time"],
                        "total": breakdown["total"]
                    }
                    for name, breakdown in calculations["category_breakdown"].items()
                ],
                "active_items": len(active_costs)
            }
        }

        # Generate report content
        period_str = f"{config.period_start.strftime('%B %Y')}"
        content = self._build_summary_content(
            period_str, calculations, active_costs, config
        )

        return self._assemble_markdown(frontmatter, content, contentmatter)

    def generate_detailed_report(self, config: ReportConfig) -> str:
        """Generate a detailed cost report with full breakdowns."""
        # Calculate period costs
        calculations = self.cost_manager.calculate_period_costs(
            config.period_start, config.period_end
        )

        # Get active cost items grouped by category
        active_costs = self.cost_manager.get_active_costs_for_period(
            config.period_start, config.period_end
        )

        # Group costs by category
        costs_by_category = {}
        for cost in active_costs:
            category = cost['category_name'] or 'Uncategorized'
            if category not in costs_by_category:
                costs_by_category[category] = []
            costs_by_category[category].append(cost)

        # Prepare frontmatter
        frontmatter = {
            "report_type": "cost_detailed",
            "period_start": config.period_start.isoformat(),
            "period_end": config.period_end.isoformat(),
            "total_costs": calculations["total_period"],
            "currency": config.currency,
            "generated_at": datetime.now().isoformat(),
            "categories_count": len(costs_by_category),
            "active_items": calculations["active_cost_items"]
        }

        # Prepare detailed contentmatter
        contentmatter = {
            "cost_data": {
                "summary": {
                    "total_monthly": calculations["total_monthly"],
                    "total_one_time": calculations["total_one_time"],
                    "total": calculations["total_period"]
                },
                "categories": {},
                "items": []
            }
        }

        for category, costs in costs_by_category.items():
            cat_total = sum(float(cost['amount_eur']) for cost in costs)
            contentmatter["cost_data"]["categories"][category] = {
                "total": cat_total,
                "items_count": len(costs)
            }

            for cost in costs:
                contentmatter["cost_data"]["items"].append({
                    "id": cost['id'],
                    "name": cost['name'],
                    "category": category,
                    "amount": float(cost['amount_eur']),
                    "type": cost['cost_type'],
                    "active": bool(cost['is_active'])
                })

        # Generate report content
        period_str = f"{config.period_start.strftime('%B %Y')}"
        content = self._build_detailed_content(
            period_str, calculations, costs_by_category, config
        )

        return self._assemble_markdown(frontmatter, content, contentmatter)

    def generate_audit_report(self, config: ReportConfig) -> str:
        """Generate an audit report with transaction history."""
        # Get cost calculations
        calculations = self.cost_manager.calculate_period_costs(
            config.period_start, config.period_end
        )

        # Get all cost items for the period
        active_costs = self.cost_manager.get_active_costs_for_period(
            config.period_start, config.period_end
        )

        # Get transaction history (simplified - would be enhanced with actual transaction data)
        transactions = self._get_transaction_history(config.period_start, config.period_end)

        # Prepare frontmatter
        frontmatter = {
            "report_type": "cost_audit",
            "period_start": config.period_start.isoformat(),
            "period_end": config.period_end.isoformat(),
            "total_costs": calculations["total_period"],
            "currency": config.currency,
            "generated_at": datetime.now().isoformat(),
            "transactions_count": len(transactions),
            "audit_trail": True
        }

        # Prepare audit contentmatter (ensure all dates are serialized)
        period_summary = calculations.copy()
        period_summary['period_start'] = period_summary['period_start'].isoformat()
        period_summary['period_end'] = period_summary['period_end'].isoformat()

        contentmatter = {
            "audit_data": {
                "period_summary": period_summary,
                "transactions": transactions,
                "cost_items": [
                    {
                        "id": cost['id'],
                        "name": cost['name'],
                        "amount": float(cost['amount_eur']),
                        "start_date": str(cost['starting_from_date']) if cost['starting_from_date'] else None,
                        "end_date": str(cost['ending_date']) if cost['ending_date'] else None
                    }
                    for cost in active_costs
                ]
            }
        }

        # Generate report content
        period_str = f"{config.period_start.strftime('%B %Y')}"
        content = self._build_audit_content(
            period_str, calculations, active_costs, transactions, config
        )

        return self._assemble_markdown(frontmatter, content, contentmatter)

    def _build_summary_content(self, period_str: str, calculations: Dict[str, Any],
                             active_costs: List[Dict], config: ReportConfig) -> str:
        """Build summary report content."""
        content = [
            f"# Cost Summary Report - {period_str}",
            "",
            "## Overview",
            f"- **Period**: {config.period_start.strftime('%Y-%m-%d')} to {config.period_end.strftime('%Y-%m-%d')}",
            f"- **Total Costs**: €{calculations['total_period']:.2f}",
            f"- **Monthly Recurring**: €{calculations['total_monthly']:.2f}",
            f"- **One-time Expenses**: €{calculations['total_one_time']:.2f}",
            f"- **Active Cost Items**: {calculations['active_cost_items']}",
            ""
        ]

        if calculations['category_breakdown']:
            content.extend([
                "## Cost Breakdown by Category",
                "",
                "| Category | Monthly | One-time | Total |",
                "|----------|---------|----------|-------|"
            ])

            for category, breakdown in calculations['category_breakdown'].items():
                content.append(
                    f"| {category} | €{breakdown['monthly']:.2f} | "
                    f"€{breakdown['one_time']:.2f} | €{breakdown['total']:.2f} |"
                )

            content.append("")

        # Add top cost items
        if active_costs:
            content.extend([
                "## Top Cost Items",
                ""
            ])

            # Sort by amount (descending)
            sorted_costs = sorted(active_costs, key=lambda x: float(x['amount_eur']), reverse=True)

            for cost in sorted_costs[:5]:  # Top 5
                content.append(
                    f"- **{cost['name']}**: €{float(cost['amount_eur']):.2f}/{cost['cost_type']} "
                    f"({cost['category_name'] or 'Uncategorized'})"
                )

            content.append("")

        return "\n".join(content)

    def _build_detailed_content(self, period_str: str, calculations: Dict[str, Any],
                              costs_by_category: Dict[str, List], config: ReportConfig) -> str:
        """Build detailed report content."""
        content = [
            f"# Detailed Cost Report - {period_str}",
            "",
            "## Executive Summary",
            f"- **Period**: {config.period_start.strftime('%Y-%m-%d')} to {config.period_end.strftime('%Y-%m-%d')}",
            f"- **Total Costs**: €{calculations['total_period']:.2f}",
            f"- **Monthly Recurring**: €{calculations['total_monthly']:.2f}",
            f"- **One-time Expenses**: €{calculations['total_one_time']:.2f}",
            f"- **Categories**: {len(costs_by_category)}",
            f"- **Active Items**: {calculations['active_cost_items']}",
            ""
        ]

        # Add detailed breakdown by category
        for category, costs in costs_by_category.items():
            category_total = sum(float(cost['amount_eur']) for cost in costs)

            content.extend([
                f"## {category}",
                f"**Category Total**: €{category_total:.2f}",
                "",
                "| Name | Type | Amount | Status | Start Date |",
                "|------|------|--------|--------|------------|"
            ])

            for cost in sorted(costs, key=lambda x: float(x['amount_eur']), reverse=True):
                status = "Active" if cost['is_active'] else "Inactive"
                content.append(
                    f"| {cost['name']} | {cost['cost_type']} | "
                    f"€{float(cost['amount_eur']):.2f} | {status} | "
                    f"{cost['starting_from_date']} |"
                )

            content.extend(["", ""])

        return "\n".join(content)

    def _build_audit_content(self, period_str: str, calculations: Dict[str, Any],
                           active_costs: List[Dict], transactions: List[Dict],
                           config: ReportConfig) -> str:
        """Build audit report content."""
        content = [
            f"# Cost Audit Report - {period_str}",
            "",
            "## Audit Summary",
            f"- **Period**: {config.period_start.strftime('%Y-%m-%d')} to {config.period_end.strftime('%Y-%m-%d')}",
            f"- **Total Costs**: €{calculations['total_period']:.2f}",
            f"- **Audit Date**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
            f"- **Transaction Records**: {len(transactions)}",
            f"- **Cost Items Reviewed**: {len(active_costs)}",
            "",
            "## Cost Verification",
            "",
            "### Active Cost Items",
            "",
            "| ID | Name | Category | Amount | Type | Start Date | End Date |",
            "|----|----- |----------|--------|------|------------|----------|"
        ]

        for cost in active_costs:
            end_date = cost['ending_date'] if cost['ending_date'] else "Ongoing"
            content.append(
                f"| {cost['id']} | {cost['name']} | "
                f"{cost['category_name'] or 'N/A'} | €{float(cost['amount_eur']):.2f} | "
                f"{cost['cost_type']} | {cost['starting_from_date']} | {end_date} |"
            )

        content.extend(["", "### Transaction History", ""])

        if transactions:
            content.extend([
                "| Date | Type | Amount | Description |",
                "|------|------|--------|-------------|"
            ])

            for transaction in transactions:
                content.append(
                    f"| {transaction['date']} | {transaction['type']} | "
                    f"€{transaction['amount']:.2f} | {transaction['description']} |"
                )
        else:
            content.append("*No transaction records found for this period.*")

        content.extend(["", "### Audit Trail", ""])
        content.append(f"This report was generated automatically from the MarkiTect cost tracking database.")
        content.append(f"All amounts are in {config.currency} and reflect active cost items for the specified period.")

        return "\n".join(content)

    def _get_transaction_history(self, period_start: date, period_end: date) -> List[Dict]:
        """Get transaction history for audit report (placeholder implementation)."""
        # This would query actual transaction data when implemented
        # For now, return sample data
        return [
            {
                "date": period_start.isoformat(),
                "type": "cost_incurred",
                "amount": 87.00,
                "description": "Monthly recurring costs applied"
            }
        ]

    def _assemble_markdown(self, frontmatter: Dict[str, Any], content: str,
                          contentmatter: Dict[str, Any]) -> str:
        """Assemble complete markdown document with frontmatter and contentmatter."""
        # Convert frontmatter to YAML
        fm_lines = ["---"]
        for key, value in frontmatter.items():
            if isinstance(value, str):
                fm_lines.append(f'{key}: "{value}"')
            else:
                fm_lines.append(f'{key}: {value}')
        fm_lines.append("---")

        # Convert contentmatter to HTML comment
        cm_json = json.dumps(contentmatter, indent=2)
        cm_lines = [
            "<!--",
            "contentmatter:",
            cm_json,
            "-->"
        ]

        # Assemble final document
        return "\n".join([
            "\n".join(fm_lines),
            "",
            content,
            "",
            "\n".join(cm_lines)
        ])

    def save_report(self, report_content: str, output_path: str) -> None:
        """Save report to file."""
        output_file = Path(output_path)
        output_file.parent.mkdir(parents=True, exist_ok=True)

        with open(output_file, 'w', encoding='utf-8') as f:
            f.write(report_content)

    def generate_period_report(self, year: int, month: int, format: str = "summary") -> str:
        """
        Generate report for a specific month.

        Args:
            year: Year (e.g., 2025)
            month: Month (1-12)
            format: Report format

        Returns:
            Generated report content
        """
        from calendar import monthrange

        period_start = date(year, month, 1)
        _, last_day = monthrange(year, month)
        period_end = date(year, month, last_day)

        config = ReportConfig(
            format=format,
            period_start=period_start,
            period_end=period_end
        )

        return self.generate_report(config)