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

PROJECT = Path('/data/video-pipeline/Youtube-Video-Maker/Project/12062026-002-Nha-Ly')
NOW = lambda: datetime.datetime.now().isoformat(timespec='seconds')
SOURCE = PROJECT / 'script/source_story.txt'; CLEAN = PROJECT / 'script/cleaned_story.txt'; SCENES = PROJECT / 'script/scenes.json'; SCENE_VAL = PROJECT / 'script/scenes_validation.json'; BIBLE = PROJECT / 'script/character_bible.json'; STEP4 = PROJECT / 'script/dense_plan_validation.json'
SECTION_TITLES = {
 '1':'Bước ngoặt từ Hoa Lư ra Thăng Long','2':'Lý Công Uẩn - người mở ra thời đại Thăng Long','3':'Xây dựng một nhà nước ổn định','4':'Phật giáo và linh hồn thời Lý','5':'Lý Thái Tông và sự củng cố triều đại','6':'Lý Thánh Tông - từ Đại Cồ Việt đến Đại Việt','7':'Lý Nhân Tông, Ỷ Lan và thời kỳ thịnh trị','8':'Lý Thường Kiệt và cuộc chiến chống Tống 1075 - 1077','9':'Một triều đại của văn hóa, kiến trúc và bản sắc','10':'Những vết rạn cuối triều Lý','11':'Lý Chiêu Hoàng và hồi kết năm 1225','12':'Di sản hơn hai thế kỷ của nhà Lý','13':'Tiếng rồng bay còn vang trong lịch sử'}

def clean_text(txt):
    txt=txt.replace('\r\n','\n').replace('\r','\n'); txt=re.sub(r'[ \t]+',' ',txt); return re.sub(r'\n{3,}','\n\n',txt).strip()+'\n'
def extract_meta(txt):
    title=''; series=''; body=[]; in_body=False
    for line in txt.splitlines():
        s=line.strip(); low=s.lower()
        if low.startswith('tiêu đề truyện:'): title=s.split(':',1)[1].strip()
        elif low.startswith('series:'): series=s.split(':',1)[1].strip()
        elif low.startswith('nội dung:'): in_body=True
        elif in_body or (s and not low.startswith(('tiêu đề truyện:','series:'))): body.append(s)
    return title,series,'\n\n'.join(body).strip()
def split_sentences(text): return [p.strip() for p in re.split(r'(?<=[.!?])\s+', text.strip()) if p.strip()]
def chunk_para(para,max_chars=360):
    chunks=[]; cur=''
    for s in split_sentences(para):
        if cur and len(cur)+len(s)+1>max_chars: chunks.append(cur.strip()); cur=s
        else: cur=(cur+' '+s).strip()
    if cur: chunks.append(cur.strip())
    return chunks
def visual_for(text,section):
    t=text.lower()
    if 'lý công uẩn' in t or 'lý thái tổ' in t or 'chiếu dời đô' in t or 'thăng long' in t: return 'Lý Công Uẩn trên thuyền dời đô, thành Đại La hóa Thăng Long, rồng vàng bay lên trong bình minh Đại Việt.'
    if 'phật giáo' in t or 'chùa' in t or 'quốc tử giám' in t or 'văn miếu' in t: return 'Không gian văn hóa thời Lý với chùa tháp, tăng sĩ, Văn Miếu và nét rồng thanh thoát trên gạch ngói Thăng Long.'
    if 'lý thường kiệt' in t or 'như nguyệt' in t or 'nam quốc sơn hà' in t or 'ung châu' in t or 'quách quỳ' in t: return 'Lý Thường Kiệt chỉ huy quân Đại Việt, phòng tuyến sông Như Nguyệt, cờ trận và khí thế Nam quốc sơn hà.'
    if 'ỷ lan' in t: return 'Ỷ Lan trong cung đình Thăng Long, khí chất nữ chính trị gia thời Lý, ánh nhìn vừa nhân ái vừa cứng cỏi.'
    if 'lý thái tông' in t or 'hình thư' in t: return 'Lý Thái Tông củng cố triều chính, ban luật Hình thư, triều đình Thăng Long quy củ và uy nghi.'
    if 'lý thánh tông' in t or 'đại việt' in t or 'chế củ' in t: return 'Lý Thánh Tông đổi quốc hiệu Đại Việt, triều đình tự tin và đoàn quân nam tiến trong bối cảnh Đông Nam Á thế kỷ XI.'
    if 'lý chiêu hoàng' in t or 'trần thủ độ' in t or 'trần cảnh' in t: return 'Lý Chiêu Hoàng nhỏ tuổi trong cung điện cuối Lý, bóng họ Trần và hồi kết chuyển triều năm 1225.'
    return f'Cảnh lịch sử Đại Việt thời Lý minh họa đoạn {section}, trang nghiêm, thanh thoát, giàu tinh thần Phật giáo.'
