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

PROJECT=Path('/data/video-pipeline/Youtube-Video-Maker/Project/28052026-001-Tay-Son-That-Ho-Tuong')
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':'Khi đất nước nổi gió','2':'Võ Văn Dũng - con hổ giữa những đường gươm','3':'Trần Quang Diệu - vị tướng của kỷ luật và lòng trung','4':'Nguyễn Văn Tuyết - người cưỡi gió trong đêm hành quân','5':'Lê Văn Hưng - thanh đao trong cơn binh lửa','6':'Lý Văn Bưu - bóng hổ trên đất võ','7':'Nguyễn Văn Lộc - người giữ lửa trong hàng ngũ Tây Sơn','8':'Võ Đình Tú - dấu ấn của một thế hệ võ nhân','9':'Những chiến công làm rung chuyển non sông','10':'Đóng góp của Thất Hổ Tướng với phong trào Tây Sơn','11':'Di sản sau cơn bão','12':'Khúc cuối của những con hổ'}

def clean_text(txt):
    txt=txt.replace('\r\n','\n').replace('\r','\n')
    txt=re.sub(r'[ \t]+',' ',txt)
    txt=re.sub(r'\n{3,}','\n\n',txt).strip()+"\n"
    return txt

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().title()
        elif low.startswith('series:'):
            series=s.split(':',1)[1].strip()
        elif low.startswith('nội dung:'):
            in_body=True
        elif in_body or (not low.startswith(('tiêu đề truyện:','series:')) and s):
            body.append(s)
    return title,series,'\n\n'.join(body).strip()

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

def chunk_para(para, max_chars=360):
    sents=split_sentences(para)
    chunks=[]; cur=''
    for s in sents:
        if cur and len(cur)+1+len(s)>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 'võ văn dũng' in t: return 'Võ Văn Dũng trong khí chất tướng lĩnh Bình Định, gươm trận và doanh trại Tây Sơn.'
    if 'trần quang diệu' in t: return 'Trần Quang Diệu nghiêm nghị giữa quân doanh, thành lũy Quy Nhơn và không khí bi tráng cuối Tây Sơn.'
    if 'nguyễn văn tuyết' in t: return 'Nguyễn Văn Tuyết cưỡi ngựa hành quân thần tốc trong đêm, cờ Tây Sơn tung bay.'
    if 'lê văn hưng' in t: return 'Lê Văn Hưng như thanh đao trong binh lửa, tướng sĩ Tây Sơn xông pha trận mạc.'
    if 'lý văn bưu' in t: return 'Lý Văn Bưu trên đất võ Bình Định, võ đường dân gian hòa vào khói lửa khởi nghĩa.'
    if 'nguyễn văn lộc' in t: return 'Nguyễn Văn Lộc giữ lửa trong hàng ngũ Tây Sơn, đội quân áo vải trên nhiều chiến trường.'
    if 'võ đình tú' in t: return 'Võ Đình Tú đại diện lớp võ nhân dân gian, roi quyền và sa trường hòa làm một.'
    if 'rạch gầm' in t or 'xoài mút' in t: return 'Thủy chiến Rạch Gầm - Xoài Mút trên sông Tiền, thuyền chiến và khói lửa.'
    if 'ngọc hồi' in t or 'đống đa' in t or 'quân thanh' in t: return 'Chiến thắng Ngọc Hồi - Đống Đa, quân Tây Sơn thần tốc tiến vào Thăng Long.'
    if 'tây sơn' in t: return 'Phong trào Tây Sơn giữa cơn bão lịch sử Đại Việt cuối thế kỷ XVIII.'
    return f'Cảnh lịch sử minh họa cho đoạn {section}, tông bi tráng, phong vị Tây Sơn cuối thế kỷ XVIII.'

