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

PROJECT = Path('/data/video-pipeline/Youtube-Video-Maker/Project/12062026-001-Nha-Tien-Le')
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 Đại Cồ Việt đứng trước cửa sinh tử',
    '2': 'Lê Hoàn - người từ chiến trận bước lên ngôi vua',
    '3': 'Cuộc kháng chiến chống Tống năm 981',
    '4': 'Sau chiến thắng - dựng lại trật tự đất nước',
    '5': 'Phương Nam và cuộc chinh phạt Chiêm Thành',
    '6': 'Triều đình Hoa Lư và những mầm mống bất ổn',
    '7': 'Lê Long Đĩnh - vị vua cuối cùng của nhà Tiền Lê',
    '8': 'Lý Công Uẩn và sự chuyển giao năm 1009 - 1010',
    '9': 'Di sản của nhà Tiền Lê',
    '10': 'Ba mươi năm ngắn ngủi, một dấu ấn không thể xóa',
}

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()
        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ê hoàn' in t or 'lê đại hành' in t: return 'Lê Hoàn trong chiến bào Hoa Lư, ánh mắt quyết đoán giữa quân doanh Đại Cồ Việt.'
    if 'dương vân nga' in t: return 'Thái hậu Dương Vân Nga trong cung Hoa Lư, khoảnh khắc trao long bào đầy áp lực lịch sử.'
    if 'tống' in t or 'hầu nhân bảo' in t or 'bạch đằng' in t: return 'Chiến trận chống Tống năm 981, sông Bạch Đằng, thuyền chiến, núi rừng và khói lửa.'
    if 'chiêm thành' in t or 'paramesvaravarman' in t: return 'Đoàn quân Đại Cồ Việt nam tiến, kinh thành Chiêm Thành và không khí chinh phạt thế kỷ X.'
    if 'lê long đĩnh' in t or 'ngọa triều' in t: return 'Triều đình cuối Tiền Lê u ám, Lê Long Đĩnh gây tranh cãi giữa bóng tối quyền lực.'
    if 'lý công uẩn' in t or 'thăng long' in t or 'đại la' in t: return 'Lý Công Uẩn bước ra từ triều Hoa Lư, hướng về Đại La - Thăng Long trong bình minh mới.'
    if 'hoa lư' in t: return 'Kinh đô Hoa Lư hiểm trở, núi đá vôi, sông ngòi và cung điện thời đầu độc lập.'
    return f'Cảnh lịch sử Đại Cồ Việt thời Tiền Lê minh họa đoạn {section}, bi tráng và trang nghiêm.'

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 10th-century Đại Cồ Việt.', '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ê Hoàn / Lê Đại Hành','founding emperor and military commander','40s-60s','Uy nghi, rắn rỏi, ánh mắt của võ tướng từng trải','Chiến bào Đại Cồ Việt, giáp nhẹ, khăn/mũ võ tướng Hoa Lư','quyết đoán, mưu lược, cứng rắn','Hoa Lư, chống Tống 981, chinh phạt Chiêm Thành','le hoan, le dai hanh, hoa lu, bach dang','Không vẽ như hoàng đế Trung Hoa hoặc fantasy king'),
        ('Dương Vân Nga','queen dowager and political pivot','30s-40s','Gương mặt điềm tĩnh nhưng nặng suy tư','Triều phục hoàng hậu thế kỷ X, màu trầm, kín đáo','sáng suốt, chịu áp lực, đặt quốc gia lên trước','Cung Hoa Lư năm 980, chuyển giao quyền lực','duong van nga, long bao, hoa lu','Không sexualize hoặc hiện đại hóa'),
        ('Đinh Toàn','child emperor of Nhà Đinh','child','Vị vua nhỏ tuổi, mong manh giữa biến động triều chính','Áo bào trẻ em hoàng gia giản dị','non trẻ, bị cuốn vào thời cuộc','Hoa Lư sau biến cố 979','dinh toan, child king','Không làm thành nhân vật trưởng thành'),
        ('Hầu Nhân Bảo và quân Tống','invading Song general and army','40s','Tướng Tống cứng cỏi cùng quân xâm lược phương Bắc','Giáp quân Tống thế kỷ X, cờ hiệu phương Bắc','kiêu ngạo, áp lực quân sự','Biên giới phía Bắc và chiến dịch 981','hau nhan bao, quan tong','Không biến thành quái vật'),
        ('Quân dân Đại Cồ Việt','collective defenders','mixed ages','Binh sĩ và dân chúng Đại Cồ Việt gan góc','Trang phục dân binh, giáo mác, thuyền chiến, nón lá thô','kiên cường, đoàn kết','Sông Bạch Đằng, núi rừng Hoa Lư, ruộng đồng sau chiến tranh','dai co viet soldiers, bach dang','Không dùng đồ hiện đại'),
        ('Sứ giả và triều đình Chiêm Thành','southern diplomatic and military force','mixed ages','Sứ giả, vương triều và binh sĩ Chăm','Trang phục Chăm thế kỷ X, màu đất, hoa văn bản địa','kiêu hãnh, căng thẳng ngoại giao','Quan hệ Đại Cồ Việt - Chiêm Thành năm 982','champa, chiem thanh','Không nhầm với Khmer/Trung Hoa'),
        ('Lê Long Đĩnh','last emperor of Early Lê','20s-30s','Khuôn mặt sắc lạnh, bệnh tật và quyền lực gây tranh cãi','Long bào u tối, cung đình cuối Tiền Lê','bất ổn, tàn bạo theo sử cũ, nhiều tranh cãi','Hoa Lư 1005-1009','le long dinh, ngoạ trieu','Không phóng đại thành ác quỷ'),
        ('Lý Công Uẩn','future founder of Lý dynasty','30s','Võ tướng/đại thần ôn hòa, chính trực','Quan phục - chiến phục trang nhã, ảnh hưởng Phật giáo','điềm đạm, có đức, được tin cậy','Cổ Pháp, Hoa Lư, dời đô Thăng Long 1010','ly cong uan, co phap, thang long','Không vẽ quá già'),
    ]
    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 10th-century Đại Cồ Việt / Hoa Lư / Nhà Tiền Lê.', 'consistency_rules': ['Preserve Vietnamese 10th-century clothing, weapons, terrain, and Hoa Lư limestone setting.', 'Use character refs before scenes where recurring figures appear clearly.', 'Avoid modern objects, fantasy armor, Chinese palace 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'] = '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
    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"Current step: {doc['current_step']}", f"Updated at: {doc['updated_at']}", '']
    for st in doc['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) == 10
    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()
