# 브라우저에서 fab.html 을 열고 구조해석 버튼을 실제로 눌러 확인한다.
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_browser.png"

# 화면에 판재 1장(300x40x6, 30도 기울임)을 넣고 fab_scene 과 똑같이 선택 하이라이트를 칠한다.
INJECT = r"""
() => {
  const T = window.FAB.THREE;
  const L=300,b=40,t=6, a=Math.PI/6;
  const c=[[0,0,0],[L,0,0],[L,b,0],[0,b,0],[0,0,t],[L,0,t],[L,b,t],[0,b,t]]
    .map(p=>[p[0]*Math.cos(a)-p[1]*Math.sin(a)+1234, p[0]*Math.sin(a)+p[1]*Math.cos(a)-567, p[2]+89]);
  const q=[[0,1,2,3],[4,5,6,7],[0,1,5,4],[2,3,7,6],[1,2,6,5],[0,3,7,4]];
  const pos=[];
  for(const f of q) for(const tr of [[0,1,2],[0,2,3]]) for(const k of tr) pos.push(...c[f[k]]);
  const g=new T.BufferGeometry();
  g.setAttribute('position', new T.Float32BufferAttribute(pos,3));
  g.computeVertexNormals();
  const m=new T.MeshStandardMaterial({color:0xcbd5e1, side:T.DoubleSide});
  const mesh=new T.Mesh(g,m); mesh.name='TESTPLATE_300x40x6';
  window.FAB.scene.add(mesh);
  m.emissive.setHex(0x224a6e);                        // fab_scene 94행과 동일한 선택 표시
  document.getElementById('fab-selname').textContent = mesh.name;
  return {verts: g.attributes.position.count};
}
"""

async def main():
    logs, errs = [], []
    async with async_playwright() as p:
        br = await p.chromium.launch()
        pg = await br.new_page(viewport={'width':1600,'height':950})
        pg.on('console', lambda m: logs.append(f'[{m.type}] {m.text}'))
        pg.on('pageerror', lambda e: errs.append(str(e)))
        await pg.goto(URL, timeout=30000)
        await pg.wait_for_timeout(3500)

        print('1) 모듈 로드 :', await pg.evaluate("() => !!window.FAB_FEA && !!window.FAB"))
        print('2) 툴바 버튼 :', await pg.locator('#fab-fea-btn').count(), '개')

        await pg.locator('#fab-fea-btn').click()
        await pg.wait_for_timeout(400)
        print('3) 패널 열림 :', await pg.evaluate(
            "() => getComputedStyle(document.getElementById('fab-fea-panel')).display"))
        print('   도크 안인가:', await pg.evaluate(
            "() => document.getElementById('fab-fea-panel').closest('#fab-right') !== null"))

        inj = await pg.evaluate(INJECT)
        print('4) 시험 판재 :', inj, '정점')
        print('   findSelected:', await pg.evaluate(
            "() => { const m = window.FAB_FEA.findSelected(); return m ? m.name : null; }"))

        print('   패널 위치   :', await pg.evaluate("""() => {
            const p=document.getElementById('fab-fea-panel'), r=p.getBoundingClientRect();
            const d=p.parentElement, dr=d.getBoundingClientRect();
            return {panel:[r.x|0,r.y|0,r.width|0,r.height|0], dockId:d.id,
                    dock:[dr.x|0,dr.y|0,dr.width|0,dr.height|0],
                    dockDisp:getComputedStyle(d).display, dockVis:getComputedStyle(d).visibility};
        }"""))
        await pg.locator('#fab-fea-panel button').click()
        await pg.wait_for_timeout(9000)

        print('5) 패널 출력 :')
        txt = await pg.locator('#fab-fea-panel > div:last-child').inner_text()
        for line in txt.split('\n'):
            if line.strip(): print('     ', line.strip())

        print('6) 결과 오버레이:', await pg.evaluate("""() => {
            let n=0, tri=0, marker=0;
            window.FAB.scene.traverse(o=>{ if(o.userData && o.userData.__feaOverlay){
                o.traverse(c=>{ if(c.isMesh){ n++;
                  if(c.geometry.index) tri += c.geometry.index.count/3;
                  if(c.material.color && c.material.color.getHex()===0xff2d3d) marker++; }});
            }});
            return {메시:n, 삼각형:tri, 취약점구슬:marker};
        }"""))
        print('   원본 판재 색 유지:', await pg.evaluate(
            "() => { let ok=null; window.FAB.scene.traverse(o=>{ if(o.name==='TESTPLATE_300x40x6') ok=o.material.color.getHexString(); }); return ok; }"))

        # 결과 오버레이가 화면에 보이도록 카메라를 그쪽으로 돌린다(확인용).
        await pg.evaluate('''() => {
            const T=window.FAB.THREE, cam=window.FAB.camera;
            const box=new T.Box3(); let g=null;
            window.FAB.scene.traverse(o=>{ if(o.userData && o.userData.__feaOverlay) g=o; });
            box.setFromObject(g);
            const ctr=box.getCenter(new T.Vector3()), sz=box.getSize(new T.Vector3());
            const r=sz.length()*1.1;
            cam.position.set(ctr.x+r*0.55, ctr.y+r*0.55, ctr.z+r*0.62);
            cam.lookAt(ctr); cam.near=1; cam.updateProjectionMatrix();
        }''')
        await pg.wait_for_timeout(800)
        await pg.screenshot(path=SHOT)
        await br.close()

    bad = [l for l in logs if 'error' in l.lower() or 'FEA' in l]
    print('\n콘솔(관련):')
    for l in bad[:12]: print('   ', l[:180])
    print('페이지 오류:', errs if errs else '없음')
    print('스크린샷:', SHOT)

asyncio.run(main())