def build_scenes(title,series,body):
    scenes=[]; sid=1; section='Mở đầu'
    for block in [b.strip() for b in body.split('\n\n') if b.strip()]:
        m=re.match(r'^(\d+)\.\s+(.+)$',block)
        if m:
            section=SECTION_TITLES.get(m.group(1),m.group(2).strip())
            scenes.append({'scene_id':f'scene_{sid:03d}','type':'heading','section':section,'summary':section,'narration':section,'text':section,'visual_beat':f'Title-card heading for section: {section}','visual_prompt':f'Vietnamese old-calligraphy title-card on warm antique paper: {section}','estimated_seconds':4,'rule':'heading_must_be_own_scene'}); sid+=1; continue
        for chunk in chunk_para(block):
            vb=visual_for(chunk,section)
            scenes.append({'scene_id':f'scene_{sid:03d}','type':'visual_beat','section':section,'summary':chunk[:140]+('...' if len(chunk)>140 else ''),'narration':chunk,'text':chunk,'visual_beat':vb,'visual_prompt':vb+' 16:9 horizontal historical storytelling image, ink-wash window centered on warm antique paper, Vietnamese co phong feeling, historically grounded 11th-12th-century Đại Việt / Thăng Long / Nhà Lý.','estimated_seconds':max(6,min(12,round(len(chunk)/34))),'rule':'split_by_visual_beat_8_12_seconds'}); sid+=1
    return scenes
def character_bible():
    chars=[
('Lý Công Uẩn / Lý Thái Tổ','founding emperor of Lý dynasty','30s-40s','Khoan hòa, uy nghi, ánh mắt nhìn xa','Long bào đầu Lý giản dị, áo choàng đi thuyền dời đô','sáng suốt, nhân hậu, quyết đoán','Cổ Pháp, Hoa Lư, Đại La - Thăng Long 1010','ly cong uan, ly thai to, thang long','Không vẽ như hoàng đế Trung Hoa'),
('Lý Thái Tông','second Lý emperor and consolidator','30s-50s','Vua võ lược, nghiêm nghị','Triều phục/chiến bào đầu Lý, giáp nhẹ','cứng rắn, biết khoan hòa','Hình thư 1042, Chiêm Thành 1044, Thăng Long','ly thai tong, hinh thu','Không fantasy armor'),
('Lý Thánh Tông','emperor who named Đại Việt','30s-50s','Vị vua điềm đạm, có đức','Long bào thời Lý, màu trầm thanh nhã','nhân từ, tự tin, mở mang','Đổi quốc hiệu Đại Việt 1054, Chiêm Thành 1069','ly thanh tong, dai viet','Không làm quá Trung Hoa'),
('Lý Nhân Tông','long-reigning emperor','child to adult','Vua trẻ rồi trưởng thành trong thời thịnh trị','Triều phục nhà Lý, dáng thư sinh/quân vương','được phụ chính, trị vì lâu dài','Khoa thi 1075, Quốc Tử Giám 1076','ly nhan tong, quoc tu giam','Không nhầm với nhà Trần'),
('Ỷ Lan','Linh Nhân Hoàng thái hậu and political regent','30s-50s','Gương mặt thông minh, trầm tĩnh, quyền lực','Triều phục hoàng thái hậu kín đáo, màu nâu vàng thanh nhã','nhân ái, sắc sảo, có bóng tối chính trị','Cung đình Thăng Long, nhiếp chính thời Lý Nhân Tông','y lan, linh nhan thai hau','Không sexualize'),
('Lý Thường Kiệt','great general and strategist','50s-60s','Danh tướng sắc bén, uy nghi, ánh mắt chiến lược','Giáp tướng Đại Việt thời Lý, kiếm lệnh, cờ trận','táo bạo, bình tĩnh, quyết đoán','Ung Châu 1075, Như Nguyệt 1077, Nam quốc sơn hà','ly thuong kiet, nhu nguyet','Không vẽ như samurai'),
('Quân Tống và Quách Quỳ','Song invasion force','mixed ages','Tướng và binh sĩ phương Bắc, giáp Tống','Giáp quân Tống thế kỷ XI, cờ hiệu phương Bắc','áp lực xâm lược, mệt mỏi nơi biên viễn','Chiến tranh Tống - Đại Việt 1075-1077','quan tong, quach quy','Không biến thành quái vật'),
('Sư tăng Phật giáo thời Lý','Buddhist monks and cultural force','mixed ages','Tăng sĩ điềm đạm, học thức','Áo cà sa nâu, chùa tháp thời Lý','từ bi, trí tuệ, ảnh hưởng triều chính','Chùa Một Cột, Phật Tích, Phật giáo Thăng Long','su tang phat giao, chua ly','Không hiện đại hóa'),
('Lý Chiêu Hoàng','last emperor of Lý dynasty','child','Bé gái hoàng đế, ánh mắt buồn và cô độc','Long bào nhỏ, cung đình cuối Lý','mong manh, bị cuốn vào chính trị','Chuyển giao Lý - Trần năm 1225','ly chieu hoang','Không vẽ trưởng thành'),
('Trần Thủ Độ và Trần Cảnh','rising Trần political force','20s-40s','Trần Thủ Độ sắc lạnh, Trần Cảnh còn trẻ','Quan phục/chiến phục họ Trần đầu thế kỷ XIII','quyền lực, tính toán, chuyển triều','Cuối Lý, họ Trần nắm triều chính','tran thu do, tran canh','Không demonize quá mức')]
    return {'project_id':PROJECT.name,'visual_style_global':'16:9 horizontal historical storytelling, ink-wash window centered on warm antique paper, muted sepia/charcoal Vietnamese co phong, historically grounded 11th-12th-century Đại Việt / Thăng Long / Nhà Lý, Buddhist elegance and Lý dragon motifs.','consistency_rules':['Preserve Đại Việt Lý dynasty clothing, Buddhist architecture, Thăng Long setting.','Use character refs for recurring figures.','Avoid modern objects, fantasy armor, Chinese opera drift, samurai/European armor.'],'characters':[{'name':n,'role':r,'estimated_age':a,'appearance':ap,'costume':c,'temperament':te,'historical_cultural_context':h,'visual_keywords':vk,'negative_notes':neg} for n,r,a,ap,c,te,h,vk,neg in chars]}
