#!/usr/bin/env python3
from pathlib import Path
import json, re

PROJECT = Path('/data/video-pipeline/Youtube-Video-Maker/Project/04072026-001-To-Vinh-Dien')
SRC = PROJECT / 'script/source_story.txt'

def clean(t):
    return re.sub(r'\n{3,}', '\n\n', t.replace('\r\n', '\n').replace('\r', '\n').strip())

def sents(p):
    return [s.strip() for s in re.split(r'(?<=[.!?])\s+', p.strip()) if s.strip()]

def title(x):
    t = re.sub(r'^\d+\.\s*', '', x.strip())
    return t[:1] + t[1:].lower()

def visual(text, sec, typ='visual_beat'):
    low = text.lower()
    if typ == 'heading':
        return f'Title card for section: {sec}'
    if 'khẩu pháo' in low or 'chèn pháo' in low or 'bánh pháo' in low or 'lao xuống vực' in low:
        return 'Tô Vĩnh Diện lao tới chèn thân mình giữ bánh pháo trên con dốc Điện Biên, đồng đội kéo dây trong khói sương núi.'
    if 'kéo pháo' in low or 'dây tời' in low or 'dốc' in low:
        return 'Bộ đội pháo binh kéo khẩu pháo nặng qua đường núi hẹp, dây chão căng, một bên vách đá một bên vực sâu.'
    if 'điện biên phủ' in low or 'him lam' in low or '13 tháng 3' in low:
        return 'Lòng chảo Điện Biên Phủ năm 1954, pháo binh Việt Nam nổ súng giữa núi rừng và cứ điểm Pháp.'
    if 'thanh hóa' in low or 'nông cống' in low or 'nông trường' in low:
        return 'Làng quê Thanh Hóa lam lũ, ruộng đồng miền Trung, người thanh niên nông dân Tô Vĩnh Diện trước ngày nhập ngũ.'
    if 'quân đội' in low or 'pháo binh' in low or 'người lính' in low:
        return 'Người lính pháo binh Việt Minh rèn luyện trong kháng chiến chống Pháp, ba lô, quân phục nâu xanh và núi rừng.'
    if 'võ nguyên giáp' in low or 'đánh chắc' in low or 'đánh nhanh' in low:
        return 'Sở chỉ huy chiến dịch trong rừng Tây Bắc, bản đồ Điện Biên Phủ và quyết định chuyển phương châm tác chiến.'
    if 'anh hùng' in low or 'truy tặng' in low or 'sách giáo khoa' in low:
        return 'Ký ức hậu thế về Tô Vĩnh Diện, tượng đài, trang sách lịch sử và ánh sáng tưởng niệm trên nền giấy cổ.'
    return 'Cảnh lịch sử Việt Nam kháng chiến chống Pháp, người lính, núi rừng Tây Bắc và ký ức Điện Biên bằng mực nâu trên giấy cổ.'

