/* ========================= */
    /*    GLOBALE VARIABLEN      */
    /* ========================= */
    let selectedPlacedModel = null;
    let currentSession = null;
    let reticle = null;
    let scene, camera;
    let geoLocation;
    const menus = ['menu-bar', 'add-menu', 'edit-menu', 'options-menu', 'map-window'];
    
    /* ========================= */
    /*          MODELLE          */
    /* ========================= */
    let models = {
      bench: {
        name: "Bench",
        image: "previewImages/bench.PNG",
        file: "/assets/models/bench_model/scene.gltf",
        scale: { x: 0.1, y: 0.1, z: 0.1 },
        minScale: 0.05, // 50% der aktuellen Größe
        maxScale: 0.5   // 500% der aktuellen Größe
      },
      trashbin: {
        name: "Trash bin",
        image: "previewImages/trash_can.PNG",
        file: "/assets/models/trash_model/scene.gltf",
        scale: { x: 0.03, y: 0.03, z: 0.03 },
        minScale: 0.01, // 50% der aktuellen Größe
        maxScale: 0.1   // 500% der aktuellen Größe
      },
      telephone_box: {
        name: "Telephone Box",
        image: "previewImages/telephone_box.PNG",
        file: "/assets/models/telephone_box_model/scene.gltf",
        scale: { x: 0.5, y: 0.5, z: 0.5 },
        minScale: 0.05,
        maxScale: 1
      },
      fire_hydrant_model: {
        name: "Fire Hydrant",
        image: "previewImages/hydrant.PNG",
        file: "/assets/models/fire_hydrant_model/scene.gltf",
        scale: { x: 0.3, y: 0.3, z: 0.3 },
        minScale: 0.1,
        maxScale: 1
      },
      statue: {
        name: "Statue",
        image: "previewImages/statue.PNG",
        file: "/assets/models/statue_model/scene.gltf",
        scale: { x: 0.5, y: 0.5, z: 0.5 },
        minScale: 0.05,
        maxScale: 2
      },
      fountain: {
        name: "Fountain",
        image: "previewImages/fountain.PNG",
        file: "/assets/models/fountain_model/scene.gltf",
        scale: { x: 0.001, y: 0.001, z: 0.001 },
        minScale: 0.0005,
        maxScale: 0.005
      },
      lantern: {
        name: "Lantern",
        image: "previewImages/lantern.jpg",
        file: "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/refs/heads/main/Models/Lantern/glTF/Lantern.gltf",
        scale: { x: 0.15, y: 0.15, z: 0.15 },
        minScale: 0.05,
        maxScale: 0.3
      }
    };

    /* ========================= */
    /*     INITIALISIERUNG       */
    /* ========================= */
    window.onload = () => {
      initializeAddMenu();

      // Allen Buttons den Sound hinzufügen
      const buttons = document.querySelectorAll("button, .menu-item");
      buttons.forEach(button => {
        button.addEventListener("click", playButtonSound);
      });
    };

    function initializeAddMenu() {
      const addMenu = document.getElementById('add-menu');
      addMenu.innerHTML = Object.entries(models)
        .map(
          ([key, model]) => `
            <div class="menu-item" id="${key}-item" onclick="selectModel('${key}')">
              <img src="${model.image}" alt="${model.name}" />
            </div>
          `
        )
        .join('') +
        `
        <div class="menu-item" onclick="showMenu('menu-bar')">
          <img src="previewImages/back-icon.png" alt="Zurück" />
        </div>
      `;
    }

    /* ========================= */
    /*     MENÜ-STEUERUNG        */
    /* ========================= */
    function showMenu(menuId) {
      const isMapWindow = menuId === 'map-window';
      if (isMapWindow && !geoLocation) {
        console.log("Standort nicht geladen");
        showInfoDialog("Ihr Standort wurde noch nicht geladen");
        return;
      }

      menus.forEach(id => {
        document.getElementById(id).style.display = id === menuId ? 'flex' : 'none';
      });
      closeDynamicMenu();
      if (menuId === 'menu-bar') clearSelectedModel();
      else if (isMapWindow) init_map();
    }

    function closeDynamicMenu() {
      const dynamicMenu = document.getElementById("dynamic-menu");
      dynamicMenu.style.display = "none";
    }

    /* ========================= */
    /*     MODELL-HANDLING       */
    /* ========================= */
    function getAllPlacedModels() {
      return scene.children.filter(child => child.isPlacedModel === true);
    }

    function loadModel(filePath) {
      placeModel(filePath, reticle.position, (model) => {
        selectedPlacedModel = model;
        highlightSelectedModel();
        showMenu('edit-menu');
      });
    }

    function placeModel(filePath, position, onPlace = null) {
      const modelConfig = Object.values(models).find(model => model.file === filePath);
      const loader = new THREE.GLTFLoader();
      loader.load(
        filePath,
        (gltf) => {
          const model = gltf.scene;
          if (modelConfig && modelConfig.scale) {
            model.scale.set(modelConfig.scale.x, modelConfig.scale.y, modelConfig.scale.z);
          }
          model.position.copy(position);
          model.isPlacedModel = true;
          model.modelConfig = modelConfig;
          scene.add(model);

          if (onPlace) {
            onPlace(model);
          }
        },
        undefined,
        (error) => {
          console.error("Fehler beim Laden des Modells:", error);
        }
      );
    }

    function selectModel(modelId) {
      const model = models[modelId];
      if (model && model.file) {
        loadModel(model.file);
        showMenu('menu-bar');
      }
    }

    function selectModelFromScene(event) {
      const mouse = new THREE.Vector2(
        (event.clientX / window.innerWidth) * 2 - 1,
        -(event.clientY / window.innerHeight) * 2 + 1
      );

      const raycaster = new THREE.Raycaster();
      raycaster.setFromCamera(mouse, camera);

      // Prüfe Kollisionen mit Objekten in der Szene
      const intersects = raycaster.intersectObjects(scene.children, true);

      if (intersects.length > 0) {
        // Finde das Hauptobjekt (Root-Parent), falls Mesh ausgewählt wurde
        let selectedObject = intersects[0].object;
        while (selectedObject.parent && selectedObject.parent !== scene) {
          selectedObject = selectedObject.parent;
        }

        // Überprüfe, ob das ausgewählte Objekt das Reticle ist
        if (selectedObject === reticle) {
          console.log("Reticle kann nicht ausgewählt werden.");
          return;
        }

        // Markiere das gesamte Modell als ausgewählt
        selectedPlacedModel = selectedObject;
        highlightSelectedModel();
        showMenu("edit-menu");
      }
    }

    function clearSelectedModel() {
      if (selectedPlacedModel) {
        selectedPlacedModel.traverse((child) => {
          if (child.isMesh) {
            child.material.emissive.setHex(0x000000); // Markierung entfernen
          }
        });
        selectedPlacedModel = null;
      }
    }

    function highlightSelectedModel() {
      if (selectedPlacedModel) {
        removeHighlightFromAllModels();
        selectedPlacedModel.traverse((child) => {
          if (child.isMesh) {
            child.material.emissive.setHex(0xff0000); // Rote Hervorhebung
          }
        });
      }
    }

    function removeHighlightFromSelectedModel() {
      if (selectedPlacedModel) {
        selectedPlacedModel.traverse((child) => {
          if (child.isMesh) child.material.emissive.setHex(0x000000); // Markierung entfernen
        });
      }
    }


      function removeHighlightFromAllModels() {
        scene.traverse((child) => {
          if (child.isMesh && child.material && child.material.emissive) {
            child.material.emissive.setHex(0x000000); // Markierung entfernen
          }
        });
      }
  
      function deleteModel() {
        if (!selectedPlacedModel) {
          console.log("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es löschen.");
          return;
        }
  
        const deleteDialog = document.getElementById('delete-confirmation-dialog');
        deleteDialog.style.display = 'flex';
      }

    function confirmDelete(shouldDelete) {
      const deleteDialog = document.getElementById('delete-confirmation-dialog');
      deleteDialog.style.display = 'none';

      if (shouldDelete && selectedPlacedModel) {
        scene.remove(selectedPlacedModel);
        selectedPlacedModel = null;
        showMenu('menu-bar');
      }
    }

    function completeEditing() {
      removeHighlightFromSelectedModel();
      closeDynamicMenu();
      selectedPlacedModel = null;
      document.getElementById('edit-menu').style.display = 'none';
      document.getElementById('menu-bar').style.display = 'flex';
    }

    /* ========================= */
    /*    BEARBEITUNGS-MENÜS     */
    /* ========================= */
    function openRotationMenu() {
      if (!selectedPlacedModel) {
        console.log("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es bearbeiten.");
        return;
      }

      const currentRotation = Math.round(THREE.MathUtils.radToDeg(selectedPlacedModel.rotation.y)); // Aktuelle Y-Rotation des Modells (in Grad)

      const dynamicMenu = document.getElementById("dynamic-menu");
      dynamicMenu.style.display = "flex";
      dynamicMenu.innerHTML = `
        <h3>Rotation anpassen</h3>
        <label>Y-Achse: <span id="current-rotation">${currentRotation}</span>°<input type="range" min="0" max="360" step="10" onchange="updateRotation('y', this.value)"></label>
        <button onclick="closeDynamicMenu()">Zurück</button>
      `;
    }

    function updateRotation(axis, value) {
      if (selectedPlacedModel) {
        const radians = (value / 180) * Math.PI;
        selectedPlacedModel.rotation[axis] = radians;

        // Anzeige der aktuellen Rotation im Dynamic-Menü aktualisieren
        const currentRotationDisplay = document.getElementById("current-rotation");
        if (currentRotationDisplay) {
          currentRotationDisplay.textContent = value; // Zeige den aktuellen Wert in Grad an
        }
      }
    }

    function openScaleMenu() {
      if (!selectedPlacedModel) {
        console.log("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es bearbeiten.");
        return;
      }

      // Aktuelle Skalierung und Grenzen bestimmen
      const currentScale = selectedPlacedModel.scale.x;
      const minScale = selectedPlacedModel.modelConfig.minScale;
      const maxScale = selectedPlacedModel.modelConfig.maxScale;
      const step = (maxScale - minScale) / 100; // Dynamische Schrittgröße basierend auf Grenzen

      const currentScalePercent = ((currentScale - minScale) / (maxScale - minScale)) * 100; // Umrechnung der Werte in Prozent

      const dynamicMenu = document.getElementById("dynamic-menu");
      dynamicMenu.style.display = "flex";
      dynamicMenu.innerHTML = `
        <h3>Skalierung anpassen</h3>
        <label>Größe: <span id="scale-value">${currentScalePercent.toFixed(0)}%</span>
        <input type="range" min="0" max="100" step="1" value="${currentScalePercent}" onchange="updateScale(this.value, ${minScale}, ${maxScale})"></label>
        <button onclick="closeDynamicMenu()">Zurück</button>
      `;
    }

    function updateScale(percentValue, minScale, maxScale) {
      if (selectedPlacedModel) {
        // Berechnung der Skalierung basierend auf dem Prozentwert
        const scale = minScale + (percentValue / 100) * (maxScale - minScale);
        selectedPlacedModel.scale.set(scale, scale, scale);

        // Anzeige des aktuellen Prozentsatzes im Dynamic-Menü aktualisieren
        const scaleValueDisplay = document.getElementById("scale-value");
        if (scaleValueDisplay) {
          scaleValueDisplay.textContent = `${parseInt(percentValue, 10)}%`;
        }
      }
    }

    let moveDelta = 0.1; // Standardwert für die Verschiebungsgröße, kann mit dem Slider geändert werden

    function openMoveMenu() {
      if (!selectedPlacedModel) {
        console.log("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es bewegen.");
        return;
      }

      const dynamicMenu = document.getElementById("dynamic-menu");
      dynamicMenu.style.display = "flex";

      dynamicMenu.innerHTML = `
    <h3>Modell bewegen</h3>
    <div id="position-info">
      <p>Aktuelle Position: X=${selectedPlacedModel.position.x.toFixed(2)}, Z=${selectedPlacedModel.position.z.toFixed(2)}</p>
    </div>
    <label>Verschiebungsgröße: <span id="move-delta-display">${moveDelta.toFixed(2)}</span></label>
    <input type="range" min="0.01" max="1.0" step="0.01" value="${moveDelta}" onchange="updateMoveDelta(this.value)">
    <div style="display: flex; flex-direction: column; align-items: center;">
      <div>
        <button onclick="moveModelDynamic('x', -1)">← X</button>
        <button onclick="moveModelDynamic('x', 1)">→ X</button>
      </div>
      <div>
        <button onclick="moveModelDynamic('z', -1)">- Z</button>
        <button onclick="moveModelDynamic('z', 1)">+ Z</button>
      </div>
    </div>
    <button onclick="closeDynamicMenu()">Zurück</button>
  `;
    }

    function updateMoveDelta(value) {
      moveDelta = parseFloat(value);
      const moveDeltaDisplay = document.getElementById("move-delta-display");
      if (moveDeltaDisplay) {
        moveDeltaDisplay.textContent = moveDelta.toFixed(2);
      }
    }

    function moveModelDynamic(axis, direction) {
      if (selectedPlacedModel) {
        const delta = direction * moveDelta; // Dynamischer Wert basierend auf Slider
        selectedPlacedModel.position[axis] += delta;

        // Position im Menü aktualisieren
        const positionInfo = document.getElementById("position-info");
        if (positionInfo) {
          positionInfo.innerHTML = `
        <p>Aktuelle Position: X=${selectedPlacedModel.position.x.toFixed(2)}, Z=${selectedPlacedModel.position.z.toFixed(2)}</p>`;
        }
      }
    }

    /* ========================= */
    /*      KARTENSTEUERUNG      */
    /* ========================= */
    function refreshMapDialog() {
      const mapDialog = document.getElementById('map-dialog');
      mapDialog.style.display = 'flex';
    }

    function closeMapDialog() {
      const mapDialog = document.getElementById('map-dialog');
      mapDialog.style.display = 'none';
    }

    /* ========================= */
    /*        AR-HANDLING        */
    /* ========================= */
    async function activateXR(sceneData = null) {
      const canvas = document.createElement('canvas');
      document.body.appendChild(canvas);
      const gl = canvas.getContext('webgl', { xrCompatible: true });
      const renderer = new THREE.WebGLRenderer({ alpha: true, canvas, context: gl });
      renderer.autoClear = false;

      scene = new THREE.Scene();
      camera = new THREE.PerspectiveCamera();
      camera.matrixAutoUpdate = false;

      const light = new THREE.DirectionalLight(0xffffff, 1);
      light.position.set(10, 10, 10);
      scene.add(light);

      const loader = new THREE.GLTFLoader();
      loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/reticle/reticle.gltf", (gltf) => {
        reticle = gltf.scene;
        reticle.visible = false;
        scene.add(reticle);
      });

      currentSession = await navigator.xr.requestSession('immersive-ar', {
        optionalFeatures: ["dom-overlay"],
        domOverlay: { root: document.body },
        requiredFeatures: ['hit-test']
      });

      currentSession.updateRenderState({ baseLayer: new XRWebGLLayer(currentSession, gl) });
      const referenceSpace = await currentSession.requestReferenceSpace('local');
      const viewerSpace = await currentSession.requestReferenceSpace('viewer');
      const hitTestSource = await currentSession.requestHitTestSource({ space: viewerSpace });

      document.getElementById('menu-bar').style.display = 'flex';

      currentSession.addEventListener("end", () => {
        currentSession = null;
        document.getElementById("dynamic-menu").style.display = "none";
        menus.forEach(id => {
          document.getElementById(id).style.display = 'none';
        });
      });

      canvas.addEventListener("pointerdown", selectModelFromScene);


      if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(position => {
          geoLocation = {
            latitude: roundTo(position.coords.latitude, 5),
            longitude: roundTo(position.coords.longitude, 5),
          };
          console.log("GeoLocation: " + JSON.stringify(geoLocation));
          if (sceneData) {
            sceneData.models.forEach((model) => {
                if (model.name) {
                    const filePath = Object.values(models).find(m => model.name === m.name).file;
                    const { x, z } = leafletToThree(model.lat, model.lng);
                    const positionVector = new THREE.Vector3(x, model.position.y, z);
                    placeModel(filePath, positionVector, (placed) => {
                        if (model.rotation) {
                          placed.rotation._x = model.rotation._x;
                          placed.rotation._y = model.rotation._y;
                          placed.rotation._z = model.rotation._z;
                        }
                        if (model.scale) {
                          placed.scale.x = model.scale.x;
                          placed.scale.y = model.scale.y;
                          placed.scale.z = model.scale.z;
                        }
                    });
                }
            });
          }
        }, function(error) {
          console.error("Fehler bei der Geolokalisierung:", JSON.stringify(error));
        }, {enableHighAccuracy: true, maximumAge: 2000, timeout: 5000});
      }

      currentSession.requestAnimationFrame(function onXRFrame(time, frame) {
        currentSession.requestAnimationFrame(onXRFrame);
        gl.bindFramebuffer(gl.FRAMEBUFFER, currentSession.renderState.baseLayer.framebuffer);

        const pose = frame.getViewerPose(referenceSpace);
        if (pose) {
          const view = pose.views[0];
          const viewport = currentSession.renderState.baseLayer.getViewport(view);
          renderer.setSize(viewport.width, viewport.height);

          camera.matrix.fromArray(view.transform.matrix);
          camera.projectionMatrix.fromArray(view.projectionMatrix);
          camera.updateMatrixWorld(true);

          const hitTestResults = frame.getHitTestResults(hitTestSource);
          if (hitTestResults.length > 0) {
            const hitPose = hitTestResults[0].getPose(referenceSpace);
            reticle.visible = true;
            reticle.position.set(hitPose.transform.position.x, hitPose.transform.position.y, hitPose.transform.position.z);
            reticle.updateMatrixWorld(true);
          }

          renderer.render(scene, camera);
        }
      });
    }

    function exitAR() {
      document.getElementById('confirmation-dialog').style.display = 'flex';
    }

    function confirmExit(shouldExit) {
      if (shouldExit && currentSession) currentSession.end();
      document.getElementById('confirmation-dialog').style.display = 'none';
    }

    /* ========================= */
    /*   BENUTZERINTERAKTIONEN   */
    /* ========================= */
    let soundTimeout = false;
    function playButtonSound() {
      if (!soundTimeout) {
        const sound = document.getElementById("button-sound");
        sound.currentTime = 0;
        sound.play();

        soundTimeout = true;
        setTimeout(() => {
          soundTimeout = false;
        }, 200); // Verzögerung von 200ms
      }
    }