"""
드래그 궤적 티칭 검증 — RoboDK 방식
마우스를 누른 채 드래그 → 그 궤적이 경로로 기록되는지 확인
"""
import asyncio, os
from playwright.async_api import async_playwright

OUT = r'E:\도진팩토리\3D스캔및티칭시스템\shots'
os.makedirs(OUT, exist_ok=True)

async def shot(pg, name):
    await pg.screenshot(path=os.path.join(OUT, name))
    print(f'  [스샷] {name}')

async def main():
    async with async_playwright() as p:
        br = await p.chromium.launch(headless=False, args=['--window-size=1536,864'])
        pg = await br.new_page(viewport={'width':1536,'height':864})
        pg.on('console', lambda m: print(f'  [{m.type}] {m.text}') if m.type in ('error','warn','log') else None)

        print('=== 1. 페이지 로드 ===')
        await pg.goto('http://localhost:8090/DOZIKWORKS_OS_v5_locked.dc.html')
        await pg.wait_for_timeout(4000)

        print('\n=== 2. 너클붐 선택 + 티칭 시작 ===')
        await pg.evaluate('() => { window.__dzw._knuckleSelect&&window.__dzw._knuckleSelect(); }')
        await pg.wait_for_timeout(500)
        await pg.evaluate('() => DZW5_EDGEPATH.startTeachSegment(window.__dzw)')
        await pg.wait_for_timeout(300)
        mode = await pg.evaluate('() => !!window.__dzw._hoverTeachMode')
        print(f'  _hoverTeachMode: {mode}')

        print('\n=== 3. 너클붐 위치 스캔 ===')
        hit_info = await pg.evaluate('''() => {
            const app=window.__dzw, mesh=app._knuckleMesh, cam=app.three&&app.three.cam;
            if(!mesh||!cam) return {err:'없음'};
            cam.updateMatrixWorld();
            const canvas=document.querySelector('canvas');
            const r=canvas.getBoundingClientRect();
            let hits=[];
            for(let py=r.top+20;py<r.bottom-20;py+=20)
              for(let px=r.left+20;px<r.right-20;px+=25){
                const mx=((px-r.left)/r.width)*2-1, my=-((py-r.top)/r.height)*2+1;
                app._ray.setFromCamera({x:mx,y:my},cam);
                const h=app._ray.intersectObjects([mesh],true);
                if(h.length) hits.push({px:Math.round(px),py:Math.round(py)});
              }
            return {count:hits.length, first:hits[0]||null, mid:hits[Math.floor(hits.length/2)]||null, last:hits[hits.length-1]||null};
        }''')
        print(f'  너클붐 히트: {hit_info["count"]}개')

        if not hit_info.get('first'):
            print('  너클붐 화면에 없음 — FIT 후 재시도')
            await pg.evaluate('''()=>{
                const btns=document.querySelectorAll("button");
                for(const b of btns) if(b.textContent.trim()==="FIT"){b.click();return;}
            }''')
            await pg.wait_for_timeout(1500)
            hit_info = await pg.evaluate('''() => {
                const app=window.__dzw, mesh=app._knuckleMesh, cam=app.three&&app.three.cam;
                if(!mesh||!cam) return {count:0,first:null,mid:null,last:null};
                cam.updateMatrixWorld();
                const canvas=document.querySelector('canvas');
                const r=canvas.getBoundingClientRect();
                let hits=[];
                for(let py=r.top+20;py<r.bottom-20;py+=20)
                  for(let px=r.left+20;px<r.right-20;px+=25){
                    const mx=((px-r.left)/r.width)*2-1, my=-((py-r.top)/r.height)*2+1;
                    app._ray.setFromCamera({x:mx,y:my},cam);
                    const h=app._ray.intersectObjects([mesh],true);
                    if(h.length) hits.push({px:Math.round(px),py:Math.round(py)});
                  }
                return {count:hits.length, first:hits[0]||null, mid:hits[Math.floor(hits.length/2)]||null, last:hits[hits.length-1]||null};
            }''')
            print(f'  FIT 후 히트: {hit_info["count"]}개')

        await shot(pg, 'drag_01_before.png')

        first = hit_info.get('first')
        last = hit_info.get('last')
        if not first or not last:
            print('  너클붐 히트 없음 — 중단')
            await br.close(); return

        # 드래그 시작점과 끝점 (너클붐 위에서)
        x1, y1 = first['px'], first['py']
        x2, y2 = last['px'], last['py']
        print(f'\n=== 4. 드래그 궤적 티칭: ({x1},{y1}) → ({x2},{y2}) ===')

        pts_before = await pg.evaluate('() => window.__dzw._currentSegmentPts?.length||0')
        print(f'  드래그 전 점: {pts_before}개')

        # 마우스 누른 채 드래그
        await pg.mouse.move(x1, y1)
        await pg.mouse.down(button='left')
        await pg.wait_for_timeout(100)

        steps = 20
        for i in range(1, steps+1):
            xi = x1 + (x2-x1)*i//steps
            yi = y1 + (y2-y1)*i//steps
            await pg.mouse.move(xi, yi)
            await pg.wait_for_timeout(30)

        await pg.mouse.up(button='left')
        await pg.wait_for_timeout(500)

        pts_after = await pg.evaluate('() => window.__dzw._currentSegmentPts?.length||0')
        drag_pts = await pg.evaluate('() => window.__dzw._dragTeaching')
        anchors = await pg.evaluate('() => window.__dzw._teachAnchors?.length||0')
        print(f'  드래그 후 점: {pts_after}개 (추가됨: {pts_after-pts_before}개)')
        print(f'  앵커 수: {anchors}개')
        print(f'  _dragTeaching: {drag_pts}')

        await shot(pg, 'drag_02_after.png')

        # 구간 완료
        print('\n=== 5. 구간 완료 ===')
        await pg.evaluate('() => DZW5_EDGEPATH.finishTeachSegment(window.__dzw)')
        await pg.wait_for_timeout(500)
        segs = await pg.evaluate('() => window.__dzw._teachSegments?.length||0')
        print(f'  확정 구간: {segs}개')
        await shot(pg, 'drag_03_finish.png')

        print('\n=== 결과 ===')
        ok = pts_after > pts_before + 3 and segs >= 1
        print('✅ 드래그 궤적 티칭 성공!' if ok else f'❌ 실패 — 점 추가={pts_after-pts_before}, 구간={segs}')
        print(f'shots 폴더: {OUT}')

        await pg.wait_for_timeout(3000)
        await br.close()

asyncio.run(main())
