"""Fast render using NumPy array operations + Pillow."""
import subprocess
import os
import math
import numpy as np
from PIL import Image, ImageDraw, ImageFont

OUT_DIR = "/app/working/workspaces/default/OpenMontage/pipeline/balimentari-senin"
NARRATION = os.path.join(OUT_DIR, "narration.wav")
FRAMES_DIR = os.path.join(OUT_DIR, "frames")
OUTPUT = os.path.join(OUT_DIR, "balimentari_senin.mp4")
FONT_BOLD = "/usr/share/fonts/truetype/quicksand/Quicksand-Bold.ttf"
FONT_REGULAR = "/usr/share/fonts/truetype/quicksand/Quicksand-Regular.ttf"

W, H = 1080, 1920
FPS = 24

dur_cmd = ["ffprobe", "-v", "error", "-show_entries", "format=duration",
           "-of", "default=noprint_wrappers=1:nokey=1", NARRATION]
narration_dur = float(subprocess.run(dur_cmd, capture_output=True, text=True).stdout.strip())
total_dur = narration_dur + 1.5
total_frames = int(total_dur * FPS)
print(f"Narration: {narration_dur:.1f}s, Total: {total_dur:.1f}s, Frames: {total_frames}")

os.makedirs(FRAMES_DIR, exist_ok=True)

# Pre-compute gradient base (y-axis color ramp)
bg_top = np.array([26, 10, 46], dtype=np.float32)
bg_bot = np.array([180, 60, 40], dtype=np.float32)

# Create y-ramp: H x 1 x 3
y_ramp = np.linspace(0, 1, H).reshape(H, 1, 1)
gradient = bg_top.reshape(1,1,3) + y_ramp * (bg_bot - bg_top).reshape(1,1,3)
# Expand to W
gradient = np.tile(gradient, (1, W, 1)).astype(np.uint8)

scenes = [
    ("The holiday", "is over.", 0.3, 2.5, 72, 88, 0.30),
    ("But today...", "is your fresh start.", 2.6, 5.5, 60, 72, 0.38),
    ("Your new", "beginning.", 5.6, 8.0, 64, 80, 0.44),
    ("The world", "is waiting.", 8.1, 10.5, 60, 68, 0.50),
    ("Take that", "first step.", 10.6, 12.8, 56, 72, 0.56),
]

print("Generating frames (NumPy optimized)...")

# Pre-generate one gradient per frame with slight pulse
for frame_idx in range(total_frames):
    t = frame_idx / FPS
    
    # Apply time-based pulse to gradient
    pulse = 1.0 + 0.04 * math.sin(t * 0.5)
    bg = np.clip(gradient.astype(np.float32) * pulse, 0, 255).astype(np.uint8)
    
    img = Image.fromarray(bg)
    draw = ImageDraw.Draw(img)
    
    # Draw scene text
    for scene in scenes:
        text1, text2, s_start, s_end, fs1, fs2, y_off = scene
        if t < s_start - 0.3 or t > s_end + 0.3:
            continue
        
        fade_dur = 0.35
        if t < s_start:
            alpha = 0.0
        elif t < s_start + fade_dur:
            alpha = (t - s_start) / fade_dur
        elif t < s_end - fade_dur:
            alpha = 1.0
        elif t < s_end:
            alpha = (s_end - t) / fade_dur
        else:
            alpha = 0.0
        
        if alpha <= 0:
            continue
        
        y_center = int(H * y_off)
        
        font1 = ImageFont.truetype(FONT_BOLD, fs1)
        font2 = ImageFont.truetype(FONT_BOLD, fs2)
        
        bbox1 = draw.textbbox((0, 0), text1, font=font1)
        tw1 = bbox1[2] - bbox1[0]
        th1 = bbox1[3] - bbox1[1]
        
        bbox2 = draw.textbbox((0, 0), text2, font=font2)
        tw2 = bbox2[2] - bbox2[0]
        th2 = bbox2[3] - bbox2[1]
        
        y1 = y_center - th1 - 8
        y2 = y_center + 8
        
        drift_y = 3 * math.sin(t * 1.5 + hash(text1) % 100)
        
        # Blend text color with alpha
        tc = (255, 255, 255)
        
        draw.text(((W - tw1) // 2, y1 + drift_y), text1, fill=tc, font=font1)
        draw.text(((W - tw2) // 2, y2 + drift_y), text2, fill=tc, font=font2)
    
    # Balimentari watermark at end
    if t > total_dur - 2.0:
        wm_font = ImageFont.truetype(FONT_BOLD, 36)
        wm_text = "Balimentari"
        wm_bbox = draw.textbbox((0, 0), wm_text, font=wm_font)
        wm_w = wm_bbox[2] - wm_bbox[0]
        draw.text(((W - wm_w) // 2, H - 120), wm_text, fill=(255,255,255), font=wm_font)
    
    img.save(os.path.join(FRAMES_DIR, f"frame_{frame_idx:05d}.png"))
    
    if frame_idx % 60 == 0 or frame_idx == total_frames - 1:
        print(f"  Frame {frame_idx+1}/{total_frames}")

print("Encoding to MP4...")
encode_cmd = [
    "ffmpeg", "-y",
    "-framerate", str(FPS),
    "-i", os.path.join(FRAMES_DIR, "frame_%05d.png"),
    "-i", NARRATION,
    "-c:v", "libx264", "-preset", "fast", "-crf", "20",
    "-c:a", "aac", "-b:a", "128k",
    "-pix_fmt", "yuv420p", "-shortest",
    OUTPUT
]
proc = subprocess.run(encode_cmd, capture_output=True, text=True, timeout=180)

if proc.returncode == 0:
    size_mb = os.path.getsize(OUTPUT) / 1024 / 1024
    print(f"\n✅ VIDEO BERHASIL DIRENDER!")
    print(f"   {OUTPUT}")
    print(f"   Size: {size_mb:.1f} MB | Duration: {total_dur:.1f}s | {W}x{H} @ {FPS}fps")
else:
    print("❌ Encode failed!")
    print(proc.stderr[-1500:])
