/**
 * @fileoverview app-gen-co.js
 */

import { appEvents, mylog, showToast, frontendConfig, terminateApp } from './utilities.js';
import { L, mapState, getMap } from './map-service.js';
import {
    fitMapToTarget,
    initMapMarkerService,

    demarcatePriorContext,
    removeAddressMarker,
    registerCoordinator,
    getSafeViewport,
    isOutsideSafeViewport
} from "./map-gen-mgr.js"
import { loadAndRenderPois, renderPois, addNewMarkerFromStore } from './map-poi-mgr.js';
import { setupClusterEventListeners, updateClusterIcon } from "./map-cluster-mgr.js";
import { InsertPoiUI } from './insert-poi-ui.js';
import { UpdatePoiDetailsUI } from './update-poi-details-ui.js';
import { LocationTrackingCoordinator } from './loc-tracking-co.js';
import { MapMarkerClusterUI } from './map-markercluster-ui.js';
import { MapLocationUI } from './map-loc-ui.js';
import { BsUI } from './bs-gen-ui.js';
import { BottomSheetCoordinatorInstance } from './bs-gen-co.js';
import { BackendService } from './backend-db.js';
import { AddressSheetUI } from './addrs-ui.js';
import { AddressSheetCoordinator } from './addrs-co.js';
import { SettingsUI } from './sc-settings-ui.js';
import { SettingsCoordinator } from './sc-settings-co.js';
import { AppStartPageUI } from './app-startpage-ui.js';
import { AppStartPageCoordinator } from './app-startpage-co.js';
import { getAdminMode } from './admin-mode-co.js';
import { initPoiEventInterceptors, updateSearchFieldWithAddress } from './app-poi-co.js';
import { setupGuiAddrsCoordinator } from './gui-address-co.js';
import { PhotoSheetUI } from './photo-sheet-ui.js';
import { initBsAudioEvents } from './bs-poi-co.js';
import { VisibilityTracker } from './visibility-tracker.js';
import { AddressEditor } from './specify_poi_address.js';
import { showPedestrianRoute, demarcateRoute } from './navigation-co.js';
import { getPoiData } from './poi-store.js';


export class ApplicationCoordinator {
    static appEvents = appEvents;

    #AppShellUIClass;
    #AppShellCoordinatorClass;
    #appShellUI;
    #appShellCoordinator;
    #locationTracker;
    #bottomSheetUI;
    #backendService;
    #insertPoiUI;
    #updatePoiUI;
    #addressSheetUI;
    #addrsCoordinator;
    #bsCoordinator;
    #settingsCoordinator;
    #appStartPageCoordinator;
    #mapLocationUI;
    #poisLoadPromise = null;
    #locationTrackingPromise = null;
    #preloadTimer = null;

    constructor(AppShellUIClass, AppShellCoordinatorClass) {
        this.#AppShellUIClass = AppShellUIClass;
        this.#AppShellCoordinatorClass = AppShellCoordinatorClass;
        this.mapCenterY = window.innerHeight / 2;
    }

