<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>{{title}}</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- Potree 1.8 from potree.github.io -->
    <script src="https://potree.github.io/potree/libs/jquery/jquery-3.1.1.min.js"></script>
    <script src="https://potree.github.io/potree/libs/spectrum/spectrum.js"></script>
    <script src="https://potree.github.io/potree/libs/jquery-ui/jquery-ui.min.js"></script>
    <script src="https://potree.github.io/potree/libs/three.js/build/three.min.js"></script>
    <script src="https://potree.github.io/potree/libs/other/BinaryHeap.js"></script>
    <script src="https://potree.github.io/potree/libs/tween/tween.min.js"></script>
    <script src="https://potree.github.io/potree/libs/d3/d3.js"></script>
    <script src="https://potree.github.io/potree/libs/proj4/proj4.js"></script>
    <script src="https://potree.github.io/potree/libs/openlayers3/ol.js"></script>
    <script src="https://potree.github.io/potree/libs/i18next/i18next.js"></script>
    <script src="https://potree.github.io/potree/libs/jstree/jstree.js"></script>
    <script src="https://potree.github.io/potree/build/potree/potree.js"></script>
    <link href="https://potree.github.io/potree/libs/spectrum/spectrum.css" rel="stylesheet" />
    <link href="https://potree.github.io/potree/libs/jquery-ui/jquery-ui.min.css" rel="stylesheet" />
    <link href="https://potree.github.io/potree/libs/openlayers3/ol.css" rel="stylesheet" />
    <link href="https://potree.github.io/potree/libs/jstree/themes/mixed/style.css" rel="stylesheet" />
    <link href="https://potree.github.io/potree/build/potree/potree.css" rel="stylesheet" />
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        html, body { height: 100%; overflow: hidden; background: #000; }
        #potree_render_area { position: absolute; top: 0; bottom: 0; left: 0; right: 0; }
    </style>
</head>
<body>
    <div id="potree_render_area"></div>
    <script>
        // Viewer state from Python
        const state = {{state}};

        // Track loaded point clouds
        const pointClouds = {};

        // Initialize Potree viewer
        const viewer = new Potree.Viewer(document.getElementById('potree_render_area'));

        // Configure viewer
        viewer.setEDLEnabled(state.edl_enabled);
        viewer.setEDLRadius(state.edl_radius);
        viewer.setEDLStrength(state.edl_strength);
        viewer.setPointBudget(state.point_budget);
        viewer.setFOV(state.fov);
        viewer.setBackground(state.background);

        // Load point clouds from state
        Object.entries(state.point_clouds || {}).forEach(function([name, config]) {
            loadPointCloud(config.url, name, config.material, config.visible);
        });

        // Replay JS calls (skip loadPointCloud since already handled above)
        for (const call of state.js_calls || []) {
            if (call.method === 'loadPointCloud') continue;
            try {
                executeMethod(call.method, call.args, call.kwargs);
            } catch (e) {
                console.error('Error executing', call.method, e);
            }
        }

        function loadPointCloud(url, name, material, visible) {
            Potree.loadPointCloud(url, name, function(e) {
                viewer.scene.addPointCloud(e.pointcloud);
                pointClouds[name] = e.pointcloud;

                // Apply material settings
                if (material) {
                    const mat = e.pointcloud.material;
                    if (material.size !== undefined) mat.size = material.size;
                    if (material.pointSizeType) {
                        const types = { fixed: 0, attenuated: 1, adaptive: 2 };
                        mat.pointSizeType = types[material.pointSizeType] || 2;
                    }
                    if (material.shape) {
                        const shapes = { square: 0, circle: 1, paraboloid: 2 };
                        mat.shape = shapes[material.shape] || 1;
                    }
                    if (material.color) {
                        mat.color = new THREE.Color(material.color);
                    }
                }

                e.pointcloud.visible = visible !== false;

                // Fit camera to show all point clouds
                viewer.fitToScreen();
            });
        }

        function executeMethod(method, args, kwargs) {
            switch (method) {
                case 'removePointCloud': {
                    const pc = pointClouds[kwargs.name];
                    if (pc) {
                        viewer.scene.removePointCloud(pc);
                        delete pointClouds[kwargs.name];
                    }
                    break;
                }

                case 'setPointCloudVisibility': {
                    const pc = pointClouds[kwargs.name];
                    if (pc) pc.visible = kwargs.visible;
                    break;
                }

                case 'setCameraPosition': {
                    viewer.scene.view.position.set(kwargs.x, kwargs.y, kwargs.z);
                    break;
                }

                case 'setCameraTarget': {
                    viewer.scene.view.lookAt(new THREE.Vector3(kwargs.x, kwargs.y, kwargs.z));
                    break;
                }

                case 'flyToPointCloud': {
                    if (kwargs.name && pointClouds[kwargs.name]) {
                        viewer.zoomTo(pointClouds[kwargs.name], 1);
                    } else {
                        viewer.fitToScreen();
                    }
                    break;
                }

                case 'resetCamera': {
                    viewer.fitToScreen();
                    break;
                }

                case 'setPointBudget': {
                    viewer.setPointBudget(kwargs.budget);
                    break;
                }

                case 'setPointSize': {
                    Object.values(pointClouds).forEach(function(pc) {
                        pc.material.size = kwargs.size;
                    });
                    break;
                }

                case 'setFOV': {
                    viewer.setFOV(kwargs.fov);
                    break;
                }

                case 'setBackground': {
                    viewer.setBackground(kwargs.color);
                    break;
                }

                case 'setEDL': {
                    viewer.setEDLEnabled(kwargs.enabled);
                    viewer.setEDLRadius(kwargs.radius);
                    viewer.setEDLStrength(kwargs.strength);
                    break;
                }

                default:
                    console.log('Unknown method:', method);
            }
        }
    </script>
</body>
</html>
