#!/usr/bin/env python3
"""
Pipeline de render SIMPLIFICADO para self-whatsapp_business_management.mp4
Sem zoompan (muito lento) - usa crop fixo + blend para transicao suave
"""

import subprocess
import os
import sys

INPUT = '/opt/mia/workspace/videos/meta_self_tech_provider/Gravando 2026-09-02 121803.mp4'
WORK_DIR = '/opt/mia/workspace/videos/meta_self_tech_provider/renders'
OUTPUT = '/opt/mia/workspace/videos/meta_self_tech_provider/self-whatsapp_business_management.mp4'
FONT = '/home/mia/.fonts/px3lab/Inter-Bold.ttf'

os.makedirs(WORK_DIR, exist_ok=True)

def run(cmd, desc):
    print(f"\n=== {desc} ===", flush=True)
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        print(f"STDOUT: {result.stdout[-500:]}", flush=True)
        print(f"STDERR: {result.stderr[-1000:]}", flush=True)
        sys.exit(1)
    # Mostrar ultima linha do stderr (progresso)
    if result.stderr:
        lines = [l for l in result.stderr.split('\n') if l.strip()]
        if lines:
            print(f"  -> {lines[-1]}", flush=True)
    print(f"OK - {desc}", flush=True)
    return result

def ffprobe_duration(path):
    r = subprocess.run(
        ['ffprobe', '-v', 'quiet', '-show_format', '-of', 'json', path],
        capture_output=True, text=True
    )
    import json
    try:
        return float(json.loads(r.stdout)['format']['duration'])
    except:
        return 0

# ============================================================
# Parametros de zoom
# crop 1.3x: viewport = 1920/1.3 x 1080/1.3 = 1476 x 830 (valores pares)
# Offset: x=443 (centrado no formulario direito), y=0
# ============================================================
CW = 1476  # crop width (par)
CH = 830   # crop height (par)
CX = 443   # crop x offset
CY = 0     # crop y offset

# ============================================================
# TIMINGS (segundos no video original)
# ============================================================
# Sem zoom: 0 - 27s
# Zoom on: 28 - 82s (legendas 3, 4, 5)
# Sem zoom: 82 - fim

# Transicao: 0.5s (15 frames) de blend entre normal e zoomed
# Ramp in: 27.0 - 27.5s
# Zoom hold: 27.5 - 82.0s
# Ramp out: 82.0 - 82.5s

T_ZOOM_START = 27.0
T_RAMP_DONE  = 27.5   # ramp in completo
T_RAMP_OUT   = 82.0   # inicio ramp out
T_ZOOM_END   = 82.5   # zoom totalmente off

# ============================================================
# ESTRATEGIA: blend entre normal e zoomed para a rampa
# ffmpeg blend filter: all_expr='A*(1-T/N)+B*(T/N)'
# onde T = frame index (0-based), N = total frames
# ============================================================

RAMP_DUR = 0.5     # duracao da rampa em segundos
RAMP_FRAMES = 15   # 0.5s * 30fps

# ============================================================
# SEGMENTO 1: 0 a 27s - sem zoom (scale simples)
# ============================================================
seg1 = f'{WORK_DIR}/seg1.mp4'
if not os.path.exists(seg1) or os.path.getsize(seg1) < 1000:
    run([
        'ffmpeg', '-y',
        '-i', INPUT,
        '-t', str(T_ZOOM_START),
        '-vf', 'scale=1920:1080',
        '-r', '30', '-c:v', 'libx264', '-crf', '17', '-preset', 'fast', '-an',
        seg1
    ], f'Seg1 (0-{T_ZOOM_START}s sem zoom)')
else:
    print(f"Seg1 ja existe ({os.path.getsize(seg1)} bytes), pulando")

# ============================================================
# SEGMENTO RAMP IN: 27.0 - 27.5s (blend normal->zoomed)
# ============================================================
seg_ramp_in = f'{WORK_DIR}/seg_ramp_in.mp4'
if not os.path.exists(seg_ramp_in) or os.path.getsize(seg_ramp_in) < 1000:
    # A = normal, B = zoomed -> blend vai de A para B
    run([
        'ffmpeg', '-y',
        '-ss', str(T_ZOOM_START), '-t', str(RAMP_DUR),
        '-i', INPUT,
        '-ss', str(T_ZOOM_START), '-t', str(RAMP_DUR),
        '-i', INPUT,
        '-filter_complex', (
            f'[0:v]scale=1920:1080[normal];'
            f'[1:v]scale=1920:1080,crop={CW}:{CH}:{CX}:{CY},scale=1920:1080[zoomed];'
            f'[normal][zoomed]blend=all_expr=\'A*(1-T/{RAMP_FRAMES-1})+B*(T/{RAMP_FRAMES-1})\'[out]'
        ),
        '-map', '[out]',
        '-r', '30', '-c:v', 'libx264', '-crf', '17', '-preset', 'fast', '-an',
        seg_ramp_in
    ], f'Ramp in ({T_ZOOM_START}-{T_RAMP_DONE}s blend normal->zoom)')