    /**
         * Startet den Bootstrapping-Prozess der Anwendung.
         * Stellt sicher, dass die Konfiguration geladen ist, bevor das UI initialisiert wird.
         */
    async start() {


        mylog("ApplicationCoordinator: Bootstrapping gestartet.");


        try {
            // --- SCHRITT 0: Zentrale Konfiguration vom Server erzwingen ---
            const configLoaded = await frontendConfig.load();

            if (!configLoaded) {
                terminateApp("Zentrale Konfiguration (config.php) konnte nicht geladen werden.");
                return;
            }

            mylog(`FrontendConfig aktiv. Umgebung: ${frontendConfig.env} | Version: ${frontendConfig.version}`);

            // --- WEITERER BOOTSTRAP-ABLAUF ---
            this.#checkFirefoxIOS();

            const appShellUI = new this.#AppShellUIClass();
            appShellUI.injectIntoDOM(document.body, this.#handleAdminModeToggle.bind(this));

            this.#appShellUI = appShellUI;
            this.#appShellCoordinator = new this.#AppShellCoordinatorClass(appShellUI);

            await initMapMarkerService();
            registerCoordinator(this);

            this.initializeApplication();
            this.preloadBackground();

        } catch (error) {
            console.error("FATALER FEHLER im Bootstrapping:", error);
            terminateApp("Kritischer Systemfehler beim Starten: " + error.message);
        }
    }

    initializeApplication() {
        const shield = document.getElementById('initial-load-shield');
        if (shield) shield.remove()
        mylog("ApplicationCoordinator: Initialisierung der Module.");

        this.#backendService = new BackendService();
        this.#updatePoiUI = UpdatePoiDetailsUI.getInstance();
        this.#insertPoiUI = InsertPoiUI.getInstance();

        this.#bottomSheetUI = new BsUI('wrapper', 'bottom-sheet', 'bottom-sheet-content-area', 'bottom-sheet-actions-area');
        this.#bsCoordinator = BottomSheetCoordinatorInstance;
        this.#bsCoordinator.init(this.#bottomSheetUI, this.#backendService, mapState, ApplicationCoordinator.appEvents);

        initPoiEventInterceptors(ApplicationCoordinator.appEvents, this.#bottomSheetUI, this.#backendService, this.#insertPoiUI, this.#updatePoiUI);

        this.#locationTracker = LocationTrackingCoordinator.getInstance();
        this.#mapLocationUI = new MapLocationUI();
        this.#addressSheetUI = new AddressSheetUI();
        this.#addrsCoordinator = new AddressSheetCoordinator(this.#addressSheetUI, this.#backendService);

        // --- NEU: AddressEditor initialisieren ---
        // Wir machen ihn an der Instanz UND global verfügbar, 
        // damit onclick-Events im HTML darauf zugreifen können.
        this.addressEditor = new AddressEditor();
        window.addressEditor = this.addressEditor;

        const mapMarkerClusterUI = new MapMarkerClusterUI();
        mapMarkerClusterUI.injectIntoDOM();

        // Start-UI Setup
        const appStartPageUI = new AppStartPageUI();
        appStartPageUI.injectIntoDOM();
        this.#appStartPageCoordinator = new AppStartPageCoordinator(appStartPageUI, this.#handleStartPageDone.bind(this));
        this.#appStartPageCoordinator.start();

        const settingsUIInstance = new SettingsUI();
        this.settingsUI = settingsUIInstance; // WICHTIG: Damit 'this.settingsUI' unten bekannt ist
        this.#settingsCoordinator = new SettingsCoordinator(settingsUIInstance);
        PhotoSheetUI.getInstance();
        this.#setupAllListeners();

        // ABLAUF: Spinner & Overlays anzeigen
        const spinner = document.getElementById('loading-spinner-content');
        const overlay = document.getElementById('location-permission-overlay');
        if (spinner) spinner.classList.remove('hidden');
        if (overlay) overlay.classList.remove('hidden');

        this.#preloadTimer = this.#startPreloadTimer();

        // Tracking & POIs parallel laden
        this.#locationTrackingPromise = this.#locationTracker.startTrackingAndHandlePermission().catch(() => { });

        this.#poisLoadPromise = loadAndRenderPois(
            this.#backendService,
            this.#appShellCoordinator.updateLoadingText.bind(this.#appShellCoordinator)
        ).then(() => {
            mylog("ApplicationCoordinator: POI-Daten geladen.");

            // Timer stoppen & Spinner entfernen
            if (this.#preloadTimer) {
                clearInterval(this.#preloadTimer);
                this.#preloadTimer = null;
            }
            if (spinner) spinner.classList.add('hidden');

            // Button auf dem Background erst jetzt einblenden
            this.#appStartPageCoordinator.showButton();
            // JETZT ist der Moment für das Modal!
            if (this.settingsUI && this.settingsUI._settingsAuth) {
                //               this.settingsUI._settingsAuth.ensureValidSession();
            }
        }).catch(err => console.error("POI Fehler:", err));

        window.addEventListener('resize', () => this.updateMapCenterY());

        // Initialisierung des Trackers mit deiner optimierten Klasse
        new VisibilityTracker((diffSec, source) => {
            // Nur die Zeit und die Quelle (source) anzeigen
            const message = `DiffTime: ${diffSec.toFixed(2)}s (${source})`;
            this.handleReEntry(diffSec);
        });

    }
    async handleReEntry(diffSec) {


        //     showToast(`Re-Entry erkannt nach ${Math.round(diffSec)}s`,``,500);

        // AKTION 1: Update-Check (Immer ausführen oder ab z.B. 10s)
        if (diffSec > 30) {
            //                 showToast("update check", "",1000); 
            if (typeof runUpdateCheck === 'function') {
                runUpdateCheck();
            }
        }


        // AKTION 2: Auth-Validierung (Wichtig, falls Session abgelaufen sein könnte)
        if (diffSec > 3) {
            if (this.settingsUI?._settingsAuth) {
                this.settingsUI._settingsAuth.ensureValidSession();
            }
        }


        // AKTION 3: Daten-Refresh (Nur wenn Zeitlimit überschritten)

        if (diffSec > 300) {
            mylog("Zeitlimit für Daten-Refresh erreicht.");
            await this.refreshPoiData();
        }
    }
    async refreshPoiData() {
        let spinner = document.getElementById('loading-spinner-content');

        if (spinner) {
            // Raus aus dem Permission-Overlay, rein in den Body-Root
            document.body.appendChild(spinner);

            spinner.style.cssText = `
                display: flex !important;
                visibility: visible !important;
                opacity: 1 !important;
                background-color: rgba(0, 0, 0, 0.4) !important; /* Halbtransparentes Schwarz */
                backdrop-filter: blur(2px); /* Optional: Leichter Blur-Effekt im Hintergrund */
                z-index: 999999 !important; 
                position: fixed !important;
                top: 0; left: 0; width: 100vw; height: 100vh;
                justify-content: center; align-items: center;
            `;

            // Falls dein Spinner ein SVG oder Bild ist, bleibt das erhalten.
            // Wir entfernen nur die "rote Warnfarbe".
            spinner.classList.remove('hidden');
        }

        // Kurze Pause, damit die UI den Status-Wechsel verarbeitet
        await new Promise(resolve => setTimeout(resolve, 50));

        try {
            await loadAndRenderPois(
                this.#backendService,
                this.#appShellCoordinator.updateLoadingText.bind(this.#appShellCoordinator)
            );

        } catch (err) {
            console.error("Refresh-Fehler:", err);
        } finally {
            if (spinner) {
                // Zurücksetzen und verstecken
                spinner.style.cssText = "";
                spinner.classList.add('hidden');
            }
        }
    }
    async #handleStartPageDone() {
        mylog("ApplicationCoordinator: Start-Button geklickt.");

        // Overlays entfernen
        this.#appShellCoordinator.hideLocationPermissionOverlay();

        const bgContainer = document.getElementById('background-image-container');
        if (bgContainer) bgContainer.classList.add('fade-out');

        // 1. Audio-Events am Body registrieren
        initBsAudioEvents();

        // 2. TTS-Unlock & Audio-Context-Unlock (NEU für Google TTS)
        if ('speechSynthesis' in window) {
            // Backup für Browser-TTS (deine bestehende Logik)
            const unlockUtterance = new SpeechSynthesisUtterance(".");
            unlockUtterance.volume = 0.01;
            unlockUtterance.rate = 10;
            window.speechSynthesis.speak(unlockUtterance);

            setTimeout(() => {
                window.speechSynthesis.cancel();
            }, 50);
        }

        // 3. NEU: Audio-Unlock für Google MP3-Wiedergabe
        // Wir spielen einen Millisekunde Stille ab, damit der Browser 
        // zukünftige Audio-Objekte (Google MP3s) ohne Blockade abspielt.
        const silentAudio = new Audio("data:audio/wav;base64,UklGRigAAABXQVZFWmZtdCAQAAAAAQABAADlFwAA5RcAAAEAAgAZAGRhdGEAAAAA");
        silentAudio.play().catch(e => mylog("Audio-Unlock fehlgeschlagen: " + e.message));

        mylog("Audio- & TTS-Unlock: Signal an Chrome/Safari gesendet.");

        // Warten auf restliche Versprechen
        await Promise.allSettled([this.#locationTrackingPromise, this.#poisLoadPromise]);

        this.#appShellCoordinator.showMapAndControls();

        if (this.#locationTracker.isTrackingActive() && this.#insertPoiUI.buttonElement) {
            this.#insertPoiUI.buttonElement.classList.remove("hidden");
        }

        this.#settingsCoordinator.initializeSettingsState();
        this.updateMapCenterY();
    }

    #setupAllListeners() {
        const onRefreshRequest = (focusData) => this.#handleRefreshRequest(focusData);
        setupMapEventListeners();
        setupClusterEventListeners(this.#bottomSheetUI, this.#backendService);

        this.#bottomSheetUI.onClose(() => {
            updateSearchFieldWithAddress(null);
            this.updateMapCenterY();
        });


        this.#bottomSheetUI.onHeaderClick(async () => {
            const map = getMap();
            const activeObj = mapState.activeMarkerOrCluster;
            const gid = mapState.activeMarkerOrClusterGID;

            if (!activeObj) return;

            demarcateRoute(map);

            if (mapState.isRouteActive) {
                mapState.isRouteActive = false;
                mylog("DEBUG: Route manuell geschlossen.");
                if (gid !== 'new') {
                    BottomSheetCoordinatorInstance.handleBsUpdate(activeObj);
                    fitMapToTarget(gid, activeObj.getLatLng(), activeObj, 'TOVIEWPORT');
                }
            }
            else {
                const userPos = this.#locationTracker.getUserPosition();

                if (userPos) {
                    mylog("DEBUG: Neue Route wird angefordert.");

                    let targetCoords = null;

                    if (activeObj instanceof L.MarkerCluster) {
                        const children = activeObj.getAllChildMarkers();
                        if (children.length > 0) {
                            const targetGid = children[0].options.gid;
                            mylog(`DEBUG: Cluster-Routing zu erstem Kind (GID: ${targetGid})`);
                            const targetPoi = getPoiData(targetGid);
                            if (targetPoi) targetCoords = { lat: targetPoi.lat, lng: targetPoi.lng };
                        }
                    }
                    else if (gid === 'new') {
                        const ll = activeObj.getLatLng();
                        targetCoords = { lat: ll.lat, lng: ll.lng };
                    }
                    else {
                        const targetPoi = getPoiData(gid);
                        if (targetPoi) targetCoords = { lat: targetPoi.lat, lng: targetPoi.lng };
                    }

                    if (!targetCoords) {
                        mylog(`DEBUG: Routing Abbruch - Keine Koordinaten für GID ${gid}.`);
                        return;
                    }

                    const success = await showPedestrianRoute(
                        map,
                        { lat: userPos[0], lng: userPos[1] },
                        targetCoords
                    );

                    if (success) {
                        mapState.isRouteActive = true;
                        if (gid !== 'new') BottomSheetCoordinatorInstance.handleBsUpdate(activeObj);
                    }
                } else {
                    if (typeof showToast === "function") showToast("Standort unbekannt.", "Info");
                }
            }
        });

