"""Brief HTML generator (Jinja2 with inline fallback).

Mirrors leads-importer's `notifier.py` philosophy — primary render path is a
Jinja2 template at `app/templates/brief.html.j2`; if the template is missing
or render fails, we fall back to a self-contained inline-HTML builder so a
template bug never blocks a brief from going to production.

The output HTML is deliberately mobile-first, single self-contained file
(inline CSS, no external stylesheet) with the canonical Open Graph tags from
the spec published in `README.md`.
"""

from __future__ import annotations

import logging
from datetime import date, datetime
from pathlib import Path
from typing import Any

from jinja2 import Environment, FileSystemLoader, TemplateError

from app.config import settings
from app.models import PastShow, Show, VoiceProfile

logger = logging.getLogger(__name__)

_TEMPLATE_DIR = Path(__file__).resolve().parent.parent / "templates"
_TEMPLATE_NAME = "brief.html.j2"

_jinja_env = Environment(
    loader=FileSystemLoader(str(_TEMPLATE_DIR)),
    autoescape=False,  # template is trusted in-repo; we deliberately don't escape
    trim_blocks=True,
    lstrip_blocks=True,
)


def generate_brief_html(
    *,
    show: Show,
    voice: VoiceProfile,
    city_intel: dict[str, Any],
    recent_news: list[dict[str, Any]],
    verified_facts: list[dict[str, Any]],
    removed_facts: list[dict[str, Any]],
    crowd_work: list[dict[str, Any]],
    competitor_warnings: list[dict[str, Any]],
    previous_show: PastShow | None,
    historical_sales: dict[str, Any],
    recent_transcripts: list[dict[str, Any]] | None = None,
    public_url: str,
) -> str:
    """Render the brief HTML. Falls back to inline HTML if Jinja breaks."""
    context = _build_template_context(**locals())
    try:
        template = _jinja_env.get_template(_TEMPLATE_NAME)
        html = template.render(**context)
        if not html or not html.strip().startswith("<"):
            logger.warning("template returned empty/non-HTML; falling back to inline")
            return _inline_fallback_html(context)
        return html
    except (TemplateError, FileNotFoundError) as exc:
        logger.warning("template render failed (%s); falling back to inline", exc)
        return _inline_fallback_html(context)


def _build_template_context(*, show, voice, city_intel, recent_news,
                            verified_facts, removed_facts, crowd_work,
                            competitor_warnings, previous_show,
                            historical_sales, public_url,
                            recent_transcripts, **_kwargs) -> dict[str, Any]:
    # Compact the recent_transcripts for the template: keep title + url + date,
    # drop the transcript body (too big for a public-facing brief).
    recent_clips = []
    for v in (recent_transcripts or []):
        recent_clips.append({
            "title": v.get("title", ""),
            "url": v.get("url", ""),
            "published_at": v.get("published_at", ""),
        })
    return {
        "comedian": voice.display_name,
        "comedian_id": voice.comedian_id,
        "city": show.city,
        "country": show.country,
        "show_date": show.show_date,
        "show_date_short": _short_date(show.show_date),
        "show_date_iso": show.show_date.isoformat(),
        "venue": show.venue,
        "capacity": show.capacity,
        "public_url": public_url,
        "og_cover_url": settings.OG_COVER_URL,
        "og_site_name": settings.OG_SITE_NAME,

        "city_intel": city_intel or {},
        "recent_news": recent_news or [],
        "verified_facts": verified_facts or [],
        "removed_facts": removed_facts or [],
        "crowd_work": crowd_work or [],
        "competitor_warnings": competitor_warnings or [],

        "recent_clips": recent_clips,

        "previous_show": previous_show,
        "previous_show_date": previous_show.show_date if previous_show else None,
        "previous_show_venue": previous_show.venue if previous_show else None,
        "previous_tickets_sold": previous_show.tickets_sold if previous_show else None,
        "historical_sales": historical_sales or {},

        "generated_at": datetime.now().strftime("%Y-%m-%d %H:%M"),
    }


def _short_date(value: date | None) -> str:
    if not value:
        return ""
    return value.strftime("%b %-d, %Y") if hasattr(value, "strftime") else str(value)


def _inline_fallback_html(context: dict[str, Any]) -> str:
    """A bare-bones brief built inline — survives any template regression."""
    city = context["city"]
    country = context["country"]
    date_str = context["show_date_short"]
    comedian = context["comedian"]
    public_url = context["public_url"]
    cover = context["og_cover_url"]
    site = context["og_site_name"]
    crowd_work = context.get("crowd_work", [])

    work_items = ""
    for i, idea in enumerate(crowd_work, 1):
        title = idea.get("title", "")
        angle = idea.get("angle", "")
        work_items += f'<li><strong>{_esc(title)}</strong> — {_esc(angle)}</li>'

    facts = ""
    for f in context.get("verified_facts", []):
        claim = f.get("claim", "")
        conf = f.get("confidence", "")
        facts += f'<li data-confidence="{_esc(conf)}">{_esc(claim)}</li>'

    news = ""
    for n in context.get("recent_news", []):
        title = n.get("title", "")
        summary = n.get("summary", "")
        news += f'<li><strong>{_esc(title)}</strong> — {_esc(summary)}</li>'

    return f"""<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>{_esc(comedian)} — {_esc(city)} Brief · {date_str}</title>
  <meta property="og:title" content="{_esc(comedian)} — {_esc(city)} Brief · {date_str}">
  <meta property="og:description" content="10 crowd work topics · local news · city intel">
  <meta property="og:image" content="{cover}">
  <meta property="og:url" content="{public_url}">
  <meta property="og:type" content="website">
  <meta property="og:site_name" content="{_esc(site)}">
  <meta name="twitter:card" content="summary_large_image">
  <style>
    body {{ font: 16px/1.45 -apple-system, BlinkMacSystemFont, system-ui, sans-serif; color: #111; max-width: 720px; margin: 0 auto; padding: 16px; }}
    h1 {{ font-size: 22px; margin: 0 0 4px 0; }}
    h2 {{ font-size: 18px; margin: 24px 0 8px 0; border-bottom: 1px solid #eee; padding-bottom: 4px; }}
    .meta {{ color: #666; font-size: 13px; margin-bottom: 16px; }}
    ul {{ padding-left: 18px; }}
    li {{ margin-bottom: 6px; }}
  </style>
</head>
<body>
  <h1>{_esc(comedian)} — {_esc(city)} Brief</h1>
  <div class="meta">{_esc(city)}, {_esc(country)} · {date_str}</div>
  <h2>Crowd Work — Top 10</h2>
  <ol>
    {work_items}
  </ol>
  <h2>Verified Facts</h2>
  <ul>{facts}</ul>
  <h2>Recent Local News</h2>
  <ul>{news}</ul>
</body>
</html>
"""


def _esc(value: Any) -> str:
    """Minimal HTML-escape for inline fallback output."""
    if value is None:
        return ""
    return (str(value)
            .replace("&", "&amp;")
            .replace("<", "&lt;")
            .replace(">", "&gt;")
            .replace('"', "&quot;"))