"""Report generation engine.

Produces PDF and HTML reports from plot specifications and protocol results.
Uses Jinja2 for HTML templating and WeasyPrint for PDF rendering.
"""

from __future__ import annotations

import logging
from pathlib import Path
from typing import Any

from impakt.channel.model import TestMetadata
from impakt.criteria.base import CriterionResult
from impakt.plot.engine import PlotEngine
from impakt.plot.spec import PlotSpec
from impakt.protocol.base import ProtocolResult

logger = logging.getLogger(__name__)

TEMPLATE_DIR = Path(__file__).parent / "templates"


def _get_jinja_env() -> Any:
    """Create Jinja2 environment with template directory."""
    from jinja2 import Environment, FileSystemLoader, select_autoescape

    return Environment(
        loader=FileSystemLoader(str(TEMPLATE_DIR)),
        autoescape=select_autoescape(["html"]),
    )


def generate_plot_sheet(
    spec: PlotSpec,
    output_path: str | Path,
    metadata: TestMetadata | None = None,
    format: str = "pdf",
) -> None:
    """Generate a single-page plot sheet.

    One plot per page with metadata header.
    """
    engine = PlotEngine()

    if format == "html":
        html = engine.to_html(spec)
        Path(output_path).write_text(html, encoding="utf-8")
    elif format == "pdf":
        # Generate plot as SVG, embed in HTML, render to PDF
        fig = engine.render(spec)
        plot_html = fig.to_html(include_plotlyjs="cdn", full_html=False)

        try:
            env = _get_jinja_env()
            template = env.get_template("plot_sheet.html")
            full_html = template.render(
                title=spec.title or "Impakt Plot",
                plot_html=plot_html,
                metadata=metadata,
            )
        except Exception:
            # Fallback: just use the raw plotly HTML
            full_html = f"""
            <!DOCTYPE html>
            <html>
            <head><title>{spec.title or "Impakt Plot"}</title></head>
            <body>
                <h1>{spec.title}</h1>
                {plot_html}
            </body>
            </html>
            """

        _html_to_pdf(full_html, output_path)
    else:
        # Static image
        image_bytes = engine.to_image(spec, format=format)
        Path(output_path).write_bytes(image_bytes)


def generate_injury_summary(
    criteria: dict[str, CriterionResult],
    output_path: str | Path,
    metadata: TestMetadata | None = None,
    format: str = "pdf",
) -> None:
    """Generate an injury criteria summary report."""
    try:
        env = _get_jinja_env()
        template = env.get_template("injury_summary.html")
        html = template.render(
            criteria=criteria,
            metadata=metadata,
        )
    except Exception:
        # Fallback HTML
        rows = ""
        for name, result in criteria.items():
            rows += f"<tr><td>{name}</td><td>{result.value:.2f}</td><td>{result.unit}</td></tr>"
        html = f"""
        <!DOCTYPE html>
        <html>
        <head><title>Injury Summary</title>
        <style>
            body {{ font-family: Arial, sans-serif; margin: 40px; }}
            table {{ border-collapse: collapse; width: 100%; }}
            th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
            th {{ background-color: #f4f4f4; }}
        </style>
        </head>
        <body>
            <h1>Injury Criteria Summary</h1>
            <table>
                <tr><th>Criterion</th><th>Value</th><th>Unit</th></tr>
                {rows}
            </table>
        </body>
        </html>
        """

    if format == "html":
        Path(output_path).write_text(html, encoding="utf-8")
    else:
        _html_to_pdf(html, output_path)


def generate_protocol_report(
    result: ProtocolResult,
    output_path: str | Path,
    metadata: TestMetadata | None = None,
) -> None:
    """Generate a full protocol rating report."""
    try:
        env = _get_jinja_env()
        template = env.get_template("protocol_report.html")
        html = template.render(
            result=result,
            metadata=metadata,
        )
    except Exception:
        # Fallback
        html = _fallback_protocol_html(result, metadata)

    _html_to_pdf(html, output_path)