def build_scenes(title, series, body):
    scenes=[]; sid=1; section='Mở đầu'; current_heading=''
    for block in [b.strip() for b in body.split('\n\n') if b.strip()]:
        m=re.match(r'^(\d+)\.\s+(.+)$', block)
        if m:
            num=m.group(1); current_heading=SECTION_TITLES.get(num, m.group(2).strip().capitalize())
            scenes.append({'scene_id':f'scene_{sid:03d}','type':'heading','section':current_heading,'summary':current_heading,'narration':current_heading,'text':current_heading,'visual_beat':f'Title-card heading for section: {current_heading}','visual_prompt':f'Light Vietnamese old-calligraphy title-card on warm antique paper: {current_heading}','estimated_seconds':4,'rule':'heading_must_be_own_scene'})
            sid+=1; section=current_heading; continue
        for chunk in chunk_para(block):
            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':visual_for(chunk,section),'visual_prompt':visual_for(chunk,section)+' 16:9 horizontal historical storytelling image, ink-wash window centered on warm antique paper, Vietnamese co phong feeling.','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=[
        ('Nguyễn Huệ - Quang Trung','central historical leader','mid 30s to early 40s','Áo vải nhưng uy nghi, ánh mắt sắc, dáng chỉ huy thần tốc','Áo giáp/áo chiến bào Tây Sơn giản dị, khăn vấn, tông nâu đỏ','quyết đoán, thần tốc, uy dũng','Tây Sơn cuối thế kỷ XVIII, Phú Xuân, Bắc Hà, Rạch Gầm - Ngọc Hồi','quang trung, áo vải, cờ tây sơn, thần tốc','Không vẽ như vua Trung Hoa/fantasy emperor'),
        ('Võ Văn Dũng','Tây Sơn Thất Hổ Tướng','40s','Tướng Bình Định rắn rỏi, ít lời, dáng võ nhân','Chiến bào thô, giáp nhẹ, gươm dài','bền bỉ, trung thành, quyết liệt','Bình Định thượng võ, trụ cột Tây Sơn','vo van dung, gươm, bình định, trung dũng','Không làm quá fantasy'),
        ('Trần Quang Diệu','Tây Sơn danh tướng','40s','Khuôn mặt điềm tĩnh, nghiêm nghị, khí chất thống soái','Giáp chỉ huy, áo choàng trận, mũ võ tướng','kỷ luật, trung nghĩa, bi tráng','Cuối triều Tây Sơn, Quy Nhơn, chống Nguyễn Ánh','tran quang dieu, thành quy nhơn, kỷ luật','Không nhầm thành quan văn'),
        ('Nguyễn Văn Tuyết','Tây Sơn hổ tướng','30s-40s','Nhanh nhẹn, mạnh mẽ, dáng kỵ binh/đột kích','Trang phục hành quân nhẹ, kiếm hoặc thương','táo bạo, linh hoạt, thần tốc','Bắc tiến, hành quân ra Thăng Long','nguyen van tuyet, kỵ mã, hành quân đêm','Không đứng tĩnh quá lâu'),
        ('Lê Văn Hưng','Tây Sơn hổ tướng','30s-40s','Võ tướng gan dạ, vóc dáng chắc khỏe','Áo trận, thanh đao, khăn võ','dũng cảm, truyền lửa binh sĩ','Chiến tranh cuối thế kỷ XVIII','le van hung, thanh đao, binh lửa','Không gán chiến công cụ thể thiếu căn cứ'),
        ('Lý Văn Bưu','Tây Sơn hổ tướng dân gian','30s-40s','Võ nhân đất võ, thân pháp mạnh','Võ phục Bình Định, roi/gươm','bí ẩn, bản lĩnh, dân gian','Đất võ Bình Định, truyền thuyết Tây Sơn','ly van buu, đất võ, võ đường','Không biến thành nhân vật thần thoại'),
        ('Nguyễn Văn Lộc','Tây Sơn hổ tướng','30s-40s','Tướng lĩnh âm thầm, cứng cỏi','Chiến phục hành quân, vũ khí nhẹ','kiên trì, giữ lửa, chịu hiểm nguy','Đội ngũ chỉ huy Tây Sơn trên nhiều chiến trường','nguyen van loc, hàng ngũ tây sơn','Không cần hào nhoáng'),
        ('Võ Đình Tú','Tây Sơn hổ tướng dân gian','30s-40s','Võ nhân dân gian, gân guốc, dáng chiến binh','Võ phục/chiến phục đơn giản, roi hoặc đao','mãnh liệt, trực diện','Ranh giới võ đường và sa trường Tây Sơn','vo dinh tu, võ nhân, roi quyền','Không tạo sheet võ thuật'),
        ('Bùi Thị Xuân','female Tây Sơn general','30s-40s','Nữ tướng mạnh mẽ, ánh mắt kiên cường','Giáp nữ tướng kín đáo, áo chiến màu trầm','quả cảm, trung nghĩa','Cuối Tây Sơn, cùng Trần Quang Diệu trong ký ức bi tráng','bui thi xuan, nữ tướng tây sơn','Không sexualize/modernize'),
        ('Nguyễn Ánh','opposing historical force','30s-40s','Dáng vương giả, kiên trì, ánh mắt lạnh','Trang phục chúa Nguyễn/quân phục quyền lực','bền bỉ, tính toán','Gia Định, cuộc chiến chống Tây Sơn','nguyen anh, gia định, đối thủ','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 late 18th century Đại Việt/Tây Sơn.','consistency_rules':['Preserve Vietnamese late-18th-century clothing, weapons, flags, terrain.','Use character refs before scenes where recurring figures appear clearly.','Avoid fantasy armor, modern objects, Chinese/European drift unless historically justified.'],'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):
    path=PROJECT/'checklist_19_steps.json'; doc=json.loads(path.read_text(encoding='utf-8'))
    doc['current_step']=current; doc['updated_at']=NOW()
    for st in doc['steps']:
        if st['step']<=done_upto:
            st['status']='done'; 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
    path.write_text(json.dumps(doc,ensure_ascii=False,indent=2),encoding='utf-8')
    lines=['# Checklist 19 Steps','',f"Project ID: {doc['project_id']}",f"Channel: {doc['channel']}",f"Workflow version: {doc['workflow_version']}",f"Current step: {doc['current_step']}",f"Updated at: {doc['updated_at']}",'',f"Rule: {doc['checklist_rule']}",'']
    for st in doc['steps']:
        box='[x]' if st['status']=='done' else '[ ]'; lines += [f"## {box} Step {st['step']:02d} - {st['name']}",'',f"Status: {st['status']}"]
        if st.get('completed_at'): lines.append(f"Completed at: {st['completed_at']}")
        lines += ['','Input:']+[f"- {x}" for x in st['input']]+['','Output:']+[f"- {x}" for x in st['output']]+['','Validation:']+[f"- {'[x]' if st['status']=='done' else '[ ]'} {x}" for x in st['validation']]+['']
    (PROJECT/'checklist_19_steps.md').write_text('\n'.join(lines),encoding='utf-8')

def main():
    raw=SOURCE.read_text(encoding='utf-8'); clean=clean_text(raw); 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':not any(s['narration'].lower().startswith(('tiêu đề truyện:','series:','nội dung:')) for s in scenes),'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),'valid':True}
    vals['valid']=vals['metadata_excluded_from_scenes'] and vals['duplicate_narration_count']==0 and vals['long_scene_count']==0 and len(heads)==12
    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={'project_id':PROJECT.name,'step':4,'status':'completed_pending_user_approval','approved_for_next_step':False,'total_scenes':len(scenes),'required_fields_present':all(all(k in s for k in ['scene_id','summary','narration','visual_prompt']) for s in scenes),'duplicate_narration_count':vals['duplicate_narration_count'],'heading_scenes':len(heads),'visual_beat_scenes':len(visuals),'notes':['Dense plan is generated and validated. Stop here for user review/approval before Step 5.']}
    step4['valid_for_review']=step4['required_fields_present'] and step4['duplicate_narration_count']==0
    STEP4.write_text(json.dumps(step4,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),'step4':'completed_pending_user_approval'},ensure_ascii=False))
if __name__=='__main__': main()
