from pathlib import Path
import argparse
import copy
import csv
import hashlib
import io
import json
import re

parser = argparse.ArgumentParser()
parser.add_argument("--actual")
parser.add_argument("--local-http", action="store_true")
args = parser.parse_args()
checks = []
def check(condition, label):
    if not condition:
        raise ValueError(label)
    checks.append(label)
def load(name): return json.loads(Path(name).read_text())
def rows(name): return list(csv.DictReader(io.StringIO(Path(name).read_text(encoding="utf-8-sig"))))
def negative(fn, value, label):
    try: fn(value)
    except (ValueError, AssertionError, KeyError, TypeError, IndexError): checks.append(label)
    else: raise AssertionError("Negative input accepted: " + label)
original=Path("participants.csv").read_bytes(); data=rows("participants.csv")
check(len(data)==8 and len({r["id"] for r in data})==8,"eight unique participants")
check(sum(int(r["devices"]) for r in data)==10,"ten devices total")
expected={"sha256":hashlib.sha256(original).hexdigest(),"bytes":len(original),"rows":8,"devices":10}
def validate(v):
    if any(v.get(k)!=value for k,value in expected.items()):raise ValueError("receipt does not match input file")
negative(validate,{**expected,"rows":7},"wrong upload row count rejected")
if args.local_http:
    import threading,urllib.request
    from server import Handler,ThreadingHTTPServer
    service=ThreadingHTTPServer(("127.0.0.1",0),Handler)
    thread=threading.Thread(target=service.serve_forever,daemon=True);thread.start()
    boundary="qr-lesson-multipart"
    body=("--"+boundary+'\r\nContent-Disposition: form-data; name="file"; filename="participants.csv"\r\nContent-Type: text/csv\r\n\r\n').encode()+original+("\r\n--"+boundary+"--\r\n").encode()
    try:
        req=urllib.request.Request("http://127.0.0.1:"+str(service.server_port)+"/upload",data=body,headers={"Content-Type":"multipart/form-data; boundary="+boundary})
        with urllib.request.urlopen(req,timeout=10) as response: validate(json.load(response))
        checks.append("real local multipart transport matched receipt; no browser Agent involved")
    finally:service.shutdown();service.server_close()
if args.actual:validate(load(args.actual));checks.append("actual server receipt matches original bytes")
report={"layer":"offline/material checks, not proof of unrun product or model", "checks":checks, "count":len(checks)}
Path("verification.json").write_text(json.dumps(report,ensure_ascii=False,indent=2))
print(json.dumps(report,ensure_ascii=False))
