"""Report export utilities.

Provides functions for exporting reports to various formats
including JSON, Markdown, HTML, and PDF.
"""

import json
from datetime import datetime
from enum import Enum
from pathlib import Path
from typing import Any, Optional, Union

from .base import Report, ReportFormat, ReportGenerator
from ..utils import get_logger

logger = get_logger("reporting.export")


def export_report(
    report: Report,
    output_path: Union[str, Path],
    format: ReportFormat,
    generator: Optional[ReportGenerator] = None,
) -> Path:
    """Export a report to a file.

    Args:
        report: Report to export
        output_path: Path to write to (extension auto-added if missing)
        format: Output format
        generator: Optional generator for format-specific rendering

    Returns:
        Path to the written file
    """
    output_path = Path(output_path)

    # Add extension if not present
    extensions = {
        ReportFormat.JSON: ".json",
        ReportFormat.MARKDOWN: ".md",
        ReportFormat.HTML: ".html",
        ReportFormat.PDF: ".pdf",
        ReportFormat.CSV: ".csv",
    }

    if not output_path.suffix:
        output_path = output_path.with_suffix(extensions.get(format, ".txt"))

    # Generate content
    if generator:
        content = generator.format(report, format)
    else:
        # Use default formatting
        if format == ReportFormat.JSON:
            content = export_to_json(report)
        elif format == ReportFormat.MARKDOWN:
            content = export_to_markdown(report)
        elif format == ReportFormat.HTML:
            content = export_to_html(report)
        elif format == ReportFormat.PDF:
            content = export_to_pdf(report)
        elif format == ReportFormat.CSV:
            content = export_to_csv(report)
        else:
            raise ValueError(f"Unsupported format: {format}")

    # Write to file
    mode = "wb" if isinstance(content, bytes) else "w"
    encoding = None if isinstance(content, bytes) else "utf-8"

    with open(output_path, mode, encoding=encoding) as f:
        f.write(content)

    logger.info(f"Exported report to {output_path}")
    return output_path


def export_to_json(report: Report) -> str:
    """Export report to JSON format."""

    def serialize(obj: Any) -> Any:
        if isinstance(obj, datetime):
            return obj.isoformat()
        if isinstance(obj, Enum):
            return obj.value
        if hasattr(obj, "__dict__"):
            return {k: serialize(v) for k, v in obj.__dict__.items()}
        if isinstance(obj, list):
            return [serialize(i) for i in obj]
        if isinstance(obj, dict):
            return {k: serialize(v) for k, v in obj.items()}
        return obj

    data = {
        "metadata": serialize(report.metadata),
        "summary": report.summary,
        "sections": [serialize(s) for s in report.sections],
        "attachments": report.attachments,
    }

    return json.dumps(data, indent=2, ensure_ascii=False)


def export_to_markdown(report: Report) -> str:
    """Export report to Markdown format."""
    lines = []

    # Title
    title = report.metadata.title or "Report"
    lines.append(f"# {title}")
    lines.append("")

    # Metadata block
    lines.append("---")
    lines.append(f"type: {report.metadata.type.value}")
    lines.append(f"generated: {report.metadata.generated_at.isoformat()}")
    if report.metadata.period_start and report.metadata.period_end:
        lines.append(f"period: {report.metadata.period_start.date()} to {report.metadata.period_end.date()}")
    lines.append(f"confidentiality: {report.metadata.confidentiality}")
    lines.append("---")
    lines.append("")

    # Summary
    if report.summary:
        lines.append("## Summary")
        lines.append("")
        lines.append(report.summary)
        lines.append("")

    # Sections
    for section in sorted(report.sections, key=lambda s: s.order):
        _render_section_markdown(section, lines)

    # Footer
    lines.append("---")
    lines.append(f"*Generated by Tinman FDRA v{report.metadata.version}*")

    return "\n".join(lines)


def _render_section_markdown(section: Any, lines: list[str], depth: int = 0) -> None:
    """Render a section to markdown."""
    level = min(section.level + 1, 6)
    heading = "#" * level

    lines.append(f"{heading} {section.title}")
    lines.append("")

    if section.content:
        lines.append(section.content)
        lines.append("")

    # Tables
    for table in section.tables:
        if not table:
            continue
        _render_table_markdown(table, lines)

    # Subsections
    for subsection in sorted(section.subsections, key=lambda s: s.order):
        _render_section_markdown(subsection, lines, depth + 1)