        ApplicationCoordinator.appEvents.addEventListener('map:refreshMarkers', (e) => onRefreshRequest({ newGid: e.detail.newGid }));
        ApplicationCoordinator.appEvents.addEventListener('app:requestClearAll', () => this.handleClearAll());
        ApplicationCoordinator.appEvents.addEventListener('map:visibilityUpdateRequested', () => {
            const isOutside = isOutsideSafeViewport(mapState.activeMarkerOrCluster.getLatLng());
            this.#bottomSheetUI.toggleEyeIcon(isOutside);
        });
        ApplicationCoordinator.appEvents.addEventListener('cluster:executeNavigation', async (event) => {
            const { cluster, origin, resolve } = event.detail;

            try {
                demarcatePriorContext(cluster, mapState);

                let navigationMode;
                if (origin === 'search') {
                    navigationMode = 'CENTER';
                } else if (origin === 'headerClick' || origin === 'swipe') {
                    navigationMode = 'TOVIEWPORT';
                } else {
                    navigationMode = 'RESIZE';
                }

                mylog(`[Coordinator] Cluster-Navigation gestartet. Modus: ${navigationMode}`);

                await fitMapToTarget(null, cluster.getLatLng(), cluster, navigationMode);

                await new Promise(r => requestAnimationFrame(() => {
                    const el = cluster._icon || (cluster.__parent ? cluster.__parent._icon : null);

                    if (el) {
                        updateClusterIcon(cluster, true);
                        mapState.activeMarkerOrCluster = cluster;
                        mapState.activeMarkerOrClusterGID = null;
                    } else {
                        console.warn("[Coordinator] Cluster-Icon nach Bewegung nicht im DOM gefunden.");
                    }
                    r();
                }));
            } finally {
                resolve?.();
            }
        });
        setupGuiAddrsCoordinator(this.#addrsCoordinator, { bottomSheetUI: this.#bottomSheetUI, backendService: this.#backendService });
        setupAddrsCoordinatorListeners(this.#addrsCoordinator, this.#bottomSheetUI, this.#mapLocationUI);
        /*
                this.#addrsCoordinator.onNextDirtyStoneSelected(() => {
                    this.#locationTracker.navigateToNextCareNeed({ bottomSheetUI: this.#bottomSheetUI, backendService: this.#backendService, mapState: mapState });
                });*/
        this.#addrsCoordinator.onNextDirtyStoneSelected(() => {
            const nextGid = this.#locationTracker.findNextCareNeedGid();

            if (nextGid) {
                // Wir feuern das Event mit der GID
                ApplicationCoordinator.appEvents.dispatchEvent(new CustomEvent('poi:requestSelection', {
                    detail: {
                        gid: nextGid,
                        origin: 'search'
                    }
                }));

                this.#addressSheetUI.closeResults();
            } else {
                showToast("Kein Stein mit Pflegebedarf in der Nähe gefunden.", "Info");
            }
        });

