#!/usr/bin/env python3
"""
annotate-draft.py — overlays lower-third title cards onto the-takeover-draft.mp4
Uses PIL for text rendering + ffmpeg overlay filter (no libfreetype needed).
"""
import subprocess, json, struct, os, sys, shutil
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont

BASE = Path(__file__).parent / "storyboard-the-takeover"
IN_VIDEO = BASE / "the-takeover-draft.mp4"
OUT_VIDEO = BASE / "the-takeover-annotated.mp4"
OVERLAY_DIR = BASE / "overlays"
OVERLAY_DIR.mkdir(exist_ok=True)

FONT_PATH = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
FONT_SM_PATH = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"

# Video dimensions
W, H = 1280, 720

# Shot data: (start_time, end_time, title, description, desc_color)
# Times are cumulative (clips are 7s or 5s each: 7+5+5+7+7+7+7+7+7+5 = 64s)
SHOTS = [
    # Opening title card (first 3.5s)
    (0.3,  3.2,  "THE TAKEOVER",  "MICHA — a psychological horror film",  "#aaaaaa", True),
    # Per-shot lower thirds
    (3.6,  6.3,  "01 · THE GATHERING",      "She arrives. Something is already off.",                          "#cccccc", False),
    (7.6,  11.3, "02 · NORA — BEFORE",      "The last moments of herself.",                                    "#cccccc", False),
    (12.6, 16.3, "03 · THE SHIFT",           "The glass moves to her palm. MICHA takes control.",               "#cccccc", False),
    (17.6, 23.3, "04 · MICHA SPEAKS",        "Calibrated. Precise. The other woman smiles too quickly.",        "#cccccc", False),
    (24.6, 30.3, "05 · ASSESSMENT",          "Not socialising. MICHA is mapping the room.",                     "#cccccc", False),
    (31.6, 37.3, "06 · RECOGNITION",         "He checks his phone. She already knows what he found.",           "#cccccc", False),
    (38.6, 44.3, "07 · THE WINDOW",          "MICHA studies the body it now inhabits.",                         "#cccccc", False),
    (45.6, 51.3, "08 · THE REFLECTION",      "They blink — together. Exactly on time.",                         "#ff6666", False),
    (52.6, 58.3, "09 · THE HALLWAY",         "Nora surfaces. She opens the app.",                               "#cccccc", False),
    (59.8, 63.3, "10 · THE MESSAGE",         "MICHA and Nora — texting each other. From the same body.",        "#ff6666", False),
]

