# -*- 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('anchors.csv','role,subtitle_seconds,video_seconds\nfit_start,0,2\nfit_end,100,104\ncheck,50,53\n');seed('drifted.vtt','WEBVTT\n\n00:00:10.000 --> 00:00:12.000\nSynthetic cue.\n')
rows=list(csv.DictReader((BASE/'anchors.csv').open()));x1,y1=float(rows[0]['subtitle_seconds']),float(rows[0]['video_seconds']);x2,y2=float(rows[1]['subtitle_seconds']),float(rows[1]['video_seconds'])
if NEG:x2=x1
if x2<=x1:raise ValueError('拟合锚点时间必须不同且升序')
a=(y2-y1)/(x2-x1);b=y1-a*x1
if a<=0:raise ValueError('速度比例必须为正')
def sub(m):
    h,mi,se,ms=map(int,m.groups());s=h*3600+mi*60+se+ms/1000;t=a*s+b
    if t<0:raise ValueError('校正后时间为负')
    n=round(t*1000);return f'{n//3600000:02}:{n//60000%60:02}:{n//1000%60:02}.{n%1000:03}'
write('resynced.vtt',re.sub(r'(\d{2}):(\d{2}):(\d{2})\.(\d{3})',sub,(BASE/'drifted.vtt').read_text(encoding='utf-8')));check=[]
for r in rows[2:]:
    x,y=float(r['subtitle_seconds']),float(r['video_seconds']);check.append([x,y,a*x+b,a*x+b-y,x+b-y])
table('residuals.csv',['subtitle','video','affine_pred','affine_residual','offset_only_residual'],check);emit({'scale':a,'offset':b,'third_anchor_residual':check[0][3],'offset_only_residual':check[0][4]})