def checklist_update(done_upto,current):
    p=PROJECT/'checklist_19_steps.json'; d=json.loads(p.read_text(encoding='utf-8')); d['current_step']=current; d['updated_at']=NOW()
    for st in d['steps']:
        if st['step']<=done_upto: st['status']='completed'; st['completed_at']=st.get('completed_at') or NOW()
        elif st['step']==current: st['status']='in_progress'; st['completed_at']=None
        else: st['status']='pending'; st['completed_at']=None
    p.write_text(json.dumps(d,ensure_ascii=False,indent=2),encoding='utf-8')
    lines=['# Checklist 19 Steps','',f"Project ID: {d['project_id']}",f"Channel: {d['channel']}",f"Current step: {d['current_step']}",f"Updated at: {d['updated_at']}",'']
    for st in d['steps']:
        box='[x]' if st['status']=='completed' else '[ ]'; lines += [f"## {box} Step {st['step']:02d} - {st['name']}",'',f"Status: {st['status']}",'']
    (PROJECT/'checklist_19_steps.md').write_text('\n'.join(lines),encoding='utf-8')
def main():
    clean=clean_text(SOURCE.read_text(encoding='utf-8')); CLEAN.write_text(clean,encoding='utf-8')
    title,series,body=extract_meta(clean); scenes=build_scenes(title,series,body)
    meta={'project_id':PROJECT.name,'title':title,'series':series,'target_beat_seconds':'8-12','split_rule':'Headings are separate scenes; passages split by visual beats, not metadata.','total_scenes':len(scenes),'scenes':scenes}; SCENES.write_text(json.dumps(meta,ensure_ascii=False,indent=2),encoding='utf-8')
    heads=[s for s in scenes if s['type']=='heading']; visuals=[s for s in scenes if s['type']=='visual_beat']
    vals={'project_id':PROJECT.name,'step':2,'status':'completed','title':title,'series':series,'total_scenes':len(scenes),'heading_scenes':len(heads),'visual_beat_scenes':len(visuals),'metadata_excluded_from_scenes':True,'duplicate_narration_count':len(scenes)-len({s['narration'] for s in scenes}),'long_scene_count':sum(1 for s in visuals if len(s['narration'])>520)}; vals['valid']=vals['duplicate_narration_count']==0 and vals['long_scene_count']==0 and len(heads)==13
    SCENE_VAL.write_text(json.dumps(vals,ensure_ascii=False,indent=2),encoding='utf-8'); checklist_update(2,3)
    BIBLE.write_text(json.dumps(character_bible(),ensure_ascii=False,indent=2),encoding='utf-8'); checklist_update(3,4)
    STEP4.write_text(json.dumps({'project_id':PROJECT.name,'step':4,'status':'completed_approved_for_next_step','approved_for_next_step':True,'total_scenes':len(scenes),'heading_scenes':len(heads),'visual_beat_scenes':len(visuals),'valid_for_review':vals['valid']},ensure_ascii=False,indent=2),encoding='utf-8'); checklist_update(4,5)
    print(json.dumps({'project_id':PROJECT.name,'title':title,'series':series,'total_scenes':len(scenes),'headings':len(heads),'visual_beats':len(visuals),'valid':vals['valid']},ensure_ascii=False))
if __name__=='__main__': main()
