"""
Gera legenda estilo karaoke word-by-word para o piloto Borrello.

- Cada "cue" do SRT cobre uma palavra so, com todas as palavras do chunk
  visiveis. A palavra ativa fica destacada em laranja (via ASS override).
- Usa ASS (Advanced SubStation Alpha) em vez de SRT simples para
  suportar coloracao por palavra.
- Chunks de 3-5 palavras (quebra em pontuacao ou silencio >= 0.4s).
- Fonte: Liberation Sans Bold (disponivel no Ubuntu) ou Helvetica.
- Cor highlight: &H0016A3F9 (laranja #F97316 em BGR do ASS).
- Cor base: &H00FFFFFF (branco).
- Posicao: 75% da altura = MarginV calcula como PlayResY * (1-0.75) = 480 em 1920.
  Mas o MarginV no ASS e em pixels a partir da borda INFERIOR.
  Para posicionar baseline em 75% da altura (1440px from top em 1920):
  MarginV = 1920 - 1440 - (fontsize * 1.3) ≈ 1920 - 1440 - 52 = 428
  Usaremos MarginV=420 (abaixo do safe zone de plataformas).
"""

import json
import re
from pathlib import Path


# ---- config ---------------------------------------------------------------
SEG_START = 677.47        # offset do video fonte
SEG_END   = 745.42        # offset do video fonte
CHUNK_MAX_WORDS = 5       # maximo de palavras por chunk visivel
SILENCE_BREAK = 0.40      # silencio >= X segundos forca novo chunk

# Cores ASS (formato BGR com alpha, & H alpha BB GG RR)
COLOR_BASE      = "&H00FFFFFF"   # branco
COLOR_HIGHLIGHT = "&H0016A3F9"   # laranja #F97316 em BGR
COLOR_SHADOW    = "&H80000000"   # sombra semi-transparente

# Font e tamanho (para publico 60+, legivel mas nao dominante)
FONT_NAME = "Liberation Sans"
FONT_SIZE = 52             # em pixels em PlayResY=1920

# Margem inferior (pixels do bottom): para ficar em ~75% da altura
# PlayResY=1920, 75% = y=1440. Baseline fica aprox em MarginV do bottom.
MARGIN_V = 360             # pixels da borda inferior

# ---- paths ----------------------------------------------------------------
TR_PATH = Path("/opt/mia/workspace/videos/borrello_lives/edit/transcripts/"
               "ENERGIAS DO SOBSOLO - CASAS QUE MATAM _ Francisco Borrello.json")
OUT_ASS = Path("/opt/mia/workspace/videos/borrello_lives/edit/karaoke.ass")


# ---- helpers --------------------------------------------------------------

