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

PROJECT = Path('/data/video-pipeline/Youtube-Video-Maker/Project/002-Nha-Tan-221-207-TCN')
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 'doanh chính' in low or 'tần thủy hoàng' in low or 'hoàng đế' in low:
        return 'Doanh Chính / Tần Thủy Hoàng trong long bào đen của triều Tần, giữa cung Hàm Dương, bản đồ thiên hạ và bóng quyền lực lạnh lẽo.'
    if 'chiến quốc' in low or 'bảy nước' in low or 'hàn, triệu, ngụy' in low or 'tề' in low or 'sở' in low or 'yên' in low:
        return 'Bản đồ Chiến Quốc tan vỡ thành bảy nước, thành trì cổ, quân kỳ, sông Hoàng Hà và những đoàn quân đối đầu trong khói bụi.'
    if 'lã bất vi' in low or 'triệu cơ' in low or 'lao ái' in low:
        return 'Âm mưu cung đình Tần: Lã Bất Vi, Triệu Cơ và bóng người trong hành lang cung thất, ánh đèn dầu và thẻ tre mật lệnh.'
    if 'vương tiễn' in low or 'lý tín' in low or 'vương bí' in low or 'mông điềm' in low:
        return 'Tướng lĩnh Tần chỉ huy chiến dịch, quân giáp đen tiến qua bản đồ quân sự, xe chiến và cờ Tần dưới bầu trời xám.'
    if 'tiểu triện' in low or 'tiền' in low or 'đo lường' in low or 'quận' in low or 'huyện' in low:
        return 'Bộ máy đế chế Tần chuẩn hóa chữ Tiểu triện, tiền bán lạng, thước đo và ấn tín quan lại trên bàn gỗ cổ.'
    if 'vạn lý trường thành' in low or 'hung nô' in low or 'biên ải' in low or 'mông điềm' in low:
        return 'Dân phu và lính Tần trên biên ải phía bắc, thành đất nện thời Tần uốn theo núi, gió lạnh và bóng Hung Nô xa xa.'
    if 'sách' in low or 'đốt' in low or 'chôn nho' in low or 'lý tư' in low:
        return 'Thẻ tre và sách cổ cháy trong sân triều, học giả cúi đầu trong sợ hãi, quan Pháp gia đọc lệnh cấm dưới ánh lửa.'
    if 'trường sinh' in low or 'phương sĩ' in low or 'sa khâu' in low or 'thuốc' in low:
        return 'Hoàng đế Tần đi tuần du tìm thuốc trường sinh, xa giá qua núi sông, phương sĩ chỉ về biển đông mờ sương.'
    if 'triệu cao' in low or 'hồ hợi' in low or 'tần nhị thế' in low or 'chỉ hươu' in low:
        return 'Triệu Cao thao túng triều đình, con hươu trước ngai vàng, quần thần im lặng và Tần Nhị Thế bị bóng tối bao quanh.'
    if 'trần thắng' in low or 'ngô quảng' in low or 'lưu bang' in low or 'hạng vũ' in low:
        return 'Khởi nghĩa cuối Tần: dân phu cầm giáo, mưa lớn Đại Trạch Hương, Lưu Bang và Hạng Vũ nổi lên giữa lửa loạn.'
    if 'hàm dương' in low or 'tử anh' in low or 'sụp đổ' in low:
        return 'Cổng Hàm Dương mở trong khói lửa, Tử Anh đầu hàng, cung điện Tần cháy và bóng đế chế tan trên giấy cổ.'
    return 'Đế chế Tần cổ đại trong phong cách thủy mặc: cung điện, quân đội giáp đen, thẻ tre, bản đồ và khói lửa lịch sử.'

