# -*- 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))

from datetime import datetime,timedelta,timezone
seed('schedule.ics','BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Original Example//Offline//ZH\r\nBEGIN:VEVENT\r\nUID:synthetic-plan-b2@example.invalid\r\nDTSTAMP:20261024T000000Z\r\nDTSTART:20261102T010000Z\r\nDTEND:20261102T013000Z\r\nRRULE:FREQ=WEEKLY;COUNT=5\r\nEXDATE:20261116T010000Z\r\nSUMMARY:Original practice session\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n')
lines=(BASE/'schedule.ics').read_text(encoding='utf-8').splitlines();props=dict(line.split(':',1) for line in lines if ':' in line);fmt='%Y%m%dT%H%M%SZ';start=datetime.strptime(props['DTSTART'],fmt).replace(tzinfo=timezone.utc);end=datetime.strptime(props['DTEND'],fmt).replace(tzinfo=timezone.utc);ex=datetime.strptime(props['EXDATE'],fmt).replace(tzinfo=timezone.utc)
if NEG: end=start-timedelta(minutes=1)
if end<=start: raise ValueError('事件结束不得早于开始')
count=int(props['RRULE'].split('COUNT=')[1]);occ=[start+timedelta(weeks=i) for i in range(count) if start+timedelta(weeks=i)!=ex]
table('expanded-occurrences.csv',['start_utc','end_utc'],[[t.isoformat(),(t+(end-start)).isoformat()] for t in occ]);write('import-notes.txt','导入单独测试日历。核对4次事件与11月16日排除；本例固定UTC，对应北京时间周一09:00，不演示夏令时。UID相同不保证客户端重复导入自动更新。此文件没有邀请参与者。');emit({'occurrences':[t.isoformat() for t in occ]})