def build(cleaned):
    body = re.sub(r'^Tiêu đề truyện:.*?^Nội dung:\s*', '', cleaned, flags=re.S | re.M).strip()
    chunks = re.split(r'(?m)^(\d+\.\s+[^\n]+)$', body)
    scenes = []
    sid = 1
    sec = 'Mở đầu'
    for ch in chunks:
        if not ch.strip():
            continue
        if re.match(r'^\d+\.\s+', ch.strip()):
            sec = title(ch)
            scenes.append({'scene_id': f'scene_{sid:03d}', 'type': 'heading', 'section': sec, 'text': sec, 'visual_beat': visual('', sec, 'heading'), 'estimated_seconds': 4, 'rule': 'heading_must_be_own_scene'})
            sid += 1
            continue
        for p in [x.strip() for x in ch.split('\n\n') if x.strip()]:
            group = []
            wc = 0
            for s in sents(p):
                group.append(s)
                wc += len(s.split())
                if wc >= 42 or len(group) >= 3:
                    txt = ' '.join(group)
                    scenes.append({'scene_id': f'scene_{sid:03d}', 'type': 'visual_beat', 'section': sec, 'text': txt, 'visual_beat': visual(txt, sec), 'estimated_seconds': max(14, min(22, round(len(txt.split()) / 3.0))), 'rule': 'grouped_visual_beat_14_22_seconds'})
                    sid += 1
                    group = []
                    wc = 0
            if group:
                txt = ' '.join(group)
                if scenes and scenes[-1]['type'] == 'visual_beat' and scenes[-1]['section'] == sec and len(txt.split()) < 18:
                    scenes[-1]['text'] += ' ' + txt
                    scenes[-1]['visual_beat'] = visual(scenes[-1]['text'], sec)
                    scenes[-1]['estimated_seconds'] = min(22, scenes[-1]['estimated_seconds'] + 5)
                else:
                    scenes.append({'scene_id': f'scene_{sid:03d}', 'type': 'visual_beat', 'section': sec, 'text': txt, 'visual_beat': visual(txt, sec), 'estimated_seconds': max(12, min(22, round(len(txt.split()) / 3.0))), 'rule': 'grouped_visual_beat_14_22_seconds'})
                    sid += 1
    return scenes

chars = [
    {'name': 'Tô Vĩnh Diện người lính pháo binh', 'role': 'Main hero, Vietnamese artillery soldier before and during Điện Biên Phủ', 'estimated_age': '29-30', 'appearance': 'Vietnamese man from Thanh Hóa, lean farmer-soldier build, sun-darkened face, calm determined eyes, modest and disciplined', 'costume': 'Viet Minh artillery uniform, simple green brown clothes, cloth cap or pith helmet, rope gloves, field pack', 'temperament': 'quiet, careful, enduring, selfless', 'historical_cultural_context': 'First Indochina War, Điện Biên Phủ campaign 1954, artillery pulling operation', 'visual_keywords': ['To Vinh Dien', 'artillery soldier', 'Dien Bien Phu', 'Viet Minh'], 'negative_notes': 'no modern uniform, no American Vietnam War gear, no fantasy, no gore'},
    {'name': 'Tô Vĩnh Diện chèn pháo', 'role': 'Main hero in the decisive sacrifice holding the rolling cannon', 'estimated_age': '30', 'appearance': 'wounded but resolute Vietnamese artillery soldier, dirt and sweat, urgent heroic expression, historically restrained', 'costume': 'battle-worn Viet Minh artillery clothing, rope harness marks, simple equipment', 'temperament': 'decisive, sacrificial, fearless, responsible', 'historical_cultural_context': 'Artillery withdrawal at Điện Biên Phủ, 1 February 1954, steep mountain road', 'visual_keywords': ['cannon wheel', 'sacrifice', 'mountain slope'], 'negative_notes': 'no gore spectacle, no superhero pose, no modern gear'},
    {'name': 'Đồng đội pháo binh Điện Biên', 'role': 'Artillery comrades pulling and braking the cannon on mountain roads', 'estimated_age': 'young adult to middle-aged', 'appearance': 'Vietnamese soldiers exhausted, muddy, focused, ropes on shoulders, teamwork around heavy cannon', 'costume': 'Viet Minh 1954 field uniforms, cloth caps, sandals, packs, rope harnesses', 'temperament': 'disciplined, tense, collective, determined', 'historical_cultural_context': 'Human-powered artillery transport in Điện Biên Phủ campaign', 'visual_keywords': ['pulling artillery', 'mountain road', 'Viet Minh artillery'], 'negative_notes': 'no modern helmets, no trucks as main focus'},
    {'name': 'Dân công hỏa tuyến Tây Bắc', 'role': 'Support forces carrying rice, ammunition, and aiding artillery movement', 'estimated_age': 'varied adults', 'appearance': 'Vietnamese dân công, men and women carrying loads, strained faces, night movement in forest', 'costume': 'simple rural clothes, nón lá, shoulder poles, backpacks, some militia clothing', 'temperament': 'enduring, communal, resilient', 'historical_cultural_context': 'Logistics network supporting Điện Biên Phủ, 1953-1954', 'visual_keywords': ['dan cong', 'logistics', 'Tay Bac forest'], 'negative_notes': 'no modern vehicles, no contemporary clothing'},
    {'name': 'Quân Pháp tại Điện Biên Phủ', 'role': 'Opposing French Union soldiers inside fortified strongpoints', 'estimated_age': 'adult soldiers', 'appearance': 'French Union soldiers in bunkers and trenches, tense silhouettes behind sandbags and barbed wire', 'costume': '1950s French colonial uniforms, helmets, bunker equipment', 'temperament': 'defensive, entrenched, alarmed', 'historical_cultural_context': 'French fortified camp at Điện Biên Phủ', 'visual_keywords': ['French bunker', 'Dien Bien Phu', 'barbed wire'], 'negative_notes': 'no WWII Nazi styling, no modern NATO gear'}
]

