#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
THẬP NGŨ NIÊN - Render Full Scene 02 (Gia Trang Họ Vương) with LTX-2.3 22B Distilled (High-Res 16:9 Cinema)
"""

import sys
import os
import json
import time
import shutil
import subprocess
from pathlib import Path

# Ensure UTF-8 console output
if sys.platform == "win32":
    try:
        sys.stdout.reconfigure(encoding="utf-8")
        sys.stderr.reconfigure(encoding="utf-8")
    except Exception:
        pass

BASE_DIR = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(BASE_DIR))

from gradio_client import Client, handle_file

HF_TOKEN = os.getenv("HF_TOKEN", "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")
LTX_SPACE_ID = "Lightricks/LTX-2-3"

def get_ffmpeg():
    exe = Path(sys.executable).parent / "ffmpeg.exe"
    if exe.exists():
        return str(exe)
    return "ffmpeg"

SHOTS_TO_RENDER = [
    {
        "id": "ep01_scene02_shot01",
        "title": "Toàn cảnh sân trong Gia Trang họ Vương (Wide Establishing 16:9)",
        "image": "04_Assets/keyframes/ep01_scene02_shot01_start.jpg",
        "prompt": "Toàn cảnh sân trong gia trang họ Vương lát gạch Bát Tràng đỏ au, chậu sen gốm hoa lam, hiên nhà gỗ chạm trổ rồng mây cổ kính, nắng sớm lung linh rọi qua rèm, camera slow cinematic push-in êm ả, 24fps cinematic film.",
        "dest": "04_Assets/videos/ep01_scene02_shot01_ltx23.mp4"
    },
    {
        "id": "ep01_scene02_shot02",
        "title": "Nội cảnh phòng khách gia trang (Interior Medium Shot 16:9)",
        "image": "04_Assets/keyframes/ep01_scene02_shot02_start.jpg",
        "prompt": "Nội cảnh phòng khách thanh nhã ấm cúng gia trang họ Vương, ánh nắng sớm rọi qua rèm the mỏng tạo dải sáng vàng mềm mại, khói trầm từ lư đồng uốn lượn bay lên nhẹ nhàng, bàn trà gỗ trắc tĩnh tại, 24fps cinematic film.",
        "dest": "04_Assets/videos/ep01_scene02_shot02_ltx23.mp4"
    },
    {
        "id": "ep01_scene02_shot04",
        "title": "Vương Ông thưởng trà (MCU Father 16:9 Widescreen)",
        "image": "04_Assets/keyframes/ep01_scene02_shot04_start.jpg",
        "prompt": "Trung cận 16:9 Vương Ông đạo mạo ngồi bên bàn trà gỗ trắc chậm rãi nâng chén trà sứ hoa lam, ánh mắt suy tư đôn hậu hiền từ, khói trầm lượn nhẹ trong nắng mai, 24fps cinematic film.",
        "dest": "04_Assets/videos/ep01_scene02_shot04_ltx23.mp4"
    },
    {
        "id": "ep01_scene02_shot06",
        "title": "Vương Bà vuốt nếp áo lụa du xuân (MCU Mother 16:9 Widescreen)",
        "image": "04_Assets/keyframes/ep01_scene02_shot06_start.jpg",
        "prompt": "Trung cận 16:9 Vương Bà hiền từ phúc hậu vấn khăn nhung đen, ngồi bên bàn trà âu yếm vuốt phẳng nếp áo lụa gấm hoa du xuân trên đùi, nụ cười ấm áp đôn hậu, ánh nắng mai dịu dàng qua chấn song cửa sổ, 24fps cinematic film.",
        "dest": "04_Assets/videos/ep01_scene02_shot06_ltx23.mp4"
    },
    {
        "id": "ep01_scene02_shot07",
        "title": "Hai vợ chồng đàm đạo gia phong (Two-Shot Parents 16:9)",
        "image": "04_Assets/keyframes/ep01_scene02_shot07_start.jpg",
        "prompt": "Trung cảnh đôi 16:9 Vương Ông và Vương Bà ngồi bên bàn trà gỗ trắc mỉm cười đôn hậu trò chuyện, ánh mắt mãn nguyện đàm đạo trong nắng mai, khói trầm uốn lượn ấm cúng gia đình gia giáo, 24fps cinematic film.",
        "dest": "04_Assets/videos/ep01_scene02_shot07_ltx23.mp4"
    },
    {
        "id": "ep01_scene02_shot08",
        "title": "Vương Quan bước vào bái chào cha mẹ (Entrance & Bow 16:9)",
        "image": "04_Assets/keyframes/ep01_scene02_shot08_start.jpg",
        "prompt": "Vương Quan thiếu niên thư sinh áo giao lĩnh lam nhạt bước qua ngưỡng cửa phòng khách, hai tay chắp bái chào cha mẹ với phong thái khiêm cung hiếu thảo, cha mẹ mỉm cười đón con, 24fps cinematic film.",
        "dest": "04_Assets/videos/ep01_scene02_shot08_ltx23.mp4"
    }
]

def render_all_shots():
    print("\n" + "=" * 75)
    print("🎬 [LTX-2.3 22B PIPELINE] BẮT ĐẦU SẢN XUẤT CẢNH 02 (TẬP 1) - CHUẨN ĐIỆN ẢNH 16:9")
    print(f"   • Không gian mô hình: {LTX_SPACE_ID} (22B Distilled + Audio + High-Res 1536x1024)")
    print(f"   • Tổng số shot cấu thành: {len(SHOTS_TO_RENDER)} shots (Toàn bộ 16:9 Widescreen)")
    print("=" * 75)

    client = None
    rendered_files = []

    for idx, s in enumerate(SHOTS_TO_RENDER, 1):
        shot_id = s["id"]
        dest_p = BASE_DIR / s["dest"]
        print(f"\n--- [{idx}/{len(SHOTS_TO_RENDER)}] Xử lý {shot_id}: {s['title']} ---")

        if dest_p.exists() and dest_p.stat().st_size > 200000:
            print(f"    ✓ Đã tồn tại bản render LTX 2.3 hợp lệ: {dest_p.name} ({dest_p.stat().st_size / 1024:.1f} KB)")
            rendered_files.append((s, dest_p))
            continue

        img_p = BASE_DIR / s["image"]
        if not img_p.exists():
            print(f"    [!] Thiếu ảnh start frame: {img_p}")
            continue

        if client is None:
            print(f"    🚀 Đang kết nối tới Space: {LTX_SPACE_ID}...")
            client = Client(LTX_SPACE_ID, token=HF_TOKEN)
            print(f"    ✓ Kết nối thành công!")

        print(f"    🚀 Đang gọi LTX-2.3 High-Res ($1536 \\times 1024$) sinh video ({img_p.name})...")
        t0 = time.time()
        try:
            res = client.predict(
                input_image=handle_file(str(img_p)),
                prompt=s["prompt"],
                duration=3.0,
                enhance_prompt=False,
                seed=42,
                randomize_seed=False,
                height=1024,
                width=1536,
                api_name="/generate_video"
            )
            elapsed = time.time() - t0
            temp_vid = res[0]
            if temp_vid and Path(temp_vid).exists():
                shutil.copy2(temp_vid, str(dest_p))
                print(f"    ✓ Render thành công trong {elapsed:.1f}s -> {dest_p.name} ({dest_p.stat().st_size / 1024:.1f} KB)")
                rendered_files.append((s, dest_p))
            else:
                print(f"    [!] Space không trả về video hợp lệ: {res}")
        except Exception as e:
            print(f"    [!] Lỗi khi gọi LTX-2.3: {e}")

    return rendered_files

def standardize_clip(input_video: Path, output_video: Path):
    """Chuẩn hóa mọi clip về đúng tỷ lệ 16:9 1920x1080 24fps."""
    ffmpeg = get_ffmpeg()
    
    # Scale 1536x1024 (1.5:1) smoothly to 1920x1080 (16:9) with minor letterboxing or crop
    vf = "scale=1920:1080:force_original_aspect_ratio=increase,crop=1920:1080,fps=24"

    cmd = [
        ffmpeg, "-y",
        "-i", str(input_video),
        "-vf", vf,
        "-c:v", "libx264", "-preset", "fast", "-crf", "18",
        "-c:a", "aac", "-b:a", "192k", "-ar", "48000",
        "-movflags", "+faststart",
        str(output_video)
    ]
    subprocess.run(cmd, capture_output=True)
    return output_video.exists() and output_video.stat().st_size > 100000

def build_scene_master(rendered_files):
    if not rendered_files:
        print("[!] Không có clip nào để ghép nối.")
        return None

    print("\n" + "=" * 75)
    print("🎬 [GHÉP MASTER CẢNH 02 LTX-2.3] Chuẩn hóa và nối chuỗi toàn bộ 6 shot 16:9...")
    print("=" * 75)

    temp_dir = BASE_DIR / "04_Assets" / "temp_scene02_ltx23"
    temp_dir.mkdir(parents=True, exist_ok=True)

    std_clips = []
    for s_info, vid_path in rendered_files:
        std_out = temp_dir / f"std_{vid_path.name}"
        print(f"    • Chuẩn hóa 1920x1080 24fps: {vid_path.name}")
        ok = standardize_clip(vid_path, std_out)
        if ok:
            std_clips.append(std_out)

    if not std_clips:
        print("[!] Lỗi chuẩn hóa clip.")
        return None

    # Create concat list
    concat_list_file = temp_dir / "concat_list.txt"
    with open(concat_list_file, "w", encoding="utf-8") as f:
        for c in std_clips:
            clean_p = str(c).replace("\\", "/")
            f.write(f"file '{clean_p}'\n")

    raw_master = temp_dir / "scene02_ltx23_raw_concat.mp4"
    ffmpeg = get_ffmpeg()
    cmd_concat = [
        ffmpeg, "-y",
        "-f", "concat", "-safe", "0",
        "-i", str(concat_list_file),
        "-c", "copy",
        str(raw_master)
    ]
    subprocess.run(cmd_concat, capture_output=True)

    if not raw_master.exists() or raw_master.stat().st_size < 10000:
        print("[!] Lỗi khi concat clip.")
        return None

    print(f"    ✓ Đã ghép nối liên hoàn các shot LTX-2.3: {raw_master.stat().st_size / 1024 / 1024:.2f} MB")

    # Add BGM and Audio Normalization to -14.0 LUFS
    final_master_export = BASE_DIR / "06_Exports" / "ep01_scene02_ltx23_cinematic_master.mp4"
    final_master_video = BASE_DIR / "04_Assets" / "videos" / "ep01_scene02_master_v1.mp4"
    
    bgm_file = BASE_DIR / "04_Assets" / "audio" / "scene01_bgm.m4a"

    if bgm_file.exists():
        print(f"    🎵 Đang hòa âm BGM cổ phong ({bgm_file.name}) và foley ambient chuẩn hóa -14.0 LUFS...")
        cmd_master = [
            ffmpeg, "-y",
            "-i", str(raw_master),
            "-stream_loop", "-1", "-i", str(bgm_file),
            "-filter_complex",
            "[1:a]volume=0.32,afade=t=in:st=0:d=1.5[bgm];"
            "[0:a][bgm]amix=inputs=2:duration=first[a_mixed];"
            "[a_mixed]loudnorm=I=-14.0:LRA=7.0:TP=-1.5[a_out]",
            "-map", "0:v", "-map", "[a_out]",
            "-c:v", "copy",
            "-c:a", "aac", "-b:a", "192k", "-ar", "48000",
            "-shortest",
            str(final_master_export)
        ]
        res = subprocess.run(cmd_master, capture_output=True)
        if res.returncode != 0 or not final_master_export.exists():
            shutil.copy2(str(raw_master), str(final_master_export))
    else:
        shutil.copy2(str(raw_master), str(final_master_export))

    # Copy to 04_Assets/videos/ so Web Review indexes it
    shutil.copy2(str(final_master_export), str(final_master_video))

    print("\n" + "=" * 75)
    print(f"🎉 HOÀN TẤT XUẤT MASTER CẢNH 02 BẰNG LTX-2.3 22B DISTILLED!")
    print(f"   • File Master Exports: {final_master_export}")
    print(f"   • File Master Web:     {final_master_video}")
    print("=" * 75)
    return final_master_export

if __name__ == "__main__":
    rendered = render_all_shots()
    master = build_scene_master(rendered)
    if master:
        print(f"\n[✓] Thành công! Xem trực tiếp tại: http://localhost:1515")
