#!/usr/bin/env python3
"""Utilitários de montagem de vídeo via FFmpeg."""

import json
import shutil
import subprocess
from pathlib import Path


def run(cmd: list, check: bool = False) -> subprocess.CompletedProcess:
    """Executa um comando FFmpeg e retorna o resultado."""
    result = subprocess.run(cmd, capture_output=True, text=True)
    if check and result.returncode != 0:
        raise RuntimeError(f"FFmpeg falhou: {result.stderr[-500:]}")
    return result


def get_duracao(path: str) -> float:
    """Retorna duração do arquivo em segundos."""
    result = subprocess.run(
        ["ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", path],
        capture_output=True, text=True
    )
    if result.returncode != 0:
        return 0.0
    data = json.loads(result.stdout)
    return float(data["format"].get("duration", 0))


def cortar_segmentos(video_path: str, segmentos: list, job_id: str) -> str:
    """Corta e une segmentos selecionados em um único arquivo."""
    temp_dir = Path(video_path).parent
    clips = []

    for i, seg in enumerate(segmentos):
        clip = str(temp_dir / f"{job_id}_seg_{i}.mp4")
        run([
            "ffmpeg", "-y", "-i", video_path,
            "-ss", str(seg["inicio"]),
            "-to", str(seg["fim"]),
            "-c", "copy", clip
        ])
        if Path(clip).exists():
            clips.append(clip)

    if not clips:
        return video_path

    if len(clips) == 1:
        return clips[0]

    lista = str(temp_dir / f"{job_id}_lista_segs.txt")
    with open(lista, "w") as f:
        for c in clips:
            f.write(f"file '{c}'\n")

    output = str(temp_dir / f"{job_id}_cortado.mp4")
    run([
        "ffmpeg", "-y", "-f", "concat", "-safe", "0",
        "-i", lista, "-c", "copy", output
    ], check=True)
    return output


