const selectedAddress = document.getElementById("selectedAddress");
const suggestions = document.getElementById("suggestions");
// outdated  const houseNumber = document.getElementById("houseNumber");
const toast = document.getElementById("toast");
let map, marker;
// 🌍 Globale Koordinaten
let userLat = null; // Userposition für die distanzprüfung
let userLon = null;
let finalLat = null; // die für die gewählte Adresse / den Stein ermittelt wurden
let finalLon = null;
// globale struktur für die Daten des Stolpersteins, hier Adresse & location
let newStone = new ScStone({}); // auf Basis der ScStone Klasse
/**
 * Zeigt an, ob die Adresse in `selectedAddress` validiert wurde.
 * Wenn ja:
 * - Ist die Karte benutzbar (verschiebbar).
 * - Wird `selectedAddress` grau hinterlegt.
 */
let isAddressValid = false; 
/**
 * Zeigt den übergebenen String für kurze zeit als Info an.
 * @param message  Der Infotext
 */
function showToast(message) {
  toast.textContent = `${message} `;
  toast.classList.add("show");
  setTimeout(() => toast.classList.remove("show"), 3000);
}

/**
 * 
 * @param {*} items : zeigt liste der vorgeschlagenen adressen. 
 * es gibt Adressen ohne Hnr. Dieser Sonderfall muss noch geprüft werden
 */
function showSuggestions(items) {
  suggestions.innerHTML = "";

  // Mehrere Vorschläge anzeigen
  items.forEach((item) => {
    const addr = item.address;
    const label = `${addr.street || ""}${addr.houseNumber ? " " + addr.houseNumber : ""
      }${addr.district ? ", " + addr.district : ""}`;

    const li = document.createElement("li");
    li.textContent = label;
    li.addEventListener("mousedown", () => {
      // Auswahl aus Vorschlagsliste. 
      // Die Adresse zu den Koordinaten muss neu ermittelt werden, weil sie ev abweicht  
      // ist zum Suchbegriff, zB "hauptstr 5c" oder "Rabenstr. 3 -> Turmfalkenstr 24"
      const coords = item.position;
      validateAddressFromCoordinates(coords.lat, coords.lng);
    });
    suggestions.appendChild(li);
  });
  suggestions.classList.remove("hidden"); // unnötig? ansonsten hideSuggestions

}
// Addressvorschläge entfernen
function hideSuggestions() {
  suggestions.innerHTML = "";
  suggestions.classList.add("hidden");
}

/**
 * Distanzprüfung zwischen Nutzer- und Zielort, 
 * maxDistance als Toleranzschwelle
 * @param userposition und Steinposition
 */