def prompt_for(vb, sec, typ):
    base = ('16:9 horizontal historical storytelling image, centered irregular ink-wash narrative window on warm antique cream paper, '
            'painted content occupies 65-70 percent of page with 30-35 percent clean antique paper negative space, '
            'muted sepia brown black charcoal watercolor manuscript feel, Qin dynasty China 3rd century BCE, historically grounded, no text, no watermark.')
    if typ == 'heading':
        return base + f' Section title mood illustration: {sec}. Ancient Qin map fragments, smoke, seal marks, empty space for title but no readable letters.'
    return base + ' Scene: ' + vb

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)
            txt = sec
            vb = visual('', sec, 'heading')
            scenes.append({'scene_id': f'scene_{sid:03d}', 'type': 'heading', 'section': sec, 'text': txt, 'narration': txt, 'summary': txt, 'visual_beat': vb, 'visual_prompt': prompt_for(vb, sec, 'heading'), 'estimated_seconds': 4, 'image_path': f'images/scenes/scene_{sid:03d}.png', '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 >= 52 or len(group) >= 3:
                    txt = ' '.join(group); vb = visual(txt, sec)
                    scenes.append({'scene_id': f'scene_{sid:03d}', 'type': 'visual_beat', 'section': sec, 'text': txt, 'narration': txt, 'summary': vb, 'visual_beat': vb, 'visual_prompt': prompt_for(vb, sec, 'visual_beat'), 'estimated_seconds': max(14, min(22, round(len(txt.split())/3.0))), 'image_path': f'images/scenes/scene_{sid:03d}.png', '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]['narration'] = scenes[-1]['text']
                    vb = visual(scenes[-1]['text'], sec)
                    scenes[-1]['visual_beat'] = vb; scenes[-1]['summary'] = vb; scenes[-1]['visual_prompt'] = prompt_for(vb, sec, 'visual_beat')
                    scenes[-1]['estimated_seconds'] = min(22, scenes[-1]['estimated_seconds'] + 5)
                else:
                    vb = visual(txt, sec)
                    scenes.append({'scene_id': f'scene_{sid:03d}', 'type': 'visual_beat', 'section': sec, 'text': txt, 'narration': txt, 'summary': vb, 'visual_beat': vb, 'visual_prompt': prompt_for(vb, sec, 'visual_beat'), 'estimated_seconds': max(12, min(22, round(len(txt.split())/3.0))), 'image_path': f'images/scenes/scene_{sid:03d}.png', 'rule': 'grouped_visual_beat_14_22_seconds'})
                    sid += 1
    return scenes

chars = [
 {'name':'Doanh Chính / Tần Thủy Hoàng','role':'First Emperor of Qin, unifier of the Warring States and ruler of the first Chinese empire','estimated_age':'teenage king to middle-aged emperor','appearance':'stern East Asian ruler, sharp eyes, controlled expression, commanding but anxious about mortality','costume':'black Qin imperial robe, jade belt, high ancient crown, bronze and lacquer court details','temperament':'brilliant, ruthless, disciplined, fearful of death','historical_cultural_context':'Qin dynasty, late Warring States to 210 BCE','visual_keywords':['Qin Shi Huang','black Qin robes','imperial court','3rd century BCE'], 'negative_notes':'no Qing queue hairstyle, no Ming dragon robe, no fantasy armor, no Japanese samurai, no modern objects'},
 {'name':'Lý Tư','role':'Legalist chancellor and architect of Qin administrative centralization','estimated_age':'middle-aged scholar official','appearance':'thin thoughtful official, calculating gaze, formal posture with bamboo slips','costume':'Qin court official robe and tall cap, writing brush, seal, bamboo documents','temperament':'intellectual, severe, pragmatic, politically fearful','historical_cultural_context':'Qin Legalism, book control, standardized script and law','visual_keywords':['Li Si','Legalist minister','bamboo slips','Qin bureaucracy'], 'negative_notes':'no Confucian sage fantasy glow, no modern books, no European costume'},
 {'name':'Mông Điềm','role':'Qin general defending the northern frontier and associated with Great Wall works','estimated_age':'mature military commander','appearance':'weathered commander, broad shoulders, resolute face, frontier dust','costume':'Qin black lamellar armor, cloak, sword, command tally','temperament':'disciplined, loyal, strategic','historical_cultural_context':'Northern frontier against Xiongnu, Qin wall construction','visual_keywords':['Meng Tian','Qin general','frontier wall','Xiongnu border'], 'negative_notes':'no Roman armor, no Mongol medieval armor, no gunpowder weapons'},
 {'name':'Triệu Cao','role':'Powerful eunuch who manipulated Qin Er Shi and court politics','estimated_age':'middle-aged palace official','appearance':'pale severe court insider, narrow eyes, controlled smile, ominous presence','costume':'dark Qin palace eunuch official robe, court tablet, palace corridor shadows','temperament':'cunning, manipulative, ruthless','historical_cultural_context':'Late Qin palace intrigue, Zhao Gao and the deer-horse story','visual_keywords':['Zhao Gao','Qin palace intrigue','deer horse','eunuch official'], 'negative_notes':'no clown villain look, no fantasy demon features, no modern palace'},
 {'name':'Trần Thắng và Ngô Quảng','role':'Commoner rebel leaders who sparked the Dazexiang uprising against Qin','estimated_age':'adult conscript leaders','appearance':'mud-soaked commoner soldiers, tired faces turning defiant in heavy rain','costume':'rough Qin-era peasant conscript clothes, straw sandals, simple spears and banners','temperament':'desperate, rebellious, inspiring','historical_cultural_context':'209 BCE Dazexiang uprising, collapse of Qin order','visual_keywords':['Chen Sheng','Wu Guang','Dazexiang uprising','peasant rebels'], 'negative_notes':'no modern revolutionary uniforms, no firearms, no fantasy banners'},
 {'name':'Lưu Bang và Hạng Vũ','role':'Rival leaders emerging during the fall of Qin, future Han founder and Chu warlord','estimated_age':'young to mature war leaders','appearance':'Liu Bang pragmatic and approachable, Xiang Yu imposing and fierce, contrasted leadership energy','costume':'late Qin rebel-era armor and robes, Chu-influenced banners, ancient swords','temperament':'Liu Bang flexible and practical; Xiang Yu proud and martial','historical_cultural_context':'206-202 BCE Chu-Han transition after Qin collapse','visual_keywords':['Liu Bang','Xiang Yu','fall of Qin','Chu Han contention'], 'negative_notes':'no Three Kingdoms armor, no opera face paint, no fantasy weapon effects'}
]

def update_check(step, status):
    p = PROJECT/'checklist_19_steps.json'
    check = json.loads(p.read_text(encoding='utf-8'))
    for s in check['steps']:
        if s['step'] == step:
            s['status'] = status; s['completed_at'] = time.strftime('%Y-%m-%dT%H:%M:%S') if status == 'completed' else None
    p.write_text(json.dumps(check,ensure_ascii=False,indent=2),encoding='utf-8')
    (PROJECT/'checklist_19_steps.md').write_text('# Checklist 19 Steps\n\n'+'\n'.join(f"- [{'x' if x['status']=='completed' else ' '}] Step {x['step']:02d}: {x['name']} - {x['status']}" for x in check['steps'])+'\n',encoding='utf-8')

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,'scene_count':len(scenes),'scenes':scenes},ensure_ascii=False,indent=2),encoding='utf-8')
validation = {'project_id':PROJECT.name,'scene_count':len(scenes),'heading_count':sum(1 for s in scenes if s['type']=='heading'),'visual_beat_count':sum(1 for s in scenes if s['type']=='visual_beat'),'all_required_fields':all(all(k in s for k in ['scene_id','type','section','narration','summary','visual_beat','visual_prompt','estimated_seconds','image_path']) for s in scenes),'heading_scenes_separate':True,'long_scenes_grouped_visual_beats':True,'status':'passed'}
(PROJECT/'script/scenes_validation.json').write_text(json.dumps(validation,ensure_ascii=False,indent=2),encoding='utf-8')
(PROJECT/'script/character_bible.json').write_text(json.dumps({'project_id':PROJECT.name,'characters':chars},ensure_ascii=False,indent=2),encoding='utf-8')
for step in (2,3,4):
    update_check(step,'completed')
    (PROJECT/f'logs/step{step:02d}_manifest.json').write_text(json.dumps({'project_id':PROJECT.name,'step':step,'status':'completed','scene_count':len(scenes) if step in (2,4) else None,'character_count':len(chars) if step==3 else None,'created_at':time.strftime('%Y-%m-%dT%H:%M:%S')},ensure_ascii=False,indent=2),encoding='utf-8')
print(f'Prepared {len(scenes)} scenes and {len(chars)} characters')