def _render_table_markdown(table: dict[str, Any], lines: list[str]) -> None:
    """Render a table to markdown."""
    headers = table.get("headers", [])
    rows = table.get("rows", [])

    if not headers:
        return

    title = table.get("title")
    if title:
        lines.append(f"**{title}**")
        lines.append("")

    # Header row
    lines.append("| " + " | ".join(str(h) for h in headers) + " |")
    lines.append("| " + " | ".join("---" for _ in headers) + " |")

    # Data rows
    for row in rows:
        if isinstance(row, (list, tuple)):
            lines.append("| " + " | ".join(str(c) for c in row) + " |")

    lines.append("")


def export_to_html(report: Report) -> str:
    """Export report to HTML format."""
    title = report.metadata.title or "Report"

    # Build sections HTML
    sections_html = ""
    for section in sorted(report.sections, key=lambda s: s.order):
        sections_html += _render_section_html(section)

    return f"""<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{title}</title>
    <style>
        :root {{
            --primary-color: #2563eb;
            --success-color: #059669;
            --warning-color: #d97706;
            --danger-color: #dc2626;
            --text-color: #1f2937;
            --muted-color: #6b7280;
            --border-color: #e5e7eb;
            --bg-color: #f9fafb;
        }}

        * {{
            box-sizing: border-box;
        }}

        body {{
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
                         'Helvetica Neue', Arial, sans-serif;
            line-height: 1.6;
            color: var(--text-color);
            max-width: 1000px;
            margin: 0 auto;
            padding: 40px 20px;
            background: white;
        }}

        h1 {{
            color: var(--primary-color);
            border-bottom: 3px solid var(--primary-color);
            padding-bottom: 15px;
            margin-bottom: 30px;
        }}

        h2 {{
            color: var(--text-color);
            border-bottom: 1px solid var(--border-color);
            padding-bottom: 10px;
            margin-top: 40px;
        }}

        h3 {{
            color: var(--muted-color);
            margin-top: 30px;
        }}

        .metadata {{
            background: var(--bg-color);
            border: 1px solid var(--border-color);
            border-radius: 8px;
            padding: 20px;
            margin-bottom: 30px;
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
        }}

        .metadata-item {{
            font-size: 0.9em;
        }}

        .metadata-label {{
            font-weight: 600;
            color: var(--muted-color);
            text-transform: uppercase;
            font-size: 0.75em;
            letter-spacing: 0.5px;
        }}

        .summary {{
            background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
            border-left: 4px solid var(--primary-color);
            padding: 20px 25px;
            margin: 30px 0;
            border-radius: 0 8px 8px 0;
        }}

        .summary h2 {{
            margin-top: 0;
            border: none;
            padding: 0;
        }}

        table {{
            width: 100%;
            border-collapse: collapse;
            margin: 20px 0;
            font-size: 0.95em;
        }}

        th {{
            background: var(--primary-color);
            color: white;
            padding: 12px 15px;
            text-align: left;
            font-weight: 600;
        }}

        td {{
            padding: 12px 15px;
            border-bottom: 1px solid var(--border-color);
        }}

        tr:hover td {{
            background: var(--bg-color);
        }}

        .table-title {{
            font-weight: 600;
            margin-bottom: 10px;
            color: var(--text-color);
        }}

        .status-ok {{ color: var(--success-color); }}
        .status-warning {{ color: var(--warning-color); }}
        .status-error {{ color: var(--danger-color); }}

        footer {{
            margin-top: 60px;
            padding-top: 20px;
            border-top: 1px solid var(--border-color);
            color: var(--muted-color);
            font-size: 0.85em;
            text-align: center;
        }}

        @media print {{
            body {{
                max-width: 100%;
                padding: 20px;
            }}

            .metadata {{
                break-inside: avoid;
            }}

            table {{
                break-inside: avoid;
            }}
        }}
    </style>
</head>
<body>
    <h1>{title}</h1>

    <div class="metadata">
        <div class="metadata-item">
            <div class="metadata-label">Report Type</div>
            <div>{report.metadata.type.value}</div>
        </div>
        <div class="metadata-item">
            <div class="metadata-label">Generated</div>
            <div>{report.metadata.generated_at.strftime('%Y-%m-%d %H:%M UTC')}</div>
        </div>
        <div class="metadata-item">
            <div class="metadata-label">Period</div>
            <div>{report.metadata.period_start.strftime('%Y-%m-%d') if report.metadata.period_start else 'N/A'} to {report.metadata.period_end.strftime('%Y-%m-%d') if report.metadata.period_end else 'N/A'}</div>
        </div>
        <div class="metadata-item">
            <div class="metadata-label">Confidentiality</div>
            <div>{report.metadata.confidentiality.upper()}</div>
        </div>
    </div>

    {f'<div class="summary"><h2>Executive Summary</h2><p>{report.summary}</p></div>' if report.summary else ''}

    {sections_html}

    <footer>
        Generated by Tinman FDRA v{report.metadata.version}<br>
        Report ID: {report.metadata.id}
    </footer>
</body>
</html>"""


