#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
=============================================================================
KIEU STORY — EP01 GRAND FEATURE MASTER ASSEMBLER (25-30 PHÚT)
=============================================================================
Ghép nối toàn bộ 15 phân cảnh (C01 - C15: 188 shots) thành bản Master hoàn chỉnh
thời lượng 25-30 phút (Full Feature 188 Shots) chuẩn điện ảnh.
Tuân thủ Directive 2026-10-08T05:38:03Z về quy tắc versioning _v*.
=============================================================================
"""

import os
import sys
import re
import argparse
import subprocess
from pathlib import Path
from typing import List, Optional, Tuple, Dict

# Ensure UTF-8 on Windows
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
EXPORTS_DIR = BASE_DIR / "06_Exports"
VIDEOS_DIR = BASE_DIR / "04_Assets" / "videos"
EXPORTS_DIR.mkdir(parents=True, exist_ok=True)

# Default versioned master output
output_master = EXPORTS_DIR / "thap_ngu_nien_ep01_grand_feature_master_v1.mp4"

# Danh mục đầy đủ 15 phân cảnh EP01 (C01 đến C15: 188 shots)
EP01_SCENE_IDS = [
    "ep01_scene01",
    "ep01_scene02",
    "ep01_scene03",
    "ep01_scene04",
    "ep01_scene05",
    "ep01_scene06",
    "ep01_scene07",
    "ep01_scene08",
    "ep01_scene09",
    "ep01_scene10",
    "ep01_scene11",
    "ep01_scene12",
    "ep01_scene13",
    "ep01_scene14",
    "ep01_scene15",
]

# Thành phần mở đầu cố định (Chuẩn Điện Ảnh: Intro 20s -> Fadedown -> Blackout 5s Hold -> Fadeup -> Prologue 40s)
INTRO_PARTS = [
    VIDEOS_DIR / "thap_ngu_nien_intro_complete_20s.mp4",
    VIDEOS_DIR / "cinematic_blackout_5s.mp4",
    VIDEOS_DIR / "prologue_hoai_niem_198x_to_gia_tinh_40s.mp4"
]


def resolve_scene_part(scene_id: str) -> Optional[Path]:
    """
    Tìm kiếm file master phân cảnh theo thứ tự ưu tiên:
    1. 06_Exports/<scene_id>_master_audio_v*.mp4 (phiên bản cao nhất)
    2. 06_Exports/<scene_id>_cinematic_master_v*.mp4 (phiên bản cao nhất)
    3. 06_Exports/<scene_id>_master_audio.mp4
    4. 06_Exports/<scene_id>_cinematic_master.mp4
    5. 06_Exports/<scene_id>_master_v*.mp4
    6. 06_Exports/<scene_id>_master.mp4
    7. 04_Assets/videos/<scene_id>*master*.mp4
    """
    candidates = []

    # 1. Quét master_audio trong 06_Exports
    for p in EXPORTS_DIR.glob(f"{scene_id}_master_audio*.mp4"):
        if p.is_file() and p.stat().st_size > 1000:
            candidates.append(p)

    # 2. Quét cinematic master trong 06_Exports
    for p in EXPORTS_DIR.glob(f"{scene_id}_cinematic_master*.mp4"):
        if p.is_file() and p.stat().st_size > 1000:
            candidates.append(p)

    # 3. Quét master thông thường trong 06_Exports
    for p in EXPORTS_DIR.glob(f"{scene_id}_master*.mp4"):
        if p.is_file() and p.stat().st_size > 1000:
            candidates.append(p)

    # 4. Quét trong 04_Assets/videos
    for p in VIDEOS_DIR.glob(f"{scene_id}*master*.mp4"):
        if p.is_file() and p.stat().st_size > 1000:
            candidates.append(p)

    if candidates:
        def sort_key(p: Path):
            m = re.search(r'_v(\d+)\.mp4$', p.name, re.IGNORECASE)
            version_num = int(m.group(1)) if m else 0
            lname = p.name.lower()
            if "master_audio" in lname:
                type_score = 4
            elif "cinematic_master" in lname:
                type_score = 3
            elif p.parent == EXPORTS_DIR:
                type_score = 2
            else:
                type_score = 1
            return (type_score, version_num, p.stat().st_mtime)

        candidates.sort(key=sort_key, reverse=True)
        return candidates[0]

    # Fallback đường dẫn mặc định chuẩn versioning
    return EXPORTS_DIR / f"{scene_id}_master_audio_v1.mp4"


def get_ep01_assembly_parts(num_scenes: int = 10, include_intro: bool = False) -> List[Tuple[str, Path, bool]]:
    """
    Trả về danh sách các thành phần cấu thành EP01 Feature Cut:
    - num_scenes = 10: Chiến dịch tái sản xuất 10 cảnh (Scenes 01-10, 140 shots = 23m20s).
    - num_scenes = 15: Grand Feature 15 cảnh (188 shots = 25-30 phút).
    """
    resolved_parts = []

    # Intro và Prologue (chỉ nạp khi include_intro=True)
    if include_intro:
        for intro_path in INTRO_PARTS:
            resolved_parts.append((intro_path.stem, intro_path, intro_path.exists()))

    # Danh mục scenes theo num_scenes
    target_scenes = EP01_SCENE_IDS[:num_scenes] if num_scenes else EP01_SCENE_IDS
    for sc_id in target_scenes:
        target_path = resolve_scene_part(sc_id)
        exists = target_path.exists() if target_path else False
        resolved_parts.append((sc_id, target_path, exists))

    return resolved_parts


def assemble_grand_feature(
    ep: str = "ep01",
    num_scenes: int = 10,
    include_intro: bool = False,
    dry_run: bool = False,
    check: bool = False,
    output_path: Optional[str] = None,
    version: Optional[str] = None
) -> bool:
    """
    Hàm thực thi ghép nối các phân cảnh thành Feature Master hoàn chỉnh.
    Hỗ trợ 10 cảnh chiến dịch (Scenes 01-10) hoặc 15 cảnh (Full Feature).
    """
    parts_info = get_ep01_assembly_parts(num_scenes=num_scenes, include_intro=include_intro)

    # Xác định đường dẫn xuất
    v_tag = version if (version and version.startswith("v")) else f"v{version or 1}"
    if output_path:
        out_file = Path(output_path)
    elif num_scenes == 10:
        out_file = EXPORTS_DIR / f"{ep}_full_feature_master_{v_tag}.mp4"
    else:
        out_file = EXPORTS_DIR / f"thap_ngu_nien_{ep}_grand_feature_master_{v_tag}.mp4"

    print("=" * 80)
    print(f"🎬 KIEU STORY AI CINEMA — GRAND FEATURE MASTER ASSEMBLER ({ep.upper()})")
    print(f"   Quy mô phân cảnh: {num_scenes} Cảnh ({len(parts_info)} thành phần)")
    print(f"   Tập tin đích: {out_file}")
    print("=" * 80)

    missing = []
    available = []
    for tag, p, exists in parts_info:
        status_icon = "✓" if exists else "✗"
        print(f"  [{status_icon}] {tag:<25} -> {p.name if p else 'N/A'}")
        if exists:
            available.append(p)
        else:
            missing.append((tag, p))

    print("-" * 80)
    print(f"Tổng thành phần: {len(parts_info)} | Sẵn sàng: {len(available)} | Thiếu: {len(missing)}")

    if check:
        print("[✓] Chế độ kiểm tra (--check): Báo cáo trạng thái hoàn tất.")
        return True

    if dry_run:
        print("\n[*] Chế độ mô phỏng (--dry-run):")
        print(f"    Thành phần dự kiến ghép nối: {len(parts_info)} file")
        sample_inputs = " ".join([f"-i {p.name}" for _, p, _ in parts_info[:3]]) + f" ... [{len(parts_info)} scenes]"
        print(f"    Lệnh FFmpeg mẫu: ffmpeg -y {sample_inputs} -filter_complex ... {out_file.name}")
        print("[✓] Mô phỏng thành công.")
        return True

    if missing:
        print(f"\n[!] Cảnh báo: Có {len(missing)} thành phần chưa được render hoặc chưa tồn tại:")
        for tag, p in missing:
            print(f"    - {tag}: {p}")
        print("[!] Không thể ghép nối toàn vẹn khi thiếu cảnh. Vui lòng render trước khi xuất bản chính thức.")
        return False

    # Triển khai lệnh FFmpeg ghép nối
    try:
        from audio_continuity_engine import get_ffmpeg, AudioContinuityEngine
        ffmpeg_exe = get_ffmpeg()
    except ImportError:
        ffmpeg_exe = "ffmpeg"
        AudioContinuityEngine = None

    inputs = []
    filter_parts = []
    format_filters = []
    for i, p in enumerate(available):
        inputs.extend(["-i", str(p)])
        format_filters.append(f"[{i}:v:0]format=yuv420p,setsar=1[v{i}];")
        filter_parts.append(f"[v{i}][{i}:a:0]")

    n = len(available)
    concat_filter = f"{''.join(format_filters)}{''.join(filter_parts)}concat=n={n}:v=1:a=1[v][a]"
    raw_target = out_file.parent / f"{out_file.stem}_raw{out_file.suffix}"

    cmd = [
        ffmpeg_exe, "-y",
        *inputs,
        "-filter_complex", concat_filter,
        "-map", "[v]",
        "-map", "[a]",
        "-c:v", "libx264",
        "-crf", "18",
        "-preset", "slow",
        "-pix_fmt", "yuv420p",
        "-c:a", "aac",
        "-b:a", "192k",
        "-ar", "48000",
        str(raw_target)
    ]

    print(f"\n[*] Đang ghép nối toàn bộ {n} thành phần thành Feature Master...")
    res = subprocess.run(cmd, capture_output=True, text=True)

    if res.returncode == 0 and raw_target.exists():
        # Chuẩn hóa âm thanh EBU R128 Two-Pass Linear
        if AudioContinuityEngine is not None:
            engine = AudioContinuityEngine()
            norm_ok = engine.normalize_loudness(
                str(raw_target),
                str(out_file),
                target_lufs=-14.0,
                target_tp=-1.0,
                target_lra=9.0,
                two_pass=True
            )
            if norm_ok and out_file.exists():
                if raw_target.exists():
                    try:
                        raw_target.unlink()
                    except Exception:
                        pass
            else:
                raw_target.rename(out_file)
        else:
            raw_target.rename(out_file)

        size_mb = out_file.stat().st_size / (1024 * 1024)
        print(f"\n[✓] GHÉP THÀNH CÔNG GRAND FEATURE MASTER TẬP 1 ({num_scenes} Cảnh)!")
        print(f"    File: {out_file.name}")
        print(f"    Dung lượng: {size_mb:.2f} MB")
        return True
    else:
        print(f"[!] Lỗi khi ghép nối:\n{res.stderr}")
        return False


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Ghép nối các phân cảnh EP01 thành Grand Feature Master 25-30 phút (Full Feature 188 Shots)"
    )
    parser.add_argument("--check", action="store_true", help="Kiểm tra trạng thái các phân cảnh mà không thực thi ghép nối")
    parser.add_argument("--dry-run", action="store_true", help="Mô phỏng quy trình ghép nối và hiển thị pipeline")
    parser.add_argument("--output", type=str, default=None, help="Đường dẫn file MP4 xuất bản")
    parser.add_argument("--version", type=str, default=None, help="Phiên bản versioning (ví dụ: v1, v2)")
    parser.add_argument("--scenes", type=int, default=10, help="Số lượng phân cảnh cần ghép (10 cho chiến dịch Ep01, 15 cho Grand Feature)")
    parser.add_argument("--include-intro", action="store_true", help="Kèm theo intro và prologue")

    args = parser.parse_args()

    success = assemble_grand_feature(
        ep="ep01",
        num_scenes=args.scenes,
        include_intro=args.include_intro,
        dry_run=args.dry_run,
        check=args.check,
        output_path=args.output,
        version=args.version
    )

    if not success and not (args.check or args.dry_run):
        sys.exit(1)
    sys.exit(0)