function checkDistance( //
  userLat,
  userLon,
  itemLat,
  itemLon,
  maxDistance = 600000
) {
  // Überprüfen, ob die Benutzer-Koordinaten gültig sind
  if (!isNaN(userLat) && !isNaN(userLon)) {
    const userLocation = L.latLng(userLat, userLon);
    const selectedLocation = L.latLng(itemLat, itemLon);

    // Berechne die Distanz zwischen den beiden Punkten
    const distance = userLocation.distanceTo(selectedLocation);

    // Wenn die Distanz größer als maxDistance ist, zeige eine Benachrichtigung und blende die Felder aus
    if (distance > maxDistance) {
      showToast(
        "Die ausgewählte Adresse ist zu weit entfernt. Bitte wähle eine nähere."
      );
      document.getElementById("victimFields").style.display = "none";
      return false; // Distanz zu groß
    }

    return true; // Distanz in Ordnung
  }

  return false; // Ungültige Benutzer-Koordinaten
}
/**
* validateAddressFromCoordinates(): Aufruf, wenn 
* - die Seite geladen wird (proposeAddress-> Test, ob sich der user an einer verwertbaren 
* location befindet). zusätzlich zuerst getAddressFromLocation
* - ein Adressvorschlag aus der Liste gewählt wurde (weil ggf korrekturbedarf)
* - die Adresssuche nur eine Adresse findet (weil ggf korrekturbedarf)
* - NICHT: nach .moveend (nur getAddressFromLocation), weil dort auch unerlaubte adressen möglich sind  yyy
*
* holt für eine Koordinate die nächstgelegene Adresse
* prüft, ob diese Adresse "erlaubt" ist um damit einen Stein anzulegen: 
* - nah an userlocation (je nach Modus)
* - innerhalb Berlins (je nach Modus)
* - mit Hausnummer
* korrigiert ggf die Adresse: aus hausnummer 5a wird 5 , auch die strasse kann 
* sich ändern bei Interpolierter Adresse (zB Rabenstraße), dann wird für die 
* korrigierte Adresse  ein 2. mal die koordiate gelesen. 
* hier passiert zu viel: wenn die adresse verwertbar ist,
* - wird die karte aktualisiert (das ist nicht modular)
* -  werden die felder zur eingabe der opfer-daten (das ist nicht modular)
* aktiviert -> ist die kombination in einer funktion sinnvoll?
* 
 * @param {*} lat 
 * @param {*} lon 
*/
function validateAddressFromCoordinates(lat, lon) {
  console.log (ppcount + " propose");ppcount +=1;
  fetch(`getAddressFromLocation.php?lat=${lat}&lon=${lon}`)
    .then((res) => res.json())
    .then((data) => {
      if (!data.items || data.items.length === 0) {
        showToast("Keine Adresse für Koordinaten gefunden.");
        return;
      }

      const item = data.items[0];
      const itemLat = item.position.lat; // die koordinaten des gefundenen adresse
      const itemLon = item.position.lng;

      finalLat = itemLat;
      finalLon = itemLon;
      if (!checkDistance(userLat, userLon, itemLat, itemLon)) {
        return;
      }

      // Eingabefeld setzen & sperren
      updateValidAddress(data.items[0]);

      selectedAddress.setAttribute("readonly", "readonly");
      selectedAddress.style.backgroundColor = "#e0e0e0";

      // Info, falls Koordinaten abweichen, speziell wenn der mauszeiger bewegt wurde
      if (lat !== itemLat || lon !== itemLon) {
        showToast("Adresse angenähert.");
      }

      // Karte zeigen
      showMap(itemLat, itemLon);
      hideSuggestions();

      // Benutzerfelder anzeigen
      const victimFields = document.getElementById("victimFields");
      victimFields.style.display = "block";
    
      document.getElementById("saveButton").classList.add("disabled");

      // Live-Validierung
      document
        .getElementById("firstName")
        .addEventListener("input", updateSaveButton);
      document
        .getElementById("lastName")
        .addEventListener("input", updateSaveButton);
      document
        .getElementById("birthYear")
        .addEventListener("input", updateSaveButton);

      updateSaveButton();

      document.getElementById("firstName").focus();
    })
    .catch((err) => {
      console.error(err);
      showToast("Fehler bei Koordinaten-Validierung.");
    });
}
/**
 * ruft die url ( service mit parametern) und gibt die antwort als json zurück
 * Fehlertoleranz einstellbar
 * @param url 
 * @param retries  max anz wiederholungen
 * @param delay
 */
function fetchWithRetry(url, retries = 3, delay = 500) {
  return new Promise((resolve, reject) => {
    function attemptFetch(attempt) {
      fetch(url)
        .then((response) => {
          if (!response.ok) {
            throw new Error(`Fehler: ${response.status}`);
          }
          return response.json(); // WICHTIG: nicht direkt resolve()
        })
        .then((json) => {
          resolve(json); // Jetzt korrekt
        })
        .catch((error) => {
          if (attempt < retries) {
            showToast(`Laden ...`);
            setTimeout(() => attemptFetch(attempt + 1), delay);
          } else {
            reject(new Error("Maximale Anzahl von Versuchen erreicht"));
          }
        });
    }
    attemptFetch(0);
  });
}

/**
 * Abrufen der Addressvorschläge für Berlin
 * @param query  der suchbegriff
 */
function fetchSuggestions(query) {
  const url = `validate_address.php?q=${encodeURIComponent(
    query + ", Berlin, Deutschland"
  )}`;

  fetchWithRetry(url)
    .then((data) => {

      const victimFields = document.getElementById("victimFields");

      if (data.items && data.items.length > 0) {
        const berlinItems = data.items.filter(  // weil HERE auch vorschäge außerhalb B liefert
          (item) =>
            item.address &&
            item.address.city === "Berlin" &&
            item.address.street
        );


        if (berlinItems.length === 1) {
          // Ein einziger Vorschlag, direkt übernehmen
          const item = berlinItems[0];
          const coords = item.position;
          validateAddressFromCoordinates(coords.lat, coords.lng);

          selectedAddress.setAttribute("readonly", "readonly");
          selectedAddress.style.backgroundColor = "#e0e0e0"; // Grau

          // Vorschläge ausblenden
          /// hideSuggestions(); unnötig

        } else if (berlinItems.length > 1) {
          showSuggestions(berlinItems);
        }
        else {
          hideSuggestions();
          showToast("Keine gültige Adresse in Berlin gefunden.");
        }
      } else {
        hideSuggestions();
        showToast("Keine Adresse gefunden.");
      }
    })
    .catch((error) => {
      console.error("[fetchSuggestions] Fehler im Catch-Block:", error);
      hideSuggestions();
      showToast(
        `Fehler beim Laden der Vorschläge: ${error.message || error}`
      );
    });
}