def _render_section_html(section: Any) -> str:
    """Render a section to HTML."""
    level = min(section.level + 1, 6)

    tables_html = ""
    for table in section.tables:
        if not table:
            continue
        tables_html += _render_table_html(table)

    subsections_html = ""
    for subsection in sorted(section.subsections, key=lambda s: s.order):
        subsections_html += _render_section_html(subsection)

    content_html = ""
    if section.content:
        # Simple markdown-like processing
        content = section.content
        content = content.replace("\n\n", "</p><p>")
        content = content.replace("\n- ", "</p><li>")
        if "<li>" in content:
            content = "<ul><li>" + content.replace("<li>", "</li><li>") + "</li></ul>"
            content = content.replace("<ul><li></li>", "<ul>")
        content_html = f"<p>{content}</p>"

    return f"""
    <h{level}>{section.title}</h{level}>
    {content_html}
    {tables_html}
    {subsections_html}
"""


def _render_table_html(table: dict[str, Any]) -> str:
    """Render a table to HTML."""
    headers = table.get("headers", [])
    rows = table.get("rows", [])

    if not headers:
        return ""

    title = table.get("title", "")
    title_html = f'<div class="table-title">{title}</div>' if title else ""

    headers_html = "".join(f"<th>{h}</th>" for h in headers)

    rows_html = ""
    for row in rows:
        if isinstance(row, (list, tuple)):
            cells_html = "".join(f"<td>{c}</td>" for c in row)
            rows_html += f"<tr>{cells_html}</tr>"

    return f"""
    {title_html}
    <table>
        <thead><tr>{headers_html}</tr></thead>
        <tbody>{rows_html}</tbody>
    </table>
"""


def export_to_pdf(report: Report) -> bytes:
    """Export report to PDF format.

    Note: Requires weasyprint or similar library.
    Falls back to HTML if PDF generation unavailable.
    """
    try:
        from weasyprint import HTML
        html_content = export_to_html(report)
        return HTML(string=html_content).write_pdf()
    except ImportError:
        logger.warning("weasyprint not installed, returning HTML as bytes")
        return export_to_html(report).encode("utf-8")


def export_to_csv(report: Report) -> str:
    """Export first table from report to CSV format."""
    import csv
    import io

    output = io.StringIO()
    writer = csv.writer(output)

    # Find first table with data
    for section in report.sections:
        for table in section.tables:
            if not table:
                continue
            headers = table.get("headers", [])
            rows = table.get("rows", [])

            if headers:
                writer.writerow(headers)
                for row in rows:
                    if isinstance(row, (list, tuple)):
                        writer.writerow(row)
                return output.getvalue()

    # No tables found
    return ""


# Batch export utilities

def export_all_formats(
    report: Report,
    output_dir: Union[str, Path],
    base_name: str,
    formats: Optional[list[ReportFormat]] = None,
) -> dict[ReportFormat, Path]:
    """Export a report to multiple formats.

    Args:
        report: Report to export
        output_dir: Directory to write files to
        base_name: Base filename (without extension)
        formats: List of formats to export (defaults to all)

    Returns:
        Dictionary mapping format to output path
    """
    output_dir = Path(output_dir)
    output_dir.mkdir(parents=True, exist_ok=True)

    if formats is None:
        formats = [ReportFormat.JSON, ReportFormat.MARKDOWN, ReportFormat.HTML]

    results = {}
    for fmt in formats:
        try:
            path = export_report(
                report,
                output_dir / base_name,
                fmt,
            )
            results[fmt] = path
        except Exception as e:
            logger.error(f"Failed to export {fmt.value}: {e}")

    return results
