"""Side-effect-free HTML preview generation for render manifests."""

from __future__ import annotations

from dataclasses import dataclass
from html import escape

from autoshorts.ideas.candidate import ValidationResult
from autoshorts.rendering.manifest import RenderManifest, validate_render_manifest


@dataclass(frozen=True)
class RenderPreview:
    script_id: str
    title: str
    preview_type: str
    html: str
    side_effects: tuple[str, ...] = ()
    external_calls: tuple[str, ...] = ()


def _is_blank(value: str) -> bool:
    return not (value or "").strip()


def _timeline_row(index: int, item) -> str:
    time_range = f"{item.start_seconds}–{item.end_seconds}s"
    return "".join(
        (
            '<section class="scene">',
            f"<h2>{index:02d}. {escape(item.scene_purpose)}</h2>",
            f"<p><strong>Time:</strong> {escape(time_range)}</p>",
            f"<p><strong>Asset mode:</strong> {escape(item.asset_mode)}</p>",
            f"<p><strong>Motion:</strong> {escape(item.motion_instruction)}</p>",
            f"<p><strong>Caption:</strong> {escape(item.caption_layer.text)}</p>",
            f"<p><strong>Label:</strong> {escape(item.label_layer.text)}</p>",
            f"<p><strong>Placeholder:</strong> {escape(item.placeholder_asset_path)}</p>",
            "</section>",
        )
    )


def build_html_preview(manifest: RenderManifest) -> RenderPreview:
    """Build an inspectable HTML timeline preview without rendering media."""

    validation = validate_render_manifest(manifest)
    if not validation.is_valid:
        raise ValueError("; ".join(validation.errors))

    settings = manifest.settings
    rows = "\n".join(_timeline_row(index, item) for index, item in enumerate(manifest.timeline, start=1))
    html = f"""<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>{escape(manifest.title)} — render preview</title>
  <style>
    body {{ font-family: system-ui, sans-serif; background: #111827; color: #f9fafb; margin: 2rem; }}
    .meta, .scene {{ border: 1px solid #374151; border-radius: 12px; padding: 1rem; margin: 1rem 0; }}
    .scene {{ background: #1f2937; }}
    strong {{ color: #93c5fd; }}
  </style>
</head>
<body>
  <main>
    <h1>{escape(manifest.title)}</h1>
    <section class="meta">
      <p><strong>Script:</strong> {escape(manifest.script_id)}</p>
      <p><strong>Format:</strong> {settings.width}x{settings.height}, {settings.fps}fps</p>
      <p><strong>Text policy:</strong> captions and labels are renderer-owned; no generated text inside assets.</p>
    </section>
    {rows}
  </main>
</body>
</html>"""
    return RenderPreview(
        script_id=manifest.script_id,
        title=manifest.title,
        preview_type="html_timeline",
        html=html,
        side_effects=(),
        external_calls=(),
    )


def validate_render_preview(preview: RenderPreview) -> ValidationResult:
    errors: list[str] = []
    if _is_blank(preview.script_id):
        errors.append("script_id is required")
    if _is_blank(preview.title):
        errors.append("title is required")
    if preview.preview_type != "html_timeline":
        errors.append("preview_type must be html_timeline")
    if _is_blank(preview.html):
        errors.append("html is required")
    if "<html" not in preview.html.casefold():
        errors.append("html preview must contain an html document")
    if preview.side_effects:
        errors.append("preview must not have side effects")
    if preview.external_calls:
        errors.append("preview must not call external renderers")
    return ValidationResult(is_valid=not errors, errors=tuple(errors))
