#!/usr/bin/env python3
import json, re, subprocess, time
from pathlib import Path
PROJECT=Path('/data/video-pipeline/Channel-Loi-Co-Nhan/project/11062026-001-Biet-Du-Thi-Khong-Nhuc')
LOGO=Path('/data/video-pipeline/Channel-Loi-Co-Nhan/data/logo/logoloiconhan.png')
BGM=Path('/data/video-pipeline/Channel-Loi-Co-Nhan/data/bgm/paulyudin-sentimental-story-182512.mp3')
LOG=PROJECT/'logs/fix_sub_v5_words.log'
SUB_FONT_SIZE=10
SUB_MARGIN_V=55
WORDS_PER_CUE=5

def log(s):
    line=time.strftime('%F %T ')+s
    print(line, flush=True)
    LOG.parent.mkdir(parents=True, exist_ok=True)
    with LOG.open('a', encoding='utf-8') as f: f.write(line+'\n')

def run(cmd):
    log('RUN '+' '.join(map(str, cmd)))
    subprocess.check_call(list(map(str, cmd)))

def dur(p):
    return float(subprocess.check_output(['ffprobe','-v','error','-show_entries','format=duration','-of','default=nw=1:nk=1',str(p)], text=True).strip())

def ts(sec):
    ms=int(round(sec*1000)); h=ms//3600000; ms%=3600000; m=ms//60000; ms%=60000; s=ms//1000; ms%=1000
    return f'{h:02}:{m:02}:{s:02},{ms:03}'

def word_chunks(text):
    # Keep punctuation attached to words. 4-5 words per subtitle cue.
    words=' '.join(text.replace('\n',' ').split()).split()
    chunks=[]
    i=0
    while i < len(words):
        remain=len(words)-i
        n=WORDS_PER_CUE
        if remain <= WORDS_PER_CUE:
            n=remain
        elif remain == WORDS_PER_CUE + 1:
            n=3  # avoid a final 1-word cue
        chunks.append(' '.join(words[i:i+n]))
        i += n
    return chunks

def main():
    LOG.write_text('', encoding='utf-8')
    data=json.loads((PROJECT/'script/scenes.json').read_text(encoding='utf-8'))
    timeline=json.loads((PROJECT/'audio/master_narration_timeline.json').read_text(encoding='utf-8'))['items']
    by_id={s['scene_id']:s for s in data['scenes']}
    sub=PROJECT/'subtitles/master_subtitles_one_line_bottom_split.srt'
    blocks=[]; idx=1
    debug=[]
    for it in timeline:
        chunks=word_chunks(by_id[it['scene_id']]['narration'])
        start=float(it['start']); end=float(it['speech_end']); total=max(0.1,end-start)
        # Even distribution across chunks. This guarantees every chunk appears in sequence.
        step=total/len(chunks)
        for j,c in enumerate(chunks):
            a=start + j*step
            b=end if j == len(chunks)-1 else start + (j+1)*step
            blocks.append(f"{idx}\n{ts(a)} --> {ts(b)}\n{c}\n")
            debug.append({'idx':idx,'scene_id':it['scene_id'],'start':round(a,3),'end':round(b,3),'text':c})
            idx += 1
    sub.write_text('\n'.join(blocks), encoding='utf-8')
    (PROJECT/'subtitles/subtitle_debug_v5.json').write_text(json.dumps(debug,ensure_ascii=False,indent=2), encoding='utf-8')
    seglist=PROJECT/'render_onepass/segments.txt'
    master=PROJECT/'audio/master_narration.wav'
    mainv=PROJECT/'output/main_story.mp4'
    # Use original_size to make libass coordinates stable, and WrapStyle=2 to prevent auto wrapping.
    fc=(f"[0:v]fps=30,setpts=N/(30*TB),scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,"
        f"subtitles='{sub}':original_size=1080x1920:force_style='FontName=DejaVu Sans,FontSize={SUB_FONT_SIZE},Outline=1,Alignment=2,MarginV={SUB_MARGIN_V},WrapStyle=2'[base];"
        f"movie='{LOGO}',scale=160:-1,format=rgba,colorchannelmixer=aa=0.55[wm];[base][wm]overlay=W-w-35:35[v]")
    run(['ffmpeg','-y','-v','error','-f','concat','-safe','0','-i',seglist,'-i',master,'-filter_complex',fc,'-map','[v]','-map','1:a','-r','30','-c:v','libx264','-pix_fmt','yuv420p','-c:a','aac','-b:a','192k','-ar','44100','-ac','2','-shortest',mainv])
    intro=PROJECT/'output/intro/intro.mp4'; pause=PROJECT/'output/intro/intro_pause_3s.mp4'; final=PROJECT/'output/final/final_video.mp4'
    filter_complex=('[0:v]setpts=PTS-STARTPTS[v0];[0:a]aresample=44100:async=1:first_pts=0[a0];'
        '[1:v]setpts=PTS-STARTPTS[v1];[1:a]aresample=44100:async=1:first_pts=0[a1];'
        '[2:v]setpts=PTS-STARTPTS[v2];[2:a]aresample=44100:async=1:first_pts=0[a2];'
        '[v0][a0][v1][a1][v2][a2]concat=n=3:v=1:a=1[vcat][voice];'
        '[3:a]aresample=44100,volume=0.10[bgm];[voice]volume=1.8[voiceboost];'
        '[voiceboost][bgm]amix=inputs=2:duration=first:dropout_transition=2,alimiter=limit=0.95[a]')
    run(['ffmpeg','-y','-v','error','-i',intro,'-i',pause,'-i',mainv,'-stream_loop','-1','-i',BGM,'-filter_complex',filter_complex,'-map','[vcat]','-map','[a]','-r','30','-c:v','libx264','-pix_fmt','yuv420p','-c:a','aac','-b:a','192k','-ar','44100','-ac','2','-shortest',final])
    run(['ffmpeg','-v','error','-i',final,'-f','null','-'])
    info=json.loads((PROJECT/'output/info.json').read_text(encoding='utf-8'))
    info.update({'duration_sec':dur(final),'subtitle_mode':'one_line_bottom_4_5_words_v5','subtitle_words_per_cue':WORDS_PER_CUE,'subtitle_debug':str(PROJECT/'subtitles/subtitle_debug_v5.json')})
    (PROJECT/'output/info.json').write_text(json.dumps(info,ensure_ascii=False,indent=2),encoding='utf-8')
    log('COMPLETE '+str(final))
if __name__=='__main__': main()