        this.#appShellCoordinator.onSearchTriggered(() => {
            this.#addrsCoordinator.triggerSheetOpened();
            this.#addressSheetUI.openResults();
        });

        this.#appShellCoordinator.onSettingsClicked(() => this.#settingsCoordinator.toggleSettings());

        this.#bottomSheetUI.onResize(() => {
            this.updateMapCenterY();
            if (this.#bottomSheetUI.isExpanded) {
                const gid = mapState.activeMarkerOrClusterGID;
                const coords = this.#bottomSheetUI.getCoords();
                const activeCluster = mapState.activeMarkerOrCluster;
                if ((gid || activeCluster) && coords) {
                    fitMapToTarget(gid, coords, activeCluster, 'RESIZE');
                }
            }
        });
    }

    #handleRefreshRequest(focusData) {
        if (focusData?.newGid) addNewMarkerFromStore(focusData.newGid);
    }

    #startPreloadTimer() {
        let seconds = 0;
        return setInterval(() => {
            seconds++;
            this.#appShellCoordinator.updateLoadingText(`Ladezeit: ${seconds} Sekunde(n)...`);
        }, 1000);
    }

    async preloadBackground() {
        const BG_IMAGE_URL = 'StolperCleanBackground.jpg?v=' + Date.now();
        const bgContainer = document.getElementById('background-image-container');
        try {
            const response = await fetch(BG_IMAGE_URL);
            const blob = await response.blob();
            const imgElement = new Image();
            imgElement.src = URL.createObjectURL(blob);
            imgElement.style.cssText = "width:100%; height:100%; object-fit:cover;";
            if (bgContainer) bgContainer.appendChild(imgElement);
        } catch (e) { if (bgContainer) bgContainer.style.opacity = 1; }
    }

    #handleAdminModeToggle() {
        const newState = !getAdminMode.getStatus();
        showToast(newState ? "Zusatzfunktionen aktiviert" : "Standard-Modus aktiv", "");
        getAdminMode.dispatchStatusChange(newState);
    }

    handleClearBS() {
        demarcatePriorContext(null, mapState);
        mapState.activeMarkerOrCluster = null;
        mapState.activeMarkerOrClusterGID = null;
        mapState.parentClusterOfActiveMarker = null;
        if (this.#bottomSheetUI.isOpen()) this.#bottomSheetUI.close();
        updateSearchFieldWithAddress(null);
        this.updateMapCenterY();
        this.#bottomSheetUI.toggleEyeIcon(false);
    }

    updateMapCenterY() {
        const map = getMap();
        if (!map || map.getSize().y <= 0) return;
        const vp = getSafeViewport();
        this.mapCenterY = vp.centerY;
    }

    getMapCenterY() { return this.mapCenterY; }

    handleClearAll() {
        mylog("ApplicationCoordinator: Full Clear angestoßen.");

        // FIX 1 & 2: Korrekte private Variable mit '#' und Schließen des UI
        if (this.#bottomSheetUI) {
            this.#bottomSheetUI.close();
        }

        // 2. Karte aufräumen
        this.clearAllMap();
    }

    clearAllMap() {
        const map = getMap();
        if (!map) return;

        removeAddressMarker();      // NEU
        mapState.isRouteActive = false;  // NEU


        // 1. API-Weg: Alle offiziellen Vektoren/Pfade entfernen
        map.eachLayer(l => {
            if ((l instanceof L.Polyline || l instanceof L.Path) && !(l instanceof L.TileLayer)) {
                map.removeLayer(l);
            }

            // 2. Plugin-Check: Spiderfy-Beine einklappen
            // Falls ein Cluster gerade "offen" ist, löscht das die Linien im DOM sauber
            if (l.unspiderfy && typeof l.unspiderfy === 'function') {
                l.unspiderfy();
            }
        });

        // ---  Logischen Selektions-State zurücksetzen ---
        // Das verhindert, dass die App glaubt, ein Marker sei noch aktiv, 
        // obwohl er gerade neu gerendert wird.
        if (typeof mapState !== 'undefined') {
            mapState.activeMarkerOrCluster = null;
            mapState.activeMarkerOrClusterGID = null;
            mapState.parentClusterOfActiveMarker = null;
            mapState.currentlySpiderfiedCluster = null;
            mylog("mapState selektive Variablen wurden in clearAllMap bereinigt.");
        }

        // 3. Render-Refresh: Löscht die Marker im Cluster und zeichnet neu
        renderPois();

        mylog("ApplicationCoordinator: Karte garantiert bereinigt.");
    }
    // Neue private Methode für die Warnung
    #checkFirefoxIOS() {
        const ua = navigator.userAgent;
        const isIOS = /iPad|iPhone|iPod/.test(ua);
        const isFirefox = /FxiOS/.test(ua);

        // Prüfen, ob die App bereits installiert ist (Standalone)
        const isStandalone = window.navigator.standalone === true ||
            window.matchMedia('(display-mode: standalone)').matches;

        if (isIOS && isFirefox && !isStandalone) {
            // 1. CSS dynamisch und einmalig injizieren
            if (!document.getElementById('ff-warning-styles')) {
                const style = document.createElement('style');
                style.id = 'ff-warning-styles';
                style.textContent = `
                    #ff-ios-banner {
                        position: fixed; bottom: 25px; left: 50%; transform: translateX(-50%);
                        width: 85%; max-width: 350px; background: white; color: #333;
                        padding: 20px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.4);
                        z-index: 100002; border-top: 5px solid #28a745; text-align: center;
                        animation: ffSlideUp 0.5s ease-out; font-family: Arial, sans-serif;
                    }
                    @keyframes ffSlideUp {
                        from { bottom: -100px; opacity: 0; }
                        to { bottom: 25px; opacity: 1; }
                    }
                    .ff-btn {
                        background: #28a745; color: white; border: none; padding: 12px;
                        border-radius: 8px; margin-top: 15px; font-weight: bold;
                        width: 100%; cursor: pointer; font-size: 16px;
                    }
                `;
                document.head.appendChild(style);
            }

            // 2. HTML-Banner injizieren, falls noch nicht vorhanden
            if (!document.getElementById('ff-ios-banner')) {
                const banner = document.createElement('div');
                banner.id = 'ff-ios-banner';
                banner.innerHTML = `
                    <h3 style="margin:0 0 10px 0; color:#28a745;">Firefox & iOS</h3>
                    <p style="margin:0; font-size:14px; line-height:1.5;">
                        Apple erlaubt Firefox leider nicht, Icons auf dem Homescreen zu speichern.<br><br>
                        Bitte nutze <strong>Safari</strong>, um stolperClean als App zu installieren.
                    </p>
                    <button class="ff-btn" onclick="this.parentElement.remove()">Verstanden</button>
                `;
                document.body.appendChild(banner);
            }
        }
    }

    refreshBsTitle() {
        const activeObj = mapState.activeMarkerOrCluster;
        if (activeObj) BottomSheetCoordinatorInstance.handleBsUpdate(activeObj);
    }
    showToastSW(message, buttonText, onConfirm) {
        if (document.getElementById('pwa-toast')) return;

        const toast = document.createElement('div');
        toast.id = 'pwa-toast';
        toast.style.cssText = `
        position: fixed; bottom: 30px; left: 50%; transform: translateX(-50%);
        background: #333; color: white; padding: 12px 20px; border-radius: 50px;
        z-index: 10002; display: flex; align-items: center; gap: 15px;
        box-shadow: 0 4px 15px rgba(0,0,0,0.4); font-family: sans-serif;
    `;

        toast.innerHTML = `
        <span>${message}</span>
        <button id="toast-confirm-btn" style="
            background: #ff9800; border: none; color: white;
            padding: 6px 12px; border-radius: 20px; font-weight: bold; cursor: pointer;
        ">${buttonText}</button>
    `;

        document.body.appendChild(toast);

        document.getElementById('toast-confirm-btn').addEventListener('click', () => {
            if (onConfirm) onConfirm(); // Hier wird window.location.reload() ausgeführt
        });
    }

}

function setupAddrsCoordinatorListeners(addrsCoordinator, bottomSheetUI, mapLocationUI) {
    const locTrackingCoordinator = LocationTrackingCoordinator.getInstance();
    const addressSheetUI = addrsCoordinator.addressSheetUI;
    addrsCoordinator.onCurrentLocationSelected(() => {
        removeAddressMarker();
        const userPosition = locTrackingCoordinator.getUserPosition();
        if (userPosition) {
            mapLocationUI.centerView({ coords: { latitude: userPosition[0], longitude: userPosition[1] } }, 18);
        } else {
            showToast("Standort nicht verfügbar.", 'Warnung');
        }
        bottomSheetUI.close();
    });
    addrsCoordinator.onSheetOpened(() => {
        const isEnabled = locTrackingCoordinator?.isTrackingActive();
        addressSheetUI.updateCurrentLocationButton(isEnabled);

        addressSheetUI.updateNextDirtyStoneButton(isEnabled);

        const valToSet = addrsCoordinator.searchBuffer || "";
        const inputEl = addressSheetUI.searchInputEl;
        if (inputEl) {
            inputEl.value = valToSet;
            addrsCoordinator.handleSearchInput(valToSet);
            if (valToSet.length > 0) inputEl.select();
            inputEl.focus();
        }
    });

}

