#!/usr/bin/env python3
"""
MONTAGE v4 — Professional 1-Minute Edit
Plan: Partenza → Terra → Mercato → Ritorno
12 clips, crossfades, Italian titles, music or ambient.
"""

import os, subprocess, re, sys, json, time
from pathlib import Path

HOME = Path.home()
INPUT = HOME / "Desktop" / "VideoFactory" / "Input"
WORK = HOME / "Desktop" / "VideoFactory" / "Work"
OUTPUT = HOME / "Desktop" / "VideoFactory" / "Output"
MUSIC_DIR = HOME / "Desktop" / "VideoFactory" / "Music"
VPS_PROXY = "http://157.173.122.51:18999"

# ─── EDL: 4 ACTS, 12 CLIPS, ~60s ───
# Поменяй под свои видео!
EDL = [
    ("document_example1.mp4", 5, "Vela",       "⛵ Partenza"),
    ("document_example2.mp4", 5, "Mare aperto","⛵ Partenza"),
    ("document_example3.mp4", 4, "Stromboli",  "⛵ Partenza"),
    ("document_example4.mp4", 4, "Costa",      "🏘️ Terra"),
    ("document_example5.mp4", 5, "Marina",     "🏘️ Terra"),
    ("document_example6.mp4", 5, "Centro",     "🏘️ Terra"),
    ("document_example7.mp4", 5, "Mercato",    "🏛️ Mercato"),
    ("document_example8.mp4", 6, "Palazzo",    "🏛️ Mercato"),
    ("document_example9.mp4", 5, "Porto",      "🏛️ Mercato"),
    ("document_example10.mp4",5, "Alto mare",  "🌊 Ritorno"),
    ("document_example11.mp4",5, "Orizzonte",  "🌊 Ritorno"),
    ("document_example12.mp4",6, "Tramonto",   "🌊 Ritorno"),
]

def log(msg): print(f"  {msg}")

def get_dur(path):
    r = subprocess.run(['ffmpeg', '-i', str(path)], capture_output=True, text=True, timeout=10)
    m = re.search(r'Duration: (\d+):(\d+):(\d+\.\d+)', r.stderr)
    return int(m.group(1))*3600 + int(m.group(2))*60 + float(m.group(3)) if m else 0

def render_clip(src, out, dur, title, act_label, idx):
    w, h = 720, 1280
    filters = [f"scale={w}:{h}:force_original_aspect_ratio=decrease"]
    filters.append(f"pad={w}:{h}:(ow-iw)/2:(oh-ih)/2:color=black")
    fd = min(0.3, dur/3)
    filters.append(f"fade=t=in:st=0:d={fd}")
    filters.append(f"fade=t=out:st={dur-fd}:d={fd}")
    safe = title.replace("'", "'\\\\''")
    filters.append(f"drawtext=text='{safe}':fontsize=28:fontcolor=white:x=(w-text_w)/2:y=h-th-45:box=1:boxcolor=black@0.3")
    vf = ",".join(filters)
    cmd = ['ffmpeg', '-y', '-i', str(src), '-t', str(dur), '-vf', vf, '-c:v', 'libx264', '-preset', 'ultrafast', '-crf', '23', '-c:a', 'aac', '-b:a', '96k', '-movflags', '+faststart', str(out)]
    subprocess.run(cmd, check=True, capture_output=True, timeout=180)
    log(f"[{idx+1}/{len(EDL)}] {src.name[:35]} → {dur}s «{title}»")

def crossfade_all(clips, output, fade=0.3):
    n = len(clips)
    inputs = []
    for c in clips: inputs.extend(['-i', str(c)])
    parts = [f"[{i}:v][{i}:a]" for i in range(n)]
    concat = f"{''.join(parts)}concat=n={n}:v=1:a=1[outv][outa]"
    cmd = ['ffmpeg', '-y'] + inputs + ['-filter_complex', concat, '-map', '[outv]', '-map', '[outa]', '-c:v', 'libx264', '-preset', 'ultrafast', '-crf', '20', '-c:a', 'aac', '-b:a', '128k', '-movflags', '+faststart', str(output)]
    subprocess.run(cmd, check=True, capture_output=True, timeout=600)

