# 실제 제품 블럭을 불러와, 실제 클릭 선택 경로로 부재를 고른 뒤 구조해석까지 돌린다.
# (fab_material.js 가 재질을 갈아끼운 '진짜' 부재로 findSelected 가 맞는지 확인)
import asyncio, json
from playwright.async_api import async_playwright

URL = "http://127.0.0.1:8099/fab.html"
SHOT = r"C:\Users\user\AppData\Local\Temp\dzw_fea\fea_real.png"

async def main():
    errs = []
    async with async_playwright() as p:
        br = await p.chromium.launch()
        pg = await br.new_page(viewport={'width': 1600, 'height': 950})
        pg.on('pageerror', lambda e: errs.append(str(e)))
        await pg.goto(URL, timeout=30000)
        await pg.wait_for_timeout(3000)

        # 1) 실제 제품 블럭 로드 (fab_material.js 가 감싼 진짜 경로)
        n = await pg.evaluate("""async () => {
            const m = await (await fetch('fab_models/400q/manifest_400q.json')).json();
            const parts = m.items.slice(0, 12).map((it,i)=>({name:it.name, file:it.file, path:'G01/P'+i}));
            await window.FAB.loadBlock('400Q_TEST', parts);
            let c=0; window.FAB.scene.traverse(o=>{ if(o.isMesh && o.name) c++; });
            return c;
        }""")
        print('1) 실제 블럭 로드 : 부재 %d개 (fab_material 재질 적용됨)' % n)
        print('   재질 확인      :', await pg.evaluate("""() => {
            const ms=[]; window.FAB.scene.traverse(o=>{ if(o.isMesh && o.name && o.material && o.material.emissive) ms.push(o); });
            if(ms.length<2) return {부재수:ms.length, 경고:'재질 있는 부재 2개 미만'};
            const a=ms[0], b=ms[1];
            return {emissive_기본: a.material.emissive.getHexString(),
                    부재별_독립재질: a.material !== b.material,
                    색상_구분: a.material.color.getHexString()+' vs '+b.material.color.getHexString()};
        }"""))

        # 2) 진짜 선택 경로: FAB.selectMode() + 캔버스 클릭
        await pg.evaluate("() => window.FAB.selectMode()")
        box = await pg.locator('#fab-canvas').bounding_box()
        picked = None
        for (dx, dy) in [(0.5,0.5),(0.45,0.45),(0.55,0.55),(0.5,0.42),(0.4,0.55),(0.6,0.5)]:
            await pg.mouse.click(box['x']+box['width']*dx, box['y']+box['height']*dy)
            await pg.wait_for_timeout(250)
            picked = await pg.evaluate("() => document.getElementById('fab-selname').textContent.trim()")
            if picked: break
        print('2) 실제 클릭 선택 : "%s"' % picked)

        chk = await pg.evaluate("""() => {
            const f = window.FAB_FEA.findSelected();
            let meshes=0, verts=0, names=[];
            if(f) f.traverse(c=>{ if(c.isMesh && c.name!=='__fab_edge'){ meshes++;
                verts+=c.geometry.attributes.position.count; if(names.length<3) names.push(c.name); }});
            return {선택타입: f? (f.isGroup?'Group':'Mesh') : null, 선택이름: f? f.name : null,
                    부품수: meshes, 총정점: verts, 예시부품: names};
        }""")
        print('3) findSelected  :', chk['선택타입'], '"%s"' % chk['선택이름'])
        print('   묶인 부품수    :', chk['부품수'], '/ 총정점', chk['총정점'])
        print('   판정           :', 'OK (선택 인식됨)' if chk['부품수'] > 0 else 'FAIL (선택 못 찾음)')

        # 3) 그 부재로 실제 해석
        await pg.locator('#fab-fea-btn').click()
        await pg.wait_for_timeout(500)
        await pg.locator('#fab-fea-panel button').click()
        await pg.wait_for_timeout(15000)
        print('4) 해석 결과 패널 :')
        for line in (await pg.locator('#fab-fea-panel > div:last-child').inner_text()).split('\n'):
            if line.strip(): print('     ', line.strip())

        print('5) 결과 오버레이 :', await pg.evaluate("""() => {
            let tri=0, mk=0;
            window.FAB.scene.traverse(o=>{ if(o.userData && o.userData.__feaOverlay)
                o.traverse(c=>{ if(c.isMesh){ if(c.geometry.index) tri+=c.geometry.index.count/3;
                  if(c.material.color && c.material.color.getHex()===0xff2d3d) mk++; }}); });
            return {삼각형:tri, 취약점구슬:mk};
        }"""))
        await pg.screenshot(path=SHOT)
        await br.close()
    print('페이지 오류:', errs if errs else '없음')
    print('스크린샷:', SHOT)

asyncio.run(main())