function setupMapEventListeners() {
    const map = getMap();
    if (!map) return;
    map.on('click', (e) => {
        if (e.originalEvent?.cancelBubble) return;
        ApplicationCoordinator.appEvents.dispatchEvent(new CustomEvent('app:requestClearAll'));
    });
    map.on('moveend', () => {
        if (mapState.activeMarkerOrCluster) {
            ApplicationCoordinator.appEvents.dispatchEvent(new CustomEvent('map:visibilityUpdateRequested'));
        }
    });

}

export async function runUpdateCheck() {
    try {
        const url = './index.html?t=' + Date.now();
        //       alert('1. Fetch: ' + url);

        //      const response = await fetch(url, { cache: 'no-store' });
        const response = await fetch(url);
        //     alert('2. Status: ' + response.status);

        const text = await response.text();
        const match = text.match(/const\s+CURRENT_VERSION\s+=\s+([\d.]+)/);

        //       alert('3. Match: ' + (match ? match[1] : 'nicht gefunden') + ' | Lokal: ' + CURRENT_VERSION);

        if (match && parseFloat(match[1]) > CURRENT_VERSION) {
            //        alert('4. Update erkannt – zeige Overlay');
            if (!document.getElementById('update-overlay')) {
                const div = document.createElement('div');
                div.id = 'update-overlay';
                div.innerHTML = `
                    <div class="update-card">
                        <p>Eine neue Version steht bereit (${match[1]}).</p>
                        <button class="update-btn" onclick="window.location.href = window.location.href.split('?')[0] + '?t=' + Date.now()">Jetzt laden</button>
                    </div>`;
                document.body.appendChild(div);
            }
        } else {
            //         alert('4. Kein Update: Server=' + (match?.[1]) + ' Lokal=' + CURRENT_VERSION);
        }
    } catch (e) {
        alert('FEHLER: ' + e.message);
    }
}