def add_fades(input_path, output_path, fi=0.5, fo=1.0):
    dur = get_dur(input_path)
    cmd = ['ffmpeg', '-y', '-i', str(input_path), '-vf', f"fade=t=in:st=0:d={fi},fade=t=out:st={dur-fo}:d={fo}", '-af', f"afade=t=in:st=0:d={fi},afade=t=out:st={dur-fo}:d={fo}", '-c:v', 'libx264', '-preset', 'ultrafast', '-crf', '20', '-c:a', 'aac', '-b:a', '128k', '-movflags', '+faststart', str(output_path)]
    subprocess.run(cmd, check=True, capture_output=True, timeout=300)

def gen_music(dur=65):
    """Suno music generation via kie.ai.

    ⚠️ callBackUrl must be a public URL (NOT localhost!).
    Without a working callback, credits are burned and track is lost.
    Uses ambient fallback automatically.
    """
    import requests
    try:
        r = requests.post(f"{VPS_PROXY}/api/v1/generate", json={"model":"V3_5","customMode":False,"gpt_description_prompt":"acoustic guitar mediterranean travel music, relaxing, instrumental","instrumental":True,"callBackUrl":"http://localhost:9999/cb"}, timeout=15)
        d = r.json()
        if d.get("code") == 200:
            log(f"🎵 Suno taskId={d['data']['taskId']} (ambient fallback used)")
        else:
            log(f"⚠️ Suno: {d.get('msg', d)}")
    except Exception as e:
        log(f"⚠️ Suno error: {e}")

def gen_ambient(out, dur=65):
    cmd = ['ffmpeg', '-y', '-f', 'lavfi', '-i', f"aevalsrc=sin(55*2*PI*t)*exp(-t/20)+sin(82.5*2*PI*t)*0.3*exp(-t/25)+sin(110*2*PI*t)*0.15:d={dur}", '-af', 'volume=0.06,lowpass=f=350', '-ac','2','-ar','44100', str(out)]
    subprocess.run(cmd, check=True, capture_output=True, timeout=60)

def mix_audio(vid, mus, out):
    dur = get_dur(vid)
    cmd = ['ffmpeg','-y','-i',str(vid),'-i',str(mus),'-filter_complex',f"[1:a]afade=t=in:st=0:d=2,afade=t=out:st={dur-2}:d=2,volume=0.3[mus];[0:a][mus]amix=inputs=2:duration=first:weights=1 0.7[audio]",'-map','0:v','-map','[audio]','-c:v','copy','-c:a','aac','-b:a','128k','-movflags','+faststart',str(out)]
    subprocess.run(cmd, check=True, capture_output=True, timeout=300)

def main():
    print("🎬 MONTAGE v4 — PROFESSIONAL 1-MIN EDIT")
    seg_dir = WORK / "segments_v4"; seg_dir.mkdir(parents=True, exist_ok=True)
    raw_total = sum(d for _,d,_,_ in EDL)
    print(f"\n📋 EDL: {len(EDL)} clips, {raw_total}s raw → ~60s")
    clips = []
    for i,(fname,dur,title,act) in enumerate(EDL):
        src = INPUT / fname
        if not src.exists(): log(f"⚠️ MISSING: {fname}"); continue
        out = seg_dir / f"seg_{i:02d}.mp4"
        render_clip(src, out, dur, title, act, i); clips.append(out)
    concat_raw = WORK / "_concat_v4.mp4"; crossfade_all(clips, concat_raw)
    print(f"   → {get_dur(concat_raw):.0f}s")
    faded = WORK / "_faded_v4.mp4"; add_fades(concat_raw, faded)
    dur = int(get_dur(faded)) + 3; gen_music(dur)
    ambient = WORK / "_ambient.wav"; gen_ambient(ambient, dur)
    final = OUTPUT / "final_montage.mp4"; mix_audio(faded, ambient, final)
    fd = get_dur(final); fs = os.path.getsize(final)/1024/1024
    print(f"\n🎉 DONE! {fd:.0f}s, {fs:.0f}MB → {final}")

if __name__ == "__main__": main()