// Funktion zur Geolokalisierung und Abrufen der Adresse
let ppcount =0;
function proposeAddress() {


  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(
      function (position) {
        const lat = position.coords.latitude;
        const lon = position.coords.longitude;
        // 🌍 Nutzerposition global speichern
        userLat = lat;
        userLon = lon;

        fetch(`getAddressFromLocation.php?lat=${lat}&lon=${lon}`)
          .then((response) => response.json())
          .then((data) => {
            if (data.items && data.items.length > 0) {
              const item = data.items[0];
              const selectedAddress =
                document.getElementById("selectedAddress");

              updateValidAddress(data.items[0]);

              selectedAddress.removeAttribute("readonly");
              selectedAddress.style.backgroundColor = "#ffffff";

              // Koordinaten global speichern und Karte anzeigen
              finalLat = item.position.lat;
              finalLon = item.position.lng;
              validateAddressFromCoordinates(finalLat, finalLon);

              // Vorschlagsliste sicherheitshalber ausblenden
              hideSuggestions();
            } else {
              showToast("Keine Adresse an diesem Standort gefunden.");
            }
          })
          .catch((error) => {
            showToast("Fehler beim Abrufen der Adresse: " + error.message);
          });
      },
      function (error) {
        showToast(
          "Geoposition konnte nicht abgerufen werden: " + error.message
        );

      }
    );
  } else {
    showToast("Geolocation wird in diesem Browser nicht unterstützt.");
    const victimFields = document.getElementById("victimFields");
    victimFields.style.display = "none"; // Benutzerfelder unsichtbar machen
  }
}

/*
let debounceTimer;
selectedAddress.addEventListener("change", (event) => {
  const query = selectedAddress.value.trim();

  clearTimeout(debounceTimer); // Stopp vorherigen Timer

  if (query.length < 5) {
    showToast("Bitte mindestens 5 Zeichen eingeben.");
    hideSuggestions();
    return; // ❌ Kein API-Aufruf
  }

  if (!hasHouseNumber(query)) {
    // Fehlerhafte Eingabe → Fokus zurück und keine weitere Verarbeitung
    // setTimeout(() => selectedAddress.focus(), 0);
    event.stopPropagation(); // Stoppt die Event-Propagation
    selectedAddress.focus();  // Setzt den Fokus zurück ins Eingabefeld^
    
    console.log("Hausnummer fehlt");
    return;
  }

  debounceTimer = setTimeout(() => {
    fetchSuggestions(query); // API-Aufruf NUR nach 0,1 Sekunde Pause wenn mit "input" (echtes ajax feeling)
  }, 100);
});
*/
selectedAddress.addEventListener("blur", (event) => {
  const query = selectedAddress.value.trim();

  if (query.length < 5) {
    showToast("Bitte mindestens 5 Zeichen eingeben.");
    isAddressValid = false; // Adresse ist nicht validiert
    disableMap(); // Karte deaktivieren
    selectedAddress.focus();
    return;
  }

  if (!hasHouseNumber(query)) {
    showToast("Keine Hausnummer");
    isAddressValid = false; // Adresse ist nicht validiert
    disableMap(); // Karte deaktivieren
    selectedAddress.focus();  
    return;
  }

   // Adresse ist validiert(-> noch ergänzen!!!), Karte aktivieren 
   isAddressValid = true;
   enableMap(); // Karte aktivieren

  fetchSuggestions(query);
});

/**
 * sichert ab, dass der handler nur beim ersten aufruf von show map aktiviert wird
 */

let moveEndHandlerSet = false;
/**
 * ShowMap() zeigt die Karte zentriert an der Stein-Adresse 
 * @param {*} lat 
 * @param {*} lon 
 */
