import asyncio
from playwright.async_api import async_playwright

JS = """
() => {
    var app = window.__dzw;
    var T = app._T;
    if(!app || !T) return {err:'no app'};

    app._grp.updateMatrixWorld(true);

    var results = [];
    var meshCount = 0;

    function wpos(obj) {
        var v = new T.Vector3();
        obj.getWorldPosition(v);
        return [+(v.x*1000).toFixed(1), +(v.y*1000).toFixed(1), +(v.z*1000).toFixed(1)];
    }

    function getParentChain(obj) {
        var names = [];
        var cur = obj.parent;
        var depth = 0;
        while(cur && depth < 8) {
            var label = cur.type + (cur === app._grp ? '(grp)' :
                        cur === app._robotGrp ? '(rg)' :
                        cur === app.gj.S ? '(ang.S)' :
                        cur === app.gj.L ? '(ang.L)' :
                        cur === app.gj.U ? '(ang.U)' :
                        cur === app.gj.R ? '(ang.R)' :
                        cur === app.gj.B ? '(ang.B)' :
                        cur === app.gj.T ? '(ang.T)' : '');
            names.push(label);
            cur = cur.parent;
            depth++;
        }
        return names.join(' > ');
    }

    // scene 전체 순회
    app._grp.traverse(function(obj) {
        if(!obj.isMesh && obj.type !== 'Group' && obj.type !== 'AxesHelper') return;

        var wp = wpos(obj);
        var isFloating = Math.abs(wp[2]) > 400 || Math.abs(wp[0]) > 3000 || Math.abs(wp[1]) > 3000;

        if(obj.isMesh) {
            meshCount++;
            var vCount = obj.geometry && obj.geometry.attributes && obj.geometry.attributes.position
                         ? obj.geometry.attributes.position.count : 0;
            results.push({
                type: 'Mesh',
                name: obj.name || '(no name)',
                verts: vCount,
                wp: wp,
                floating: isFloating,
                visible: obj.visible,
                parent: getParentChain(obj)
            });
        }
    });

    // _robotGrp 직계 자식 목록 (그룹 포함)
    var rgChildren = [];
    if(app._robotGrp) {
        app._robotGrp.children.forEach(function(c) {
            rgChildren.push({
                type: c.type,
                name: c.name || '(no name)',
                pos: [+c.position.x.toFixed(1), +c.position.y.toFixed(1), +c.position.z.toFixed(1)],
                childCount: c.children ? c.children.length : 0
            });
        });
    }

    // _grp 직계 자식 (여러 _robotGrp이 있나?)
    var grpChildren = [];
    app._grp.children.forEach(function(c) {
        grpChildren.push({
            type: c.type,
            name: c.name || '(no name)',
            pos: [+c.position.x.toFixed(1), +c.position.y.toFixed(1), +c.position.z.toFixed(1)],
            isRobotGrp: c === app._robotGrp,
            childCount: c.children ? c.children.length : 0
        });
    });

    // ang 각 노드의 로컬 position + rotation (URDF 구조 확인)
    var angInfo = {};
    var gj = app.gj;
    ['S','L','U','R','B','T'].forEach(function(a) {
        if(!gj[a]) return;
        var n = gj[a];
        var piv = n.parent; // pivot Group
        angInfo[a] = {
            piv_pos: piv ? [+piv.position.x.toFixed(1),+piv.position.y.toFixed(1),+piv.position.z.toFixed(1)] : null,
            piv_rpy: piv ? [+(piv.rotation.x*180/Math.PI).toFixed(2),+(piv.rotation.y*180/Math.PI).toFixed(2),+(piv.rotation.z*180/Math.PI).toFixed(2)] : null,
            ang_rz: +(n.rotation.z*180/Math.PI).toFixed(2),
            worldPos: wpos(n),
            meshCount: 0
        };
        n.children.forEach(function(c) { if(c.isMesh) angInfo[a].meshCount++; });
    });

    return {
        meshCount: meshCount,
        results: results,
        rgChildren: rgChildren,
        grpChildren: grpChildren,
        angInfo: angInfo
    };
}
"""

async def main():
    async with async_playwright() as p:
        br = await p.chromium.launch(headless=True)
        pg = await br.new_page()
        await pg.set_viewport_size({'width': 1536, 'height': 1024})
        await pg.goto('http://localhost:8090/DOZIKWORKS_OS_v4_pathcreate.dc.html')
        await pg.wait_for_timeout(18000)

        r = await pg.evaluate(JS)

        print(f'=== 총 메시 수: {r["meshCount"]}개 ===\n')

        print('── _grp 직계 자식 (여러 robotGrp 있으면 로봇 2개) ──')
        for c in r['grpChildren']:
            flag = ' ★ _robotGrp' if c['isRobotGrp'] else ''
            print(f'  {c["type"]}  pos={c["pos"]}  children={c["childCount"]}{flag}')

        print('\n── _robotGrp 직계 자식 ──')
        for c in r['rgChildren']:
            print(f'  {c["type"]}  name={c["name"]}  pos={c["pos"]}  children={c["childCount"]}')

        print('\n── 떠있는 메시 (Z>400mm 또는 XY>3000mm) ──')
        floating = [m for m in r['results'] if m['floating'] and m['visible']]
        if not floating:
            print('  없음')
        for m in floating:
            print(f'  verts={m["verts"]:5d}  wp={m["wp"]}  parent: {m["parent"]}')

        print('\n── 전체 메시 목록 (부모 그룹별) ──')
        for m in r['results']:
            flag = ' ★FLOAT' if m['floating'] else ''
            vis = '' if m['visible'] else ' [hidden]'
            print(f'  verts={m["verts"]:5d}  wp={m["wp"]}  {m["parent"]}{flag}{vis}')

        print('\n── ang 노드 상태 (URDF 체인) ──')
        for a, info in r['angInfo'].items():
            print(f'  {a}: piv_pos={info["piv_pos"]}  piv_rpy(deg)={info["piv_rpy"]}  ang.rz={info["ang_rz"]}°  worldPos={info["worldPos"]}  직계mesh={info["meshCount"]}')

        await pg.screenshot(path='diag_scene.png')
        print('\n스크린샷 → diag_scene.png')
        await br.close()

asyncio.run(main())
