"""本地隔离复现；需 Python 3.10+、playwright 和 Chromium。"""
import functools, importlib.metadata, io, json, platform, struct, sys, threading, wave
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from urllib.parse import urlsplit
from playwright.sync_api import sync_playwright

FOLDER = Path(__file__).resolve().parent
class Handler(SimpleHTTPRequestHandler):
    def log_message(self, *args): pass
    def do_GET(self):
        path = urlsplit(self.path).path
        if path in ('/tone.wav', '/short.wav'):
            seconds = 4 if path == '/tone.wav' else 0.4
            out = io.BytesIO()
            with wave.open(out, 'wb') as w:
                w.setparams((1, 2, 8000, 0, 'NONE', 'not compressed'))
                # 原创数字静音，验证状态和事件，不输出实体扬声器声音。
                w.writeframes(b'\0\0' * int(8000 * seconds))
            data = out.getvalue()
            range_header=self.headers.get('Range','')
            if range_header.startswith('bytes='):
                start_text,end_text=range_header[6:].split('-',1)
                start=int(start_text or 0);end=min(int(end_text) if end_text else len(data)-1,len(data)-1)
                part=data[start:end+1];self.send_response(206)
                self.send_header('Content-Range',f'bytes {start}-{end}/{len(data)}')
            else:
                part=data;self.send_response(200)
            self.send_header('Accept-Ranges','bytes');self.send_header('Content-Type', 'audio/wav')
            self.send_header('Content-Length', str(len(part))); self.end_headers(); self.wfile.write(part)
        elif path in ('/image.png', '/cors.png'):
            # 原创1×1红像素PNG；只用于同一计算机两个端口的安全边界验证。
            import zlib
            def chunk(t, d):
                return struct.pack('!I', len(d))+t+d+struct.pack('!I',zlib.crc32(t+d)&0xffffffff)
            data=b'\x89PNG\r\n\x1a\n'+chunk(b'IHDR',struct.pack('!2I5B',1,1,8,6,0,0,0))+chunk(b'IDAT',zlib.compress(b'\0\xff\0\0\xff'))+chunk(b'IEND',b'')
            self.send_response(200); self.send_header('Content-Type','image/png')
            if path == '/cors.png': self.send_header('Access-Control-Allow-Origin','*')
            self.send_header('Content-Length',str(len(data))); self.end_headers(); self.wfile.write(data)
        else: super().do_GET()

def run(page, context, browser, base, other):
    r=page.evaluate('test()')
    assert r['singleErased']==[0,0,0,0] and r['foregroundErased']==[0,0,0,0]
    assert r['separateBackground']==[0,128,0,255]
    return r

def main():
    servers=[]; threads=[]
    try:
        for _ in range(2):
            server=ThreadingHTTPServer(('127.0.0.1',0),functools.partial(Handler,directory=str(FOLDER)))
            thread=threading.Thread(target=server.serve_forever,daemon=True); thread.start()
            servers.append(server); threads.append(thread)
        base,other=[f'http://127.0.0.1:{s.server_port}' for s in servers]
        with sync_playwright() as p:
            browser=p.chromium.launch(headless=True,args=['--use-gl=angle','--use-angle=swiftshader','--enable-unsafe-swiftshader'])
            try:
                context=browser.new_context(viewport={'width':900,'height':700})
                # 所有页面请求只允许本脚本拥有的两个随机端口。
                allowed={s.server_port for s in servers}
                def route_local(route):
                    u=urlsplit(route.request.url)
                    if u.scheme in ('data','blob','about') or (u.hostname=='127.0.0.1' and u.port in allowed): route.continue_()
                    else: route.abort()
                context.route('**/*',route_local)
                page=context.new_page();page.set_default_timeout(8000)
                page.goto(base+'/fixture.html')
                result=run(page,context,browser,base,other)
                report={'case':'C08-N04','passed':True,'python':platform.python_version(),'playwright':importlib.metadata.version('playwright'),'browser':browser.version,'backend':'Chromium headless；ANGLE SwiftShader启动参数；WebGL实际renderer见题内结果','input_scope':'Canvas2D或WebGL1页面API与像素读取；非指针输入、非实体GPU性能测量','result':result,'unmeasured':['实体触摸屏和GPU性能','Firefox/Safari/WebView','辅助技术朗读与真人可用性','目标展项和业务服务']}
                output=json.dumps(report,ensure_ascii=False,indent=2)
                (FOLDER/'execution.json').write_text(output+'\n',encoding='utf-8');print(output)
            finally: browser.close()
    finally:
        for server in servers: server.shutdown();server.server_close()
        for thread in threads: thread.join(timeout=2)

if __name__=='__main__': main()