function showMap(lat, lon) {
  if (!map) {
    map = L.map("map", { zoomControl: false }).setView([lat, lon], 22);

    L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
      attribution: "&copy; OpenStreetMap",
    }).addTo(map);

    if (!moveEndHandlerSet) {
      map.on("moveend", function () {
        const center = map.getCenter();

        fetch(
          `getAddressFromLocation.php?lat=${center.lat.toFixed(
            5
          )}&lon=${center.lng.toFixed(5)}`
        )
          .then((response) => response.json())
          .then((data) => {
            if (data.items && data.items.length > 0) {
              const item = data.items[0];
              const street = item.address?.street || "";
              const houseNumber = item.address?.houseNumber || "";
              finalLat = center.lat.toFixed(5);  // manuell gwählte location für Stein verwenden 
              finalLon = center.lng.toFixed(5);
              updateValidAddress(data.items[0]);  // neue Adresse anzeigen in GUI

              // newStone fürs Speichern mit korrekter detail-location  (!= Adress location) füttern 
              newStone.Lat = finalLat;
              newStone.Lon = finalLon;
              newStone.setGeom(); //  das kann noch verbessert werden, damit diese abhängige variable nicht neu zu berechnen ist. Evtl. beim laden der daten
              updateSaveButton();
            }
          })
          .catch((error) => {
            console.error("Fehler beim Abrufen der Adresse:", error);
            showToast("Fehler beim Abrufen der Adresse.");
          });
      });

      moveEndHandlerSet = true;
    }
  } else {
    map.setView([lat, lon], 22);
    if (marker) marker.remove();
  }
  //        marker = L.marker([lat, lon]).addTo(map);
}


document.addEventListener("click", (e) => {
  if (!suggestions.contains(e.target) && e.target !== selectedAddress) {
    hideSuggestions();
  }
});

let focusValueBeforeChange = "";
/**
 * alten suchbegriff selektieren und feld editierbar machen
 */
selectedAddress.addEventListener("focus", () => {
  focusValueBeforeChange = selectedAddress.value.trim(); // Wert merken
  selectedAddress.removeAttribute("readonly");
  selectedAddress.style.backgroundColor = "#ffffff";
  selectedAddress.select(); // Inhalt markieren
  disableMap(); // Karte deaktivieren solange Adresse editiert wird
});

function hasHouseNumber(address) {
  return /\b[^\d\s]+(?:\s+)\d{1,3}[a-zA-Z]?\b/.test(address);
}

/**
 * karte zentriren und feld "uneditable machen"
 */
document.getElementById("map").addEventListener("click", () => {
  const currentValue = selectedAddress.value.trim();
  if (
    currentValue === focusValueBeforeChange &&
    finalLat !== null &&
    finalLon !== null
  ) {
    map.setView([finalLat, finalLon], 22);
    // Eingabefeld wieder readonly und grau
    selectedAddress.setAttribute("readonly", "readonly");
    selectedAddress.style.backgroundColor = "#e0e0e0"; // Setzt das Grau zurück
  }
});

/**
 * prüft ob die daten des opfers ok sind
 * das ist nur eine teilvoraussetzung um einen stein zu speichern
 */
function isValidVictimData() {
  const firstName = document.getElementById("firstName").value.trim();
  const lastName = document.getElementById("lastName").value.trim();
  const birthYear = parseInt(document.getElementById("birthYear").value, 10);

  const isValidName = firstName.length > 2 && lastName.length > 2;
  const isValidYear = !isNaN(birthYear) && birthYear >= 1850 && birthYear <= 1945;

  return isValidName && isValidYear;
}

/**
* prüft ob die die adresse eine hausnummer hat und in Berlin liegt
* das ist nur eine teilvoraussetzung um einen stein zu speichern
* @param: ein objekt von ScStone 
 
*/
function isValidAddress(ScStone) {
  if (!userLat || !userLon) {
    return false;  // wenn der Auruf erfolgt bevor die userposition bekannt ist
  }
  let validationMessage = "";
  if (!checkDistance(userLat, userLon, ScStone.Lat, ScStone.Lon)) {
    validationMessage = 'zu weit entfernt, ';
  }
  if (!ScStone.house_no?.trim()) {
    validationMessage += "keine Hausnummer, ";
  }
  if (ScStone.city !== 'Berlin') {
    validationMessage += "nicht in Berlin";
  }

  if (validationMessage !== "") {
    showToast(validationMessage);
    return false;
  }
  else {
    return true; // alles ok
  }

}
/**
 * prüft ob die daten des steines valide sind und steuert auf dieser Basis, 
 * wie der SaveButton dargestellt wird 
 */
