# 블럭#6 자기몸 충돌검사 검증 (2026-07-13)
# ① 로드 콘솔에러 0 ② 홈자세 자기충돌 없음 ③ 극단자세 충돌 발생 ④ 검사 소요시간
import asyncio
from playwright.async_api import async_playwright

# 관절한계 내 극단 후보 자세 (L/U를 접어 하완·손목을 베이스 쪽으로)
CANDS = [
    {'S':0,'L':-105,'U':160,'R':0,'B':-135,'T':0},
    {'S':0,'L':-105,'U':160,'R':0,'B':90,'T':0},
    {'S':0,'L':-90,'U':160,'R':0,'B':-135,'T':0},
    {'S':0,'L':-105,'U':150,'R':0,'B':-120,'T':0},
    {'S':0,'L':-80,'U':160,'R':150,'B':-135,'T':0},
    {'S':0,'L':155,'U':-86,'R':0,'B':-135,'T':0},
    {'S':0,'L':-60,'U':160,'R':0,'B':-135,'T':0},
    {'S':0,'L':-105,'U':120,'R':0,'B':-135,'T':0},
]

async def run():
    errs = []
    async with async_playwright() as p:
        br = await p.chromium.launch(channel='msedge', headless=True)
        pg = await br.new_page(viewport={'width':1280,'height':800})
        pg.on('console', lambda m: errs.append(m.text) if m.type=='error' else None)
        await pg.goto('http://localhost:8090/DOZIKWORKS_OS_v5_locked.dc.html', timeout=15000)
        await pg.wait_for_timeout(6000)  # 메쉬·BVH 로드 대기

        st = await pg.evaluate('''() => ({
            mod: typeof window.DZW_SELF_COLLIDE,
            ready: window.DZW_SELF_COLLIDE?.ready(),
            pairs: window.DZW_SELF_COLLIDE?.pairs,
        })''')
        print('모듈:', st['mod'], '/ ready:', st['ready'])
        print('검사쌍(%d):' % len(st['pairs'] or []), st['pairs'])

        # 홈자세 검사
        home = await pg.evaluate('''() => {
            const a=window.__dzw, sc=window.DZW_SELF_COLLIDE;
            const t0=performance.now(); const hit=sc.check(); const ms=performance.now()-t0;
            const d=sc.dist();
            return {joints:{...a.state.joints}, hit, ms:+ms.toFixed(1),
                    dist: d?{d:+d.d.toFixed(1), pair:d.pair}:null};
        }''')
        print('홈자세:', home)

        # 극단 자세들 — 실제 교차 발생 자세 탐색
        found = None
        for J in CANDS:
            r = await pg.evaluate('''(J) => {
                const sc=window.DZW_SELF_COLLIDE;
                const t0=performance.now(); const hit=sc.check(J); const ms=performance.now()-t0;
                const d=sc.dist(J);
                return {hit, ms:+ms.toFixed(1), dist: d?{d:+d.d.toFixed(1), pair:d.pair}:null};
            }''', J)
            print('자세', J, '→', r)
            if r['hit'] and not found:
                found = (J, r)

        # 실시간 루프 UX 확인: setJoints로 충돌 자세 이동 → 경고/HUD
        if found:
            J = found[0]
            ux = await pg.evaluate('''async (J) => {
                const a=window.__dzw;
                a.setJoints({...J});
                await new Promise(r=>setTimeout(r,800));  // 300ms 루프 2회
                const msgs=(a.state.msgs||[]).slice(-3).map(m=>m.text||m.msg||JSON.stringify(m));
                return {collision:a.state.collision, msgs};
            }''', J)
            print('실시간 UX:', ux)
            await pg.evaluate('() => window.__dzw.setJoints({S:0,L:0,U:0,R:0,B:0,T:0})')
            await pg.wait_for_timeout(500)

        await pg.screenshot(path='05_BROWSER_TESTS/_self_collision_shot.png')
        print('콘솔 에러 %d개:' % len(errs), errs[:5])
        await br.close()
        print('충돌자세 발견:' , found[0] if found else '없음 (관절한계 내 미발견 — 거리로그로 로직 증명)')

asyncio.run(run())