def main():
    cleaned = clean(SRC.read_text(encoding='utf-8'))
    (PROJECT / 'script/cleaned_story.txt').write_text(cleaned, encoding='utf-8')
    scenes = build(cleaned)
    (PROJECT / 'script/scenes.json').write_text(json.dumps({'project_id': PROJECT.name, 'target_beat_seconds': '14-22', 'split_rule': 'Headings standalone; grouped 14-22s visual beats.', 'total_scenes': len(scenes), 'scenes': scenes}, ensure_ascii=False, indent=2), encoding='utf-8')
    (PROJECT / 'script/scenes_validation.json').write_text(json.dumps({'project_id': PROJECT.name, 'total_scenes': len(scenes), 'metadata_removed_from_scenes': True, 'headings_standalone': True, 'each_scene_has_visual_beat': True, 'status': 'passed'}, ensure_ascii=False, indent=2), encoding='utf-8')
    bible = {'project_id': PROJECT.name, 'visual_style_global': '16:9 horizontal historical storytelling image, Điện Biên Phủ 1954, ink-wash window centered on warm antique paper, muted sepia olive charcoal red-earth watercolor, no modern/fantasy drift.', 'consistency_rules': ['Use Tô Vĩnh Diện người lính pháo binh for life/training/campaign scenes.', 'Use Tô Vĩnh Diện chèn pháo for the decisive cannon-wheel sacrifice.', 'Keep Viet Minh artillery crews, dân công, French 1954 uniforms, cannons, ropes, mountain roads historically grounded.'], 'characters': chars}
    (PROJECT / 'script/character_bible.json').write_text(json.dumps(bible, ensure_ascii=False, indent=2), encoding='utf-8')
    dense = []
    for sc in scenes:
        prompt = ('16:9 horizontal historical storytelling image, ink-wash narrative window on warm antique paper, painted content only 65-70% of frame with clean parchment negative space. ' + f"Scene: {sc['visual_beat']} Narration beat: {sc['text']} Historical grounding: Thanh Hóa rural life, First Indochina War, Điện Biên Phủ 1954, artillery pulling and withdrawal, accurate Viet Minh uniforms, French fortified camp, cannons, ropes, mountain roads, trenches. Negative: no modern objects, no American Vietnam War gear, no fantasy armor, no gore spectacle, no 3D game art, no full-frame glossy poster, no text labels or watermark.")
        dense.append({**sc, 'summary': sc['visual_beat'], 'narration': sc['text'], 'visual_prompt': prompt})
    (PROJECT / 'script/dense_scene_plan.json').write_text(json.dumps({'project_id': PROJECT.name, 'approved_for_next_step': True, 'total_scenes': len(dense), 'scenes': dense}, ensure_ascii=False, indent=2), encoding='utf-8')
    print(json.dumps({'project': str(PROJECT), 'total_scenes': len(scenes)}, ensure_ascii=False))

if __name__ == '__main__':
    main()