def gerar_legenda_srt(segmentos: list, srt_path: str):
    """Gera arquivo .srt a partir dos segmentos do Whisper."""
    def fmt(s: float) -> str:
        h = int(s // 3600)
        m = int((s % 3600) // 60)
        ss = s % 60
        return f"{h:02d}:{m:02d}:{ss:06.3f}".replace(".", ",")

    with open(srt_path, "w", encoding="utf-8") as f:
        for i, seg in enumerate(segmentos, 1):
            f.write(f"{i}\n")
            f.write(f"{fmt(seg['inicio'])} --> {fmt(seg['fim'])}\n")
            f.write(f"{seg['texto']}\n\n")


def converter_9_16(input_path: str, output_path: str, sem_audio: bool = False):
    """Converte vídeo para 9:16 (1080x1920) com letterbox."""
    vf = "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black"
    cmd = ["ffmpeg", "-y", "-i", input_path, "-vf", vf]
    if sem_audio:
        cmd += ["-an"]
    else:
        cmd += ["-c:a", "copy"]
    cmd.append(output_path)
    run(cmd, check=True)


def montar_video_final(
    video_principal: str,
    clips_broll: list,
    transcricao: dict,
    musica_path: str,
    estilo_legenda: str,
    job_id: str,
    output_path: str
):
    """
    Pipeline de montagem:
    1. Converte principal para 9:16
    2. Gera SRT
    3. Intercala B-rolls (vídeo de apoio com áudio do principal)
    4. Queima legendas
    5. Adiciona música de fundo (volume 12%)
    """
    temp_dir = Path(video_principal).parent

    # --- Passo 1: principal 9:16 ---
    principal_9_16 = str(temp_dir / f"{job_id}_main_9_16.mp4")
    converter_9_16(video_principal, principal_9_16, sem_audio=False)
    duracao_total = get_duracao(principal_9_16)

    # --- Passo 2: SRT ---
    srt_path = str(temp_dir / f"{job_id}.srt")
    # Escapa o caminho para o filtro subtitles (dois-pontos e backslash)
    srt_escaped = srt_path.replace("\\", "\\\\").replace(":", "\\:")
    gerar_legenda_srt(transcricao.get("segmentos", []), srt_path)

    # Estilo de legenda
    if estilo_legenda == "amarela":
        style = "FontSize=20,PrimaryColour=&H00FFFF,OutlineColour=&H000000,Outline=2,Bold=1,Alignment=2"
    elif estilo_legenda == "karaoke":
        style = "FontSize=20,PrimaryColour=&HFFFFFF,SecondaryColour=&H00FFFF,OutlineColour=&H000000,Outline=2,Bold=1,Alignment=2"
    else:  # branca
        style = "FontSize=20,PrimaryColour=&HFFFFFF,OutlineColour=&H000000,Outline=2,Bold=1,Alignment=2"

    subtitles_filter = f"subtitles={srt_escaped}:force_style='{style}'"

    # --- Passo 3: montar com B-rolls ---
    if clips_broll:
        # Converte b-rolls para 9:16 sem áudio
        broll_convertidos = []
        for i, bp in enumerate(clips_broll[:5]):
            if not Path(bp).exists():
                continue
            broll_out = str(temp_dir / f"{job_id}_broll_{i}_9_16.mp4")
            converter_9_16(bp, broll_out, sem_audio=True)
            if Path(broll_out).exists():
                broll_convertidos.append(broll_out)

        if broll_convertidos:
            # Extrai áudio do principal
            audio_path = str(temp_dir / f"{job_id}_audio.aac")
            run(["ffmpeg", "-y", "-i", principal_9_16, "-vn", "-acodec", "copy", audio_path])
            if not Path(audio_path).exists():
                # tenta com recodificação
                run(["ffmpeg", "-y", "-i", principal_9_16, "-vn", "-acodec", "aac", audio_path])

            # Monta timeline: 8s principal, 5s b-roll
            INTERVAL_MAIN = 8.0
            INTERVAL_BROLL = 5.0
            clips_v = []
            t = 0.0
            broll_idx = 0

            while t < duracao_total:
                fim = min(t + INTERVAL_MAIN, duracao_total)
                clip_v = str(temp_dir / f"{job_id}_tl_{len(clips_v)}_main.mp4")
                run([
                    "ffmpeg", "-y", "-i", principal_9_16,
                    "-ss", str(t), "-to", str(fim),
                    "-an", clip_v
                ])
                if Path(clip_v).exists():
                    clips_v.append(clip_v)
                t = fim

                if t < duracao_total and broll_idx < len(broll_convertidos):
                    # Pega o b-roll e limita sua duracao
                    br = broll_convertidos[broll_idx % len(broll_convertidos)]
                    br_dur = min(get_duracao(br), INTERVAL_BROLL, duracao_total - t)
                    if br_dur > 0.5:
                        br_clip = str(temp_dir / f"{job_id}_tl_{len(clips_v)}_br.mp4")
                        run([
                            "ffmpeg", "-y", "-i", br,
                            "-t", str(br_dur),
                            "-an", br_clip
                        ])
                        if Path(br_clip).exists():
                            clips_v.append(br_clip)
                    broll_idx += 1

            # Concatena vídeo sem áudio
            lista_v = str(temp_dir / f"{job_id}_lista_v.txt")
            with open(lista_v, "w") as f:
                for c in clips_v:
                    f.write(f"file '{c}'\n")

            video_sem_audio = str(temp_dir / f"{job_id}_sem_audio.mp4")
            run([
                "ffmpeg", "-y", "-f", "concat", "-safe", "0",
                "-i", lista_v, "-c", "copy", video_sem_audio
            ], check=True)

            # Reaplica áudio
            video_com_audio = str(temp_dir / f"{job_id}_com_audio.mp4")
            run([
                "ffmpeg", "-y",
                "-i", video_sem_audio, "-i", audio_path,
                "-c:v", "copy", "-c:a", "aac",
                "-shortest", video_com_audio
            ], check=True)

            video_para_legenda = video_com_audio
        else:
            video_para_legenda = principal_9_16
    else:
        video_para_legenda = principal_9_16

    # --- Passo 4: queima legendas ---
    video_legendado = str(temp_dir / f"{job_id}_legendado.mp4")
    r = run([
        "ffmpeg", "-y", "-i", video_para_legenda,
        "-vf", subtitles_filter,
        "-c:a", "copy", video_legendado
    ])
    if r.returncode != 0 or not Path(video_legendado).exists():
        # fallback sem legendas
        print(f"[ffmpeg] Aviso: falha ao gravar legendas ({r.stderr[-300:]}). Continuando sem elas.")
        video_legendado = video_para_legenda

    # --- Passo 5: música de fundo ---
    if musica_path and Path(musica_path).exists():
        run([
            "ffmpeg", "-y",
            "-i", video_legendado, "-i", musica_path,
            "-filter_complex",
            "[1:a]volume=0.12[music];[0:a][music]amix=inputs=2:duration=first[aout]",
            "-map", "0:v", "-map", "[aout]",
            "-c:v", "copy", "-c:a", "aac",
            "-shortest", output_path
        ], check=True)
    else:
        shutil.copy(video_legendado, output_path)