else:
    print(f"Ramp in ja existe, pulando")

# ============================================================
# SEGMENTO ZOOM: 27.5 - 82.0s - zoom fixo 1.3x (crop simples)
# ============================================================
seg_zoom = f'{WORK_DIR}/seg_zoom.mp4'
zoom_dur = T_RAMP_OUT - T_RAMP_DONE
if not os.path.exists(seg_zoom) or os.path.getsize(seg_zoom) < 1000:
    run([
        'ffmpeg', '-y',
        '-ss', str(T_RAMP_DONE), '-t', str(zoom_dur),
        '-i', INPUT,
        '-vf', f'scale=1920:1080,crop={CW}:{CH}:{CX}:{CY},scale=1920:1080',
        '-r', '30', '-c:v', 'libx264', '-crf', '17', '-preset', 'fast', '-an',
        seg_zoom
    ], f'Seg zoom ({T_RAMP_DONE}-{T_RAMP_OUT}s crop fixo 1.3x)')
else:
    print(f"Seg zoom ja existe, pulando")

# ============================================================
# SEGMENTO RAMP OUT: 82.0 - 82.5s (blend zoomed->normal)
# ============================================================
seg_ramp_out = f'{WORK_DIR}/seg_ramp_out.mp4'
if not os.path.exists(seg_ramp_out) or os.path.getsize(seg_ramp_out) < 1000:
    # A = zoomed, B = normal -> blend vai de A para B
    run([
        'ffmpeg', '-y',
        '-ss', str(T_RAMP_OUT), '-t', str(RAMP_DUR),
        '-i', INPUT,
        '-ss', str(T_RAMP_OUT), '-t', str(RAMP_DUR),
        '-i', INPUT,
        '-filter_complex', (
            f'[0:v]scale=1920:1080,crop={CW}:{CH}:{CX}:{CY},scale=1920:1080[zoomed];'
            f'[1:v]scale=1920:1080[normal];'
            f'[zoomed][normal]blend=all_expr=\'A*(1-T/{RAMP_FRAMES-1})+B*(T/{RAMP_FRAMES-1})\'[out]'
        ),
        '-map', '[out]',
        '-r', '30', '-c:v', 'libx264', '-crf', '17', '-preset', 'fast', '-an',
        seg_ramp_out
    ], f'Ramp out ({T_RAMP_OUT}-{T_ZOOM_END}s blend zoom->normal)')
else:
    print(f"Ramp out ja existe, pulando")

# ============================================================
# SEGMENTO 3: 82.5s ate o fim - sem zoom
# ============================================================
seg3 = f'{WORK_DIR}/seg3.mp4'
if not os.path.exists(seg3) or os.path.getsize(seg3) < 1000:
    run([
        'ffmpeg', '-y',
        '-ss', str(T_ZOOM_END),
        '-i', INPUT,
        '-vf', 'scale=1920:1080',
        '-r', '30', '-c:v', 'libx264', '-crf', '17', '-preset', 'fast', '-an',
        seg3
    ], f'Seg3 ({T_ZOOM_END}s-fim sem zoom)')
else:
    print(f"Seg3 ja existe, pulando")

# ============================================================
# VERIFICAR DURACOES
# ============================================================
segs = [seg1, seg_ramp_in, seg_zoom, seg_ramp_out, seg3]
total = 0
for s in segs:
    d = ffprobe_duration(s)
    total += d
    sz = os.path.getsize(s) // 1024
    print(f"  {os.path.basename(s)}: {d:.2f}s ({sz}KB)")
print(f"Total esperado: ~102.5s | Total calculado: {total:.2f}s")

# ============================================================
# CONCAT DOS SEGMENTOS
# ============================================================
concat_list = f'{WORK_DIR}/concat.txt'
with open(concat_list, 'w') as f:
    for seg in segs:
        f.write(f"file '{seg}'\n")

concat_out = f'{WORK_DIR}/concat_out.mp4'
run([
    'ffmpeg', '-y',
    '-f', 'concat', '-safe', '0',
    '-i', concat_list,
    '-c', 'copy',
    concat_out
], 'Concat de todos os segmentos')

