# -*- 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))

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
points=[(0,0)]*70+[(1,1)]*20+[(2,0)]*10+[(3,3)]*5
if not (BASE/'points.csv').exists():table('points.csv',['x','y'],points)
points=[(float(r['x']),float(r['y'])) for r in csv.DictReader((BASE/'points.csv').open())]
if NEG:points.append((float('nan'),1))
valid=[p for p in points if all(math.isfinite(x) for x in p) and all(-.5<=x<=3.5 for x in p)];excluded=[p for p in points if p not in valid];fig,ax=plt.subplots(1,2,figsize=(10,4));ax[0].scatter(*zip(*valid),s=24);ax[0].set_title('Scatter: repeated coordinates');hb=ax[1].hexbin(*zip(*valid),gridsize=5,extent=(-.5,3.5,-.5,3.5),mincnt=1,cmap='Blues');fig.colorbar(hb,ax=ax[1],label='count');ax[1].set_title('Hexbin counts');fig.tight_layout();fig.savefig(BASE/'scatter-vs-hexbin.svg');plt.close(fig)
counts=hb.get_array().tolist();centers=hb.get_offsets().tolist();table('bin-counts.csv',['center_x','center_y','count'],[[*center,int(count)] for center,count in zip(centers,counts)]);jwrite('excluded.json',[[str(x),str(y)] for x,y in excluded]);emit({'valid':len(valid),'count_sum':sum(counts),'largest_bin':max(counts),'excluded':len(excluded)})