function updateSaveButton() {
  const saveButton = document.getElementById("saveButton");
  const victimValid = isValidVictimData();
  const addressValid = isValidAddress(newStone);


  if (victimValid && addressValid) {
    saveButton.classList.remove("disabled");
  } else {
    saveButton.classList.add("disabled");
  }
}
/**
 * das passiert, wenn das DOM komplett eingelesen wurde
 */

document.addEventListener("DOMContentLoaded", () => {

  console.log("DOMContentLoaded nach:", performance.now().toFixed(0), "ms");
  showToast("Laden...");

  document.getElementById("firstName").value = "An";
  document.getElementById("lastName").value = "Musterfrau";
  document.getElementById("birthYear").value = "1920";
  document.getElementById("selectedAddress").value = "Blankenbergstraße 8, Friedenau";
});

/**
 * die funktionen im window.load listner werden erst dann gestartet, wenn ALLE
 * resourcen (Karte etc) geladen sind. DOMcontentloaded ist idR  schon früher fertig. 
 * Wenn es interaktiv sein soll, kann man das dort steuern
 */
window.addEventListener("load", function () {
  console.log("window.load nach:", performance.now().toFixed(0), "ms");
  proposeAddress(); // Aufruf der Funktion zur Vorschlagsabfrage
  updateSaveButton(); // Führt die Validierung direkt nach dem Laden aus
  document.getElementById("selectedAddress").focus();
});



/**
 * Fügt einen stolperstein der DB hinzu
 * die daten müssen vorher validiert worden seon
 * @param {*} ein Objekt der Klasse ScStone
 * @returns 
 */
function addStoneToDatabase(myScStone) {

  myScStone.first_name = document.getElementById("firstName").value;
  myScStone.last_name = document.getElementById("lastName").value;
  myScStone.year_of_birth = parseInt(
    document.getElementById("birthYear").value
  );

  myScStone.manual_address = true;

  myScStone
    .insert()
    .then((gid) => {
      showToast(`Gespeichert: ${gid}`);

      // Eingabefelder leeren
      document.getElementById("firstName").value = "";
      //         document.getElementById("lastName").value = "";
      document.getElementById("birthYear").value = "";

    })
    .catch((error) => {
      alert("Fehler: " + error.message);
    });
}

// update the DOM attribute and the instance of ScStone, ohne weitere API calls
function updateValidAddress(item) {
  const address = item.address || {};
  const selectedAddress = document.getElementById("selectedAddress");

  const streetName = address.street || "";
  const houseNumber = address.houseNumber || "";
  const district = address.district || "";

  selectedAddress.value = `${streetName}${houseNumber ? " " + houseNumber : ""
    }${district ? ", " + district : ""}`;

  newStone.street = streetName;
  newStone.house_no = houseNumber;
  newStone.localdistrict = district;
  newStone.city = address.city || "";
  newStone.Lat = item.position.lat;
  newStone.Lon = item.position.lng;
  newStone.setGeom(); //  das kann noch verbessert werden, damit diese abhängige variable nicht neu zu berechnen ist. Evtl. beim laden der daten
}

document.getElementById("saveButton").addEventListener("click", () => {
  const btn = document.getElementById("saveButton");
  if (btn.classList.contains("disabled")) {
    showToast("Bitte alle Pflichtfelder korrekt ausfüllen.");
  } else {
    addStoneToDatabase(newStone);
  }
});
document.getElementById("backButton").addEventListener("click", () => {
  window.close();
});


// Funktion, um die Karte zu deaktivieren
function disableMap() {
  const mapContainer = document.getElementById("map");
  mapContainer.style.pointerEvents = "none"; // Deaktiviert alle Interaktionen mit der Karte
  mapContainer.classList.add("disabled"); // Optional: fügt eine CSS-Klasse hinzu, um visuell anzuzeigen, dass die Karte deaktiviert ist
}

// Funktion, um die Karte zu aktivieren
function enableMap() {
  const mapContainer = document.getElementById("map");
  mapContainer.style.pointerEvents = "auto"; // Aktiviert alle Interaktionen mit der Karte
  mapContainer.classList.remove("disabled"); // Entfernt die deaktivierende CSS-Klasse
}