# -*- 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('multiline.csv','name,note\n甲,"第一行\n第二行"\n乙,"含,逗号"\n丙,普通\n丁,"引号""保留"\n戊,最后\n')
with (BASE/'multiline.csv').open(encoding='utf-8',newline='') as input_file:raw=input_file.read()
if NEG: raw+='坏,"没有闭合\n'
parsed=list(csv.reader(io.StringIO(raw,newline=''),strict=True));heads=parsed[0];rows=parsed[1:]
if any(len(row)!=len(heads) for row in rows): raise ValueError('记录字段数不一致')
mapping=[]
for start in range(0,len(rows),2):
    batch=start//2+1;part=rows[start:start+2];table(f'batch-{batch}.csv',['row_id']+heads,[[f'r{start+i+1:04}']+r for i,r in enumerate(part)])
    mapping.extend([[f'r{i+1:04}',i+1,batch,i-start+1] for i in range(start,start+len(part))])
table('row-map.csv',['row_id','source_record','batch','batch_record'],mapping);collected={}
for file in sorted(BASE.glob('batch-*.csv')):
    records=list(csv.reader(file.open(encoding='utf-8',newline=''),strict=True))
    if records[0]!=['row_id']+heads: raise ValueError('批次表头被改动')
    for row in records[1:]:
        if row[0] in collected:raise ValueError('重复row_id')
        collected[row[0]]=row[1:]
expected=[m[0] for m in mapping]
if set(collected)!=set(expected):raise ValueError('批次缺失或多余记录')
table('recombined.csv',heads,[collected[key] for key in expected]);emit({'batches':math.ceil(len(rows)/2),'records':len(collected),'roundtrip_equal':list(csv.reader((BASE/'recombined.csv').open(encoding='utf-8',newline='')))==parsed,'first_note':collected['r0001'][1]})