def make_overlay(title, desc, desc_color, centered=False):
    """Render a lower-third PNG (full frame, transparent bg except the bar)."""
    img = Image.new("RGBA", (W, H), (0, 0, 0, 0))
    draw = ImageDraw.Draw(img)

    try:
        font_bold = ImageFont.truetype(FONT_PATH, 28)
        font_reg  = ImageFont.truetype(FONT_SM_PATH, 20)
    except:
        font_bold = ImageFont.load_default()
        font_reg  = font_bold

    if centered:
        # Big centred title card
        try:
            font_big = ImageFont.truetype(FONT_PATH, 52)
        except:
            font_big = font_bold

        # Background bar
        draw.rectangle([(0, H//2 - 60), (W, H//2 + 80)], fill=(0, 0, 0, 165))
        # Title
        bb = draw.textbbox((0, 0), title, font=font_big)
        tw = bb[2] - bb[0]
        draw.text(((W - tw) // 2, H//2 - 48), title, font=font_big, fill=(255, 255, 255, 255))
        # Subtitle
        bb2 = draw.textbbox((0, 0), desc, font=font_reg)
        tw2 = bb2[2] - bb2[0]
        draw.text(((W - tw2) // 2, H//2 + 16), desc, font=font_reg, fill=(180, 180, 180, 230))
    else:
        # Lower third bar
        bar_h = 72
        bar_y = H - bar_h - 12
        draw.rectangle([(0, bar_y), (W, bar_y + bar_h)], fill=(0, 0, 0, 155))
        draw.text((36, bar_y + 6),  title, font=font_bold, fill=(255, 255, 255, 255))
        draw.text((36, bar_y + 38), desc,  font=font_reg,  fill=(*bytes.fromhex(desc_color.lstrip("#")), 230))

    return img

# Generate all overlay PNGs
overlay_files = []
for i, (t_in, t_out, title, desc, dcolor, centered) in enumerate(SHOTS):
    img = make_overlay(title, desc, dcolor, centered)
    path = OVERLAY_DIR / f"overlay_{i:02d}.png"
    img.save(path)
    overlay_files.append((t_in, t_out, path))
    print(f"  ✓ overlay_{i:02d}.png — {title}")

CLIPS_DIR = BASE / "clips"
ANNOT_DIR = BASE / "annotated_clips"
ANNOT_DIR.mkdir(exist_ok=True)

# Clip list with their global start times
CLIP_INFO = [
    ("01-establishing.mp4",  0.00,   7.041667),
    ("02-nora-before.mp4",   7.041667, 12.083334),
    ("03-the-shift.mp4",     12.083334, 17.125001),
    ("04-micha-speaks.mp4",  17.125001, 24.166668),
    ("05-the-scan.mp4",      24.166668, 31.208335),
    ("06-david.mp4",         31.208335, 38.250002),
    ("07-the-window.mp4",    38.250002, 45.291669),
    ("08-the-reflection.mp4",45.291669, 52.333336),
    ("09-the-hallway.mp4",   52.333336, 59.375003),
    ("10-the-app.mp4",       59.375003, 64.416670),
]

def run_ffmpeg(cmd, label):
    r = subprocess.run(cmd, capture_output=True, text=True)
    if r.returncode != 0:
        print(f"  ERROR ({label}):\n{r.stderr[-1500:]}")
        sys.exit(1)

print("\nAnnotating each clip independently...")
annotated_clips = []

for clip_name, clip_start, clip_end in CLIP_INFO:
    clip_path = CLIPS_DIR / clip_name
    out_path  = ANNOT_DIR / clip_name

    # Find all overlays whose window intersects this clip
    relevant = []
    for t_in, t_out, png_path in overlay_files:
        if t_out > clip_start and t_in < clip_end:
            # Convert to clip-relative timestamps
            rel_in  = round(max(t_in  - clip_start, 0.0), 3)
            rel_out = round(min(t_out - clip_start, clip_end - clip_start), 3)
            relevant.append((rel_in, rel_out, png_path))

    if not relevant:
        # No overlay for this clip — just copy it
        shutil.copy(clip_path, out_path)
        print(f"  ✓ {clip_name}  (no overlay, copied)")
    else:
        # Build ffmpeg command: one PNG input per overlay
        cmd = ["ffmpeg", "-y", "-i", str(clip_path)]
        for _, _, p in relevant:
            cmd += ["-loop", "1", "-i", str(p)]

        # Chain overlays
        parts = []
        for idx, (rel_in, rel_out, _) in enumerate(relevant):
            src = f"[v{idx}]" if idx > 0 else "[0:v]"
            dst = f"[v{idx+1}]"
            parts.append(f"{src}[{idx+1}:v]overlay=enable='between(t,{rel_in},{rel_out})'{dst}")
        filter_complex = "; ".join(parts)
        final_label    = f"[v{len(relevant)}]"

        cmd += [
            "-filter_complex", filter_complex,
            "-map", final_label,
            "-map", "0:a?",
            "-c:v", "libx264", "-preset", "ultrafast", "-crf", "20",
            "-c:a", "copy",
            "-shortest",
            str(out_path),
        ]
        run_ffmpeg(cmd, clip_name)
        print(f"  ✓ {clip_name}  ({len(relevant)} overlay{'s' if len(relevant)>1 else ''})")

    annotated_clips.append(out_path)

# Concatenate all annotated clips
print("\nConcatenating annotated clips...")
concat_list = ANNOT_DIR / "concat.txt"
with open(concat_list, "w") as f:
    for p in annotated_clips:
        f.write(f"file '{p}'\n")

run_ffmpeg([
    "ffmpeg", "-y",
    "-f", "concat", "-safe", "0", "-i", str(concat_list),
    "-c", "copy",
    str(OUT_VIDEO),
], "concat")

print(f"\n✓ Done: {OUT_VIDEO}")
print(f"  Size: {os.path.getsize(OUT_VIDEO) // 1024 // 1024}MB")

# Cleanup
shutil.rmtree(OVERLAY_DIR)
shutil.rmtree(ANNOT_DIR)
concat_list.unlink(missing_ok=True)
print("  Temp files cleaned up")