def _fallback_protocol_html(
    result: ProtocolResult,
    metadata: TestMetadata | None = None,
) -> str:
    """Generate fallback HTML for protocol report."""
    test_info = ""
    if metadata:
        test_info = f"""
        <div class="test-info">
            <p><strong>Test:</strong> {metadata.test_number}</p>
            <p><strong>Vehicle:</strong> {metadata.vehicle.year} {metadata.vehicle.make} {metadata.vehicle.model}</p>
            <p><strong>Dummy:</strong> {metadata.dummy.dummy_type} ({metadata.dummy.position})</p>
        </div>
        """

    rows = ""
    for rs in result.region_scores:
        color_badge = ""
        if rs.color:
            color_badge = (
                f'<span class="badge" style="background:{rs.color.value}">{rs.color.value}</span>'
            )
        elif rs.rating:
            rating_colors = {
                "good": "#2ecc71",
                "acceptable": "#f1c40f",
                "marginal": "#e67e22",
                "poor": "#e74c3c",
            }
            bg = rating_colors.get(rs.rating.value, "#bdc3c7")
            color_badge = f'<span class="badge" style="background:{bg}">{rs.rating.value}</span>'

        points_str = f"{rs.points:.1f}/{rs.max_points:.1f}" if rs.max_points > 0 else ""
        rows += f"<tr><td>{rs.region}</td><td>{rs.criterion}</td><td>{rs.value:.2f} {rs.unit}</td><td>{color_badge}</td><td>{points_str}</td></tr>"

    stars_display = ""
    if result.stars is not None:
        stars_display = "&#9733;" * result.stars + "&#9734;" * (5 - result.stars)

    return f"""
    <!DOCTYPE html>
    <html>
    <head>
        <title>{result.protocol} {result.version} Report</title>
        <style>
            body {{ font-family: Arial, sans-serif; margin: 40px; color: #333; }}
            h1 {{ color: #2c3e50; }}
            .stars {{ font-size: 32px; color: #f1c40f; }}
            table {{ border-collapse: collapse; width: 100%; margin-top: 20px; }}
            th, td {{ border: 1px solid #ddd; padding: 10px; text-align: left; }}
            th {{ background-color: #2c3e50; color: white; }}
            .badge {{ padding: 4px 8px; border-radius: 4px; color: white; font-weight: bold; }}
            .test-info {{ background: #f8f9fa; padding: 15px; border-radius: 5px; margin: 15px 0; }}
            .summary {{ font-size: 18px; margin: 20px 0; }}
        </style>
    </head>
    <body>
        <h1>{result.protocol} {result.version} — Rating Report</h1>
        {test_info}
        <div class="summary">
            <p><span class="stars">{stars_display}</span></p>
            <p><strong>Overall:</strong> {result.overall_rating}</p>
            <p><strong>Score:</strong> {result.total_points:.1f}/{result.max_points:.1f} ({result.percentage:.0f}%)</p>
        </div>
        <table>
            <tr><th>Body Region</th><th>Criterion</th><th>Value</th><th>Rating</th><th>Points</th></tr>
            {rows}
        </table>
    </body>
    </html>
    """


def _html_to_pdf(html: str, output_path: str | Path) -> None:
    """Render HTML to PDF using WeasyPrint."""
    try:
        from weasyprint import HTML

        HTML(string=html).write_pdf(str(output_path))
        logger.info("PDF generated: %s", output_path)
    except ImportError:
        # Fallback: save as HTML
        html_path = Path(output_path).with_suffix(".html")
        html_path.write_text(html, encoding="utf-8")
        logger.warning(
            "WeasyPrint not available. Saved as HTML: %s. Install with: pip install weasyprint",
            html_path,
        )
    except Exception as e:
        logger.error("PDF generation failed: %s", e)
        # Save HTML as fallback
        html_path = Path(output_path).with_suffix(".html")
        html_path.write_text(html, encoding="utf-8")
