# -*- coding: utf-8 -*-
"""原创离线合成样例；不连接模型、不读取账户。输出位于脚本旁。
已有输入保留，修改输入后可以重跑。失败边界由 --negative 单独演示。
"""
from pathlib import Path
import sys, json, csv, math, io, hashlib, html, base64, re
sys.stdout.reconfigure(encoding='utf-8')
sys.stderr.reconfigure(encoding='utf-8')
BASE = Path(__file__).resolve().parent
NEG = '--negative' in sys.argv
def write(name, value):
    p=BASE/name; p.parent.mkdir(parents=True,exist_ok=True)
    if isinstance(value,bytes): p.write_bytes(value)
    else: p.write_text(value,encoding='utf-8',newline='')
def seed(name,value):
    if not (BASE/name).exists(): write(name,value)
def jwrite(name,value): write(name,json.dumps(value,ensure_ascii=False,indent=2))
def jseed(name,value):
    if not (BASE/name).exists(): jwrite(name,value)
def load(name): return json.loads((BASE/name).read_text(encoding='utf-8'))
def table(name,heads,rows):
    f=io.StringIO(newline='');w=csv.writer(f);w.writerow(heads);w.writerows(rows);write(name,f.getvalue())
def page(name,title,body):
    write(name,'<!doctype html><html lang="zh-CN"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>'+html.escape(title)+'</title><style>body{max-width:1000px;margin:2rem auto;padding:0 1rem;font:17px/1.7 system-ui}table{border-collapse:collapse}td,th{border:1px solid #aaa;padding:.5rem}pre{white-space:pre-wrap;overflow-wrap:anywhere}img,svg{max-width:100%;height:auto}a{color:#125caa}</style><h1>'+html.escape(title)+'</h1>'+body+'</html>')
def emit(data): print(json.dumps(data,ensure_ascii=False))

seed('original.vtt','WEBVTT\n\nc1\n00:00:01.000 --> 00:00:06.000\nThis sentence crosses a cut.\n\nc2\n00:00:06.000 --> 00:00:08.000\nSecond sentence.\n')
seed('keep-ranges.csv','start,end\n0,3\n5,9\n');keep=[(float(r['start']),float(r['end'])) for r in csv.DictReader((BASE/'keep-ranges.csv').open())]
if NEG:keep=[(5,9),(0,3)]
if any(b<=a or a<0 for a,b in keep) or any(keep[i][1]>keep[i+1][0] for i in range(len(keep)-1)):raise ValueError('保留区间需升序、不重叠且长度为正')
def sec(t):
    h,m,s=t.split(':');return int(h)*3600+int(m)*60+float(s)
def stamp(s):
    ms=round(s*1000);return f'{ms//3600000:02}:{ms//60000%60:02}:{ms//1000%60:02}.{ms%1000:03}'
out=['WEBVTT',''];lineage=[]
for block in (BASE/'original.vtt').read_text(encoding='utf-8').strip().split('\n\n')[1:]:
    cue,timing,text=block.split('\n',2);a,b=map(sec,timing.split(' --> '));offset=0;piece=0
    for left,right in keep:
        lo,hi=max(a,left),min(b,right)
        if hi>lo:
            piece+=1;start,end=offset+lo-left,offset+hi-left;out.extend([cue+'-'+str(piece),stamp(start)+' --> '+stamp(end),text,'']);lineage.append([cue,lo,hi,start,end,'review_text' if lo!=a or hi!=b else 'unchanged'])
        offset+=right-left
write('edited.vtt','\n'.join(out));table('lineage.csv',['cue_id','source_start','source_end','new_start','new_end','text_status'],lineage);emit({'segments':lineage})
