<template>
  <div id="app">
    <div ref="mapContainer" class="map-container"></div>
    <canvas ref="threeCanvas" class="three-canvas"></canvas>
    
    <div class="layer-controls">
      <div class="control-section">
        <label>Base Map:</label>
        <label><input type="radio" value="osm" v-model="baseLayer" @change="updateBaseLayer"> Street</label>
        <label><input type="radio" value="satellite" v-model="baseLayer" @change="updateBaseLayer"> Satellite</label>
      </div>
      
      <div class="control-section">
        <label>
          <input type="checkbox" v-model="showOctagon" @change="toggleOctagon">
          Show Octagon
        </label>
        <label>
          <input type="checkbox" v-model="showLidar" @change="toggleLidar">
          Show Lidar
        </label>
      </div>
    </div>
  </div>
</template>

<script>
import { ref, onMounted, onUnmounted } from 'vue';
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import * as THREE from 'three';

export default {
  name: 'App',
  setup() {
    const mapContainer = ref(null);
    const threeCanvas = ref(null);
    let map = null;
    let scene = null;
    let camera = null;
    let renderer = null;
    let lidarMeshes = [];
    const baseLayer = ref('osm');
    const showOctagon = ref(true);
    const showLidar = ref(true);

    // Newark Octagon coordinates (converted from DMS to decimal)
    const octagonCoords = [
      [-82.44133, 40.05431], // 40°03'15.5"N 82°26'28.8"W
      [-82.44264, 40.05311], // 40°03'11.2"N 82°26'33.5"W
      [-82.44464, 40.05242], // 40°03'08.7"N 82°26'40.7"W
      [-82.44631, 40.05342], // 40°03'12.3"N 82°26'46.7"W
      [-82.44728, 40.05500], // 40°03'18.0"N 82°26'50.2"W
      [-82.44589, 40.05633], // 40°03'22.8"N 82°26'45.2"W
      [-82.44389, 40.05697], // 40°03'25.1"N 82°26'38.0"W
      [-82.44192, 40.05589], // 40°03'21.2"N 82°26'30.9"W
      [-82.44133, 40.05431], // Close the polygon
    ];

    const octagonCenter = [-82.44383, 40.05469];

    onMounted(() => {
      map = new maplibregl.Map({
        container: mapContainer.value,
        style: {
          version: 8,
          sources: {
            'osm': {
              type: 'raster',
              tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'],
              tileSize: 256,
              attribution: '© OpenStreetMap contributors'
            },
            'satellite': {
              type: 'raster',
              tiles: [
                'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'
              ],
              tileSize: 256,
              attribution: 'Esri, Maxar, Earthstar Geographics, USDA FSA, USGS, Aerogrid, IGN, IGP, and the GIS User Community'
            }
          },
          layers: [
            {
              id: 'osm-layer',
              type: 'raster',
              source: 'osm',
              layout: { visibility: 'visible' }
            },
            {
              id: 'satellite-layer',
              type: 'raster',
              source: 'satellite',
              layout: { visibility: 'none' }
            }
          ]
        },
        center: octagonCenter,
        zoom: 15
      });

      map.on('load', () => {
        // Add octagon source and layer
        map.addSource('octagon', {
          type: 'geojson',
          data: {
            type: 'Feature',
            geometry: {
              type: 'Polygon',
              coordinates: [octagonCoords]
            }
          }
        });

        map.addLayer({
          id: 'octagon-fill',
          type: 'fill',
          source: 'octagon',
          paint: {
            'fill-color': '#ff0000',
            'fill-opacity': 0.2
          }
        });

        map.addLayer({
          id: 'octagon-outline',
          type: 'line',
          source: 'octagon',
          paint: {
            'line-color': '#ff0000',
            'line-width': 2
          }
        });

        // Initialize Three.js
        initThreeJS();
        loadLidarTiles();
        
        // Update Three.js on map move
        map.on('move', updateThreeCamera);
        map.on('zoom', updateThreeCamera);
      });
    });

    const updateBaseLayer = () => {
      if (!map) return;
      
      if (baseLayer.value === 'osm') {
        map.setLayoutProperty('osm-layer', 'visibility', 'visible');
        map.setLayoutProperty('satellite-layer', 'visibility', 'none');
      } else {
        map.setLayoutProperty('osm-layer', 'visibility', 'none');
        map.setLayoutProperty('satellite-layer', 'visibility', 'visible');
      }
    };

    const toggleOctagon = () => {
      if (!map) return;
      
      const visibility = showOctagon.value ? 'visible' : 'none';
      map.setLayoutProperty('octagon-fill', 'visibility', visibility);
      map.setLayoutProperty('octagon-outline', 'visibility', visibility);
    };

    const toggleLidar = () => {
      lidarMeshes.forEach(mesh => {
        mesh.visible = showLidar.value;
      });
      if (renderer) renderer.render(scene, camera);
    };

    const initThreeJS = () => {
      scene = new THREE.Scene();
      
      camera = new THREE.OrthographicCamera(
        -1, 1, 1, -1, 0.1, 10000
      );
      camera.position.z = 1;
      
      renderer = new THREE.WebGLRenderer({
        canvas: threeCanvas.value,
        alpha: true,
        antialias: true
      });
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.setClearColor(0x000000, 0);
      
      const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
      scene.add(ambientLight);
      
      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
      directionalLight.position.set(1, 1, 1);
      scene.add(directionalLight);
      
      window.addEventListener('resize', handleResize);
      
      updateThreeCamera();
    };

    const handleResize = () => {
      if (!renderer || !camera) return;
      renderer.setSize(window.innerWidth, window.innerHeight);
      updateThreeCamera();
    };

    const updateThreeCamera = () => {
      if (!map || !camera || !renderer) return;
      
      const bounds = map.getBounds();
      const ne = bounds.getNorthEast();
      const sw = bounds.getSouthWest();
      
      camera.left = sw.lng;
      camera.right = ne.lng;
      camera.top = ne.lat;
      camera.bottom = sw.lat;
      camera.updateProjectionMatrix();
      
      renderer.render(scene, camera);
    };

    const parseMoundFile = async (url) => {
      const response = await fetch(url);
      const buffer = await response.arrayBuffer();
      
      const view = new DataView(buffer);
      let offset = 0;
      
      const magic = String.fromCharCode(
        view.getUint8(offset++),
        view.getUint8(offset++),
        view.getUint8(offset++),
        view.getUint8(offset++)
      );
      
      if (magic !== 'LIDR') {
        throw new Error('Invalid .mound file');
      }
      
      const version = view.getUint32(offset, true); offset += 4;
      const pointCount = view.getUint32(offset, true); offset += 4;
      const triangleCount = view.getUint32(offset, true); offset += 4;
      const minX = view.getFloat32(offset, true); offset += 4;
      const minY = view.getFloat32(offset, true); offset += 4;
      const minZ = view.getFloat32(offset, true); offset += 4;
      const maxX = view.getFloat32(offset, true); offset += 4;
      const maxY = view.getFloat32(offset, true); offset += 4;
      const maxZ = view.getFloat32(offset, true); offset += 4;
      offset += 24; // Skip reserved
      
      const positions = new Float32Array(buffer, offset, pointCount * 3);
      offset += pointCount * 3 * 4;
      
      const indices = new Uint32Array(buffer, offset, triangleCount * 3);
      
      return {
        pointCount,
        triangleCount,
        bounds: { minX, minY, minZ, maxX, maxY, maxZ },
        positions,
        indices
      };
    };

    const loadLidarTiles = async () => {
      const tiles = [
        'BS19820747',
        'BS19820748',
        'BS19830747',
        'BS19830748'
      ];
      
      for (const tileName of tiles) {
        try {
          console.log(`Loading ${tileName}...`);
          const data = await parseMoundFile(`/tiles/${tileName}.mound`);
          
          console.log(`${tileName} bounds:`, data.bounds);
          console.log(`First few positions:`, data.positions.slice(0, 15));
          
          const geometry = new THREE.BufferGeometry();
          geometry.setAttribute('position', new THREE.BufferAttribute(data.positions, 3));
          geometry.setIndex(new THREE.BufferAttribute(data.indices, 1));
          geometry.computeVertexNormals();
          
          const material = new THREE.MeshLambertMaterial({
            color: 0x8B7355,
            side: THREE.DoubleSide,
            wireframe: false
          });
          
          const mesh = new THREE.Mesh(geometry, material);
          scene.add(mesh);
          lidarMeshes.push(mesh);
          
          console.log(`Loaded ${tileName}: ${data.pointCount} points, ${data.triangleCount} triangles`);
          console.log(`Mesh position:`, mesh.position);
          console.log(`Mesh in scene:`, scene.children.length);
        } catch (err) {
          console.error(`Failed to load ${tileName}:`, err);
        }
      }
      
      console.log('Map bounds:', map.getBounds().toArray());
      console.log('Camera:', camera);
      
      updateThreeCamera();
    };

    onUnmounted(() => {
      window.removeEventListener('resize', handleResize);
      if (renderer) {
        renderer.dispose();
      }
    });

    return {
      mapContainer,
      threeCanvas,
      baseLayer,
      showOctagon,
      showLidar,
      updateBaseLayer,
      toggleOctagon,
      toggleLidar
    };
  }
};
</script>

<style>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

#app {
  width: 100vw;
  height: 100vh;
  position: relative;
}

.map-container {
  width: 100%;
  height: 100%;
}

.three-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.layer-controls {
  position: absolute;
  bottom: 20px;
  left: 20px;
  background: white;
  padding: 15px;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.3);
  font-family: Arial, sans-serif;
  font-size: 14px;
}

.control-section {
  margin-bottom: 10px;
}

.control-section:last-child {
  margin-bottom: 0;
}

.control-section label {
  display: block;
  margin: 5px 0;
  cursor: pointer;
}

.control-section label:first-child {
  font-weight: bold;
  margin-bottom: 8px;
  cursor: default;
}

.control-section input[type="radio"],
.control-section input[type="checkbox"] {
  margin-right: 8px;
  cursor: pointer;
}
</style>