"""PDF report generation endpoint.

Accepts rendered HTML + optional brand config, renders to PDF via Gotenberg,
and returns the PDF bytes.
"""

from __future__ import annotations

import logging
import os
from typing import Any

import httpx
from fastapi import APIRouter, Request
from fastapi.responses import JSONResponse, Response

router = APIRouter(prefix="/v1/report", tags=["report"])

_log = logging.getLogger(__name__)

GOTENBERG_TIMEOUT = 60.0
GOTENBERG_MAX_PAYLOAD = 10_485_760  # 10 MB


async def _require_bearer_auth(
    request: Request,
) -> tuple[str, str, list[str]]:
    """Validate Bearer token and return (customer_id, tier, features).

    Reuses the API key infrastructure but reads from Authorization
    header.
    """
    from backend.api.middleware.api_key_auth import (
        APIKeyAuthError,
        require_api_key,
    )

    auth_header = request.headers.get("Authorization", "")
    if not auth_header.startswith("Bearer "):
        raise APIKeyAuthError(401, "Missing or invalid Authorization header")

    # Inject the token as X-API-Key for require_api_key
    api_key = auth_header.removeprefix("Bearer ").strip()
    request._headers = request.headers.mutablecopy()  # type: ignore[assignment]
    request._headers["X-API-Key"] = api_key  # type: ignore[index]

    ctx = await require_api_key(request)
    return ctx.customer_id, ctx.tier, ctx.features


def _inject_brand(html: str, brand: dict[str, Any]) -> str:
    """Inject brand customizations into HTML content."""
    result = html

    # Replace CSS custom properties
    primary = brand.get("primary_color")
    if primary:
        result = result.replace(
            "--primary-color: #1a56db",
            f"--primary-color: {primary}",
        )

    accent = brand.get("accent_color")
    if accent:
        result = result.replace(
            "--accent-color: #6366f1",
            f"--accent-color: {accent}",
        )

    # Inject company name into title
    company = brand.get("company_name")
    if company and "<title>" in result:
        result = result.replace(
            "<title>ComplyForm Compliance Report</title>",
            f"<title>{company} — Compliance Report</title>",
        )

    # Inject footer
    footer = brand.get("report_footer")
    if footer:
        footer_html = (
            '<footer style="text-align:center;'
            "font-size:10px;color:#6b7280;"
            "padding:1rem;"
            'border-top:1px solid #e5e7eb;">'
            f"{footer}</footer>"
        )
        result = result.replace("</body>", f"{footer_html}</body>")

    return result


@router.post("/pdf")
async def generate_pdf(request: Request) -> Response:
    """Generate PDF from HTML via Gotenberg.

    Accepts JSON body with:
    - html (str): rendered HTML content
    - brand (dict, optional): brand config for white-label
    - logo_base64 (str, optional): base64-encoded logo
    """
    from backend.api.middleware.api_key_auth import APIKeyAuthError

    try:
        customer_id, tier, features = await _require_bearer_auth(
            request,
        )
    except APIKeyAuthError as exc:
        return JSONResponse(
            status_code=exc.status_code,
            content={"detail": exc.detail},
        )

    if "branded_pdf" not in features:
        msg = f"PDF generation requires Agency tier (current: {tier})"
        return JSONResponse(
            status_code=403,
            content={"detail": msg},
        )

    try:
        body = await request.json()
    except Exception:
        return JSONResponse(
            status_code=400,
            content={"detail": "Invalid JSON body"},
        )

    html: str = body.get("html", "")
    if not html:
        return JSONResponse(
            status_code=400,
            content={"detail": "Missing 'html' field"},
        )

    # Size check
    html_bytes = html.encode("utf-8")
    if len(html_bytes) > GOTENBERG_MAX_PAYLOAD:
        return JSONResponse(
            status_code=413,
            content={"detail": "HTML payload exceeds 10 MB limit"},
        )

    # Brand injection
    brand: dict[str, Any] | None = body.get("brand")
    if brand:
        html = _inject_brand(html, brand)

    # Logo injection
    logo_b64: str | None = body.get("logo_base64")
    if logo_b64:
        logo_tag = (
            '<img src="data:image/png;base64,'
            f'{logo_b64}"'
            ' style="max-width:200px;max-height:100px;"'
            ' alt="Logo">'
        )
        # Insert after <body> tag
        html = html.replace("<body>", f"<body>{logo_tag}", 1)

    # Send to Gotenberg
    gotenberg_url = os.environ.get("GOTENBERG_URL", "http://localhost:3000")
    convert_url = f"{gotenberg_url}/forms/chromium/convert/html"

    try:
        async with httpx.AsyncClient(
            timeout=GOTENBERG_TIMEOUT,
        ) as client:
            resp = await client.post(
                convert_url,
                files={
                    "index.html": (
                        "index.html",
                        html.encode("utf-8"),
                        "text/html",
                    ),
                },
            )
    except httpx.TimeoutException:
        _log.warning("Gotenberg timeout for customer %s", customer_id)
        return JSONResponse(
            status_code=504,
            content={"detail": "PDF rendering timed out"},
        )
    except httpx.HTTPError as exc:
        _log.exception("Gotenberg error for customer %s", customer_id)
        return JSONResponse(
            status_code=502,
            content={"detail": f"PDF rendering failed: {exc}"},
        )

    if resp.status_code >= 400:
        _log.warning(
            "Gotenberg returned %s for customer %s: %s",
            resp.status_code,
            customer_id,
            resp.text[:200],
        )
        detail = f"Gotenberg error ({resp.status_code}): {resp.text[:200]}"
        return JSONResponse(
            status_code=502,
            content={"detail": detail},
        )

    return Response(
        content=resp.content,
        media_type="application/pdf",
        headers={
            "Content-Disposition": ("attachment; filename=complyform-report.pdf"),
        },
    )