def srt_time(t: float) -> str:
    """Segundos -> HH:MM:SS.cs (centisegundos) para ASS."""
    t = max(0.0, t)
    h = int(t // 3600)
    m = int((t % 3600) // 60)
    s = int(t % 60)
    cs = int((t - int(t)) * 100)
    return f"{h}:{m:02d}:{s:02d}.{cs:02d}"


def escape_ass(text: str) -> str:
    """Escapa caracteres especiais para ASS."""
    return text.replace("{", "\\{").replace("}", "\\}")


def ass_highlight(words_in_chunk: list[dict], active_idx: int) -> str:
    """Retorna linha ASS com a palavra ativa em laranja e o resto em branco."""
    parts = []
    for i, w in enumerate(words_in_chunk):
        text = escape_ass(w["text"])
        if i == active_idx:
            parts.append(f"{{\\c{COLOR_HIGHLIGHT}}}{text}{{\\c{COLOR_BASE}}}")
        else:
            parts.append(text)
    return " ".join(parts)


# ---- carga de dados -------------------------------------------------------

def load_words(tr_path: Path, seg_start: float, seg_end: float) -> list[dict]:
    data = json.loads(tr_path.read_text())
    words = [
        w for w in data["words"]
        if w["type"] == "word"
        and w.get("start") is not None
        and w["start"] >= seg_start - 0.15
        and w["end"] <= seg_end + 0.3
    ]
    return words


def make_chunks(words: list[dict], chunk_max: int, silence_break: float) -> list[list[dict]]:
    """Agrupa palavras em chunks de ate chunk_max, quebrando em pontuacao ou silencio."""
    chunks: list[list[dict]] = []
    current: list[dict] = []

    for i, w in enumerate(words):
        current.append(w)

        # verificar se deve quebrar
        ends_punct = bool(re.search(r"[.!?]$", w["text"].rstrip()))
        ends_comma = bool(re.search(r"[,;]$", w["text"].rstrip()))

        gap = 0.0
        if i + 1 < len(words):
            gap = words[i + 1]["start"] - w["end"]

        should_break = (
            len(current) >= chunk_max
            or ends_punct
            or (ends_comma and len(current) >= 3)
            or gap >= silence_break
        )

        if should_break:
            chunks.append(current)
            current = []

    if current:
        chunks.append(current)

    return chunks


# ---- gera ASS -------------------------------------------------------------

ASS_HEADER = """\
[Script Info]
Title: Borrello Karaoke Piloto
ScriptType: v4.00+
WrapStyle: 0
PlayResX: 1080
PlayResY: 1920
ScaledBorderAndShadow: yes

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,{font},{size},{color_base},&H000000FF,&H00000000,{color_shadow},-1,0,0,0,100,100,0,0,1,3.5,1.5,2,30,30,{margin_v},1

[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
""".format(
    font=FONT_NAME,
    size=FONT_SIZE,
    color_base=COLOR_BASE,
    color_shadow=COLOR_SHADOW,
    margin_v=MARGIN_V,
)


def build_ass(words: list[dict], chunks: list[list[dict]], seg_start: float) -> str:
    lines = [ASS_HEADER]

    # Para cada chunk, para cada palavra do chunk, gerar uma cue
    # onde a palavra ativa fica em laranja
    for chunk in chunks:
        for active_idx, active_word in enumerate(chunk):
            # timing: do inicio da palavra ativa ate o inicio da proxima palavra
            # (ou fim do chunk se for a ultima)
            cue_start = active_word["start"] - seg_start
            if active_idx + 1 < len(chunk):
                cue_end = chunk[active_idx + 1]["start"] - seg_start
            else:
                # ultima palavra do chunk: vai ate inicio do proximo chunk ou ate o fim
                cue_end = active_word["end"] - seg_start + 0.08  # 80ms de respiro

            # nao deixar tempo negativo
            cue_start = max(0.0, cue_start)
            cue_end = max(cue_start + 0.05, cue_end)

            text = ass_highlight(chunk, active_idx)
            line = (
                f"Dialogue: 0,{srt_time(cue_start)},{srt_time(cue_end)},"
                f"Default,,0,0,0,,{text}"
            )
            lines.append(line)

    return "\n".join(lines)


# ---- main -----------------------------------------------------------------

def main():
    print(f"Carregando transcricao: {TR_PATH.name}")
    words = load_words(TR_PATH, SEG_START, SEG_END)
    print(f"  {len(words)} palavras no trecho {SEG_START:.1f}s - {SEG_END:.1f}s")

    chunks = make_chunks(words, CHUNK_MAX_WORDS, SILENCE_BREAK)
    print(f"  {len(chunks)} chunks")

    ass_content = build_ass(words, chunks, SEG_START)

    OUT_ASS.parent.mkdir(parents=True, exist_ok=True)
    OUT_ASS.write_text(ass_content, encoding="utf-8")
    print(f"ASS salvo: {OUT_ASS}")

    # contar cues
    cues = [l for l in ass_content.split("\n") if l.startswith("Dialogue:")]
    print(f"  {len(cues)} cues de legenda")

    # mostrar alguns exemplos
    print("\nPrimeiras 5 cues:")
    for c in cues[:5]:
        print(f"  {c[:100]}")


if __name__ == "__main__":
    main()