d = ffprobe_duration(concat_out)
print(f"Concat final: {d:.2f}s (esperado ~102.5s)")

# ============================================================
# PASS 2: Legendas com drawtext
#
# TIMINGS (segundos - apos concat, mesmos do original):
#   L1: 0.0  - 17.0s  (single) login + painel carregando
#   L2: 22.0 - 27.0s  (single) aba WhatsApp aberta com lista
#   L3: 28.0 - 46.0s  (double) preenchimento formulario (com zoom)
#   L4: 46.0 - 63.0s  (single) corpo + variaveis + exemplos (com zoom)
#   --: 63.0 - 76.0s  (sem legenda) RASCUNHO -> Submeter -> SUBMETIDO
#   L5: 76.0 - 82.0s  (double) SUBMETIDO na lista (com zoom)
#   L6: 82.0 - 102.5s (single) WhatsApp Manager
#
# NOTA IMPORTANTE: os timings do concat mudam levemente por causa dos segmentos
# A diferenca e desprezivel (< 0.1s) pois nao cortamos nada, apenas zoom
# ============================================================

# Estilo
FS = 46        # font size
TC = 'white'   # text color
BC = '0x000000@0.87'  # box color preto 87%
BP = 20        # box padding

# Posicoes Y (validadas com teste visual)
YS = 940    # single line
YD1 = 920   # double line 1
YD2 = 978   # double line 2

def dt(text, t0, t1, y):
    """Gera filtro drawtext."""
    esc = text.replace("'", "\\'").replace(':', '\\:')
    return (
        f"drawtext=fontfile='{FONT}'"
        f":text='{esc}'"
        f":fontcolor={TC}:fontsize={FS}"
        f":box=1:boxcolor={BC}:boxborderw={BP}"
        f":x=(w-text_w)/2:y={y}"
        f":enable='between(t,{t0},{t1})'"
    )

# Construir cadeia de filtros
filters = ','.join([
    # L1
    dt('This is Self, our platform for graduation companies in Brazil.', 0, 17, YS),
    # L2
    dt('Our clients manage their WhatsApp message templates here.', 22, 27, YS),
    # L3 linha 1
    dt('Our app uses whatsapp_business_management to create message', 28, 46, YD1),
    # L3 linha 2
    dt('templates on behalf of our clients.', 28, 46, YD2),
    # L4
    dt('Variables are filled per student, so each message is personalized.', 46, 63, YS),
    # L5 linha 1
    dt('The template is submitted to Meta through the API, and our platform', 76, 82, YD1),
    # L5 linha 2
    dt('reads the approval status so it only sends what Meta approved.', 76, 82, YD2),
    # L6
    dt('The same template, now visible in WhatsApp Manager.', 82, 102.5, YS),
])

run([
    'ffmpeg', '-y',
    '-i', concat_out,
    '-vf', filters,
    '-c:v', 'libx264', '-crf', '18', '-preset', 'fast',
    '-profile:v', 'high', '-level', '4.1',
    '-an',
    '-movflags', '+faststart',
    OUTPUT
], 'Pass 2: legendas burnadas')

# ============================================================
# VALIDACAO FINAL
# ============================================================
print("\n=== VALIDACAO FINAL ===", flush=True)
r = subprocess.run(
    ['ffprobe', '-v', 'quiet', '-show_streams', '-show_format', '-of', 'json', OUTPUT],
    capture_output=True, text=True
)
import json
data = json.loads(r.stdout)
fmt = data['format']
streams = data['streams']

print(f"Arquivo: {OUTPUT}")
print(f"Duracao: {float(fmt['duration']):.2f}s (esperado ~102.5s)")
print(f"Tamanho: {int(fmt['size']) // 1024 // 1024}MB")
print(f"Streams: {len(streams)}")
for s in streams:
    if s['codec_type'] == 'video':
        print(f"  Video: {s['codec_name']} {s['width']}x{s['height']} {s.get('r_frame_rate','?')}fps")
    else:
        print(f"  Audio: {s['codec_name']} (PROBLEMA - deve ser removido!)")

if len(streams) == 1 and streams[0]['codec_type'] == 'video':
    w = streams[0]['width']
    h = streams[0]['height']
    if w == 1920 and h == 1080:
        print("\nTUDO OK: 1920x1080, sem audio, H.264")
    else:
        print(f"\nAVISO: resolucao {w}x{h} (esperado 1920x1080)")
else:
    print("\nERRO: streams incorretos!")
