import { mylog, showToast } from './sc-utilities.js';
import { initMap, fetchPOIs, setupMapEventListeners, 
        centerMapOnBottomSheetContent, setupAddrsCoordinatorListeners } from "./map-gen-mgr.js";
import { setupClusterEventListeners } from "./map-cluster-mgr.js";
import { InsertPoiUI } from './insert-poi-ui.js';
import { UpdatePoiUI } from './update-poi-details-ui.js';
import { LocationTrackingCoordinator } from './loc-tracking-co.js';
import { MapLocationUI } from './map-loc-ui.js'; 
import { BsUI } from './bs-gen-ui.js';
import { BackendService } from './backend-poi.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 { updateSearchFieldWithAddress } from './app-shell-co.js';
import { initAddStoneLogic, handleSaveStone } from './insert-poi-co.js';
import { setupGuiAddrsCoordinator } from './gui-address-co.js';
import { setAdminStatusGetter } from './sc-admin-mode.js';

/** @typedef {import('./app-shell-ui.js').AppShellUI} AppShellUI */
/** @typedef {import('./app-shell-co.js').AppShellCoordinator} AppShellCoordinator */

/**
 * ApplicationCoordinator.js
 * Verwaltet die zentrale Initialisierung, die Event-Subscription und die Orchestrierung
 * aller Hauptmodule der App.
 */
export class ApplicationCoordinator {

    // Referenzen auf Klassen (vom Index übergeben)
    #AppShellUIClass;
    #AppShellCoordinatorClass;
    #setupAdminModeDetectorFunc;
    
    // Instanzen (innerhalb von start() oder initializeApplication() gesetzt)
    /** @type {AppShellUI} */
    #appShellUI;
    /** @type {AppShellCoordinator} */
    #appShellCoordinator;
    
    /** @type {Map} */
    #map;
    /** @type {L.MarkerClusterGroup} */
    #markers;
    /** @type {LocationTrackingCoordinator} */ 
    #locationTracker; 
    /** @type {BsUI} */
    #bottomSheetUI;
    /** @type {BackendService} */
    #backendService;
    /** @type {InsertPoiUI} */
    #insertPoiUI;
    /** @type {UpdatePoiUI} */
    #updatePoiUI;
    /** @type {AddressSheetUI} */
    #addressSheetUI;
    /** @type {AddressSheetCoordinator} */
    #addrsCoordinator;
    /** @type {SettingsCoordinator} */
    #settingsCoordinator;
    
    // View für die Standort-Anzeige auf der Karte
    /** @type {MapLocationUI} */ 
    #mapLocationUI;
    
    // Zentrale Zustandsspeicher
    #isAdminModeActive = false; 
    #getAdminModeStatusLocal = () => this.#isAdminModeActive;
    
    // 🚨 Promises für das Vorladen der Daten (werden sofort gestartet)
    /** @type {Promise<void> | null} */
    #poisLoadPromise = null;
    /** @type {Promise<void> | null} */
    #locationTrackingPromise = null;


    /**
     * @param {function(): boolean} getAdminModeStatus - Funktion zum Abrufen des Admin-Status
     * @param {typeof import('./app-shell-ui.js').AppShellUI} AppShellUIClass - Die AppShellUI Klasse
     * @param {typeof import('./app-shell-co.js').AppShellCoordinator} AppShellCoordinatorClass - Die AppShellCoordinator Klasse
     * @param {function(HTMLElement): void} setupAdminModeDetectorFunc - Die Setup-Funktion für den Admin-Modus
     */
    constructor(getAdminModeStatus, AppShellUIClass, AppShellCoordinatorClass, setupAdminModeDetectorFunc) {
        this.#AppShellUIClass = AppShellUIClass;
        this.#AppShellCoordinatorClass = AppShellCoordinatorClass;
        this.#setupAdminModeDetectorFunc = setupAdminModeDetectorFunc; 
    }

    // ===============================================
    // 🚀 START-METHODE (UI/Hintergrund-Laden)
    // ===============================================

    /**
     * Startet die gesamte Anwendung und initiiert das parallele Laden.
     */
    async start() {
        mylog("ApplicationCoordinator: Startet den Bootstrapping-Prozess.");
        
        // 1-4. Initialisierung der Shell und des Coordinators
        const appShellUI = new this.#AppShellUIClass();
        appShellUI.injectIntoDOM(document.body); 
        const appShellCoordinator = new this.#AppShellCoordinatorClass(appShellUI);
        appShellCoordinator.setupAdminModeDetection(); 
        this.#appShellUI = appShellUI;
        this.#appShellCoordinator = appShellCoordinator;

        // 5. RESTLICHE MODULE INITIALISIEREN UND DATEN VORLADEN (startet Promises)
        this.initializeApplication(); 
        
        // 6. Spinner und Overlay anzeigen
        this.#appShellCoordinator.showLoadingSpinner();
        this.#appShellCoordinator.updateLoadingText("Bereite Karte vor...");
        this.#appShellCoordinator.showLocationPermissionOverlay();

        // 7. Vorladen des Hintergrunds (VERZÖGERT/ECHT PARALLEL)
        setTimeout(() => {
             this.#appShellCoordinator.preloadBackground();
        }, 0); 
    }
    
    // ===============================================
    // 🧠 INITIALISIERUNG DER MODULE UND PARALLELER START DER DATEN
    // ===============================================

    /**
     * Initialisiert alle App-Module und startet das VORLADEN der kritischen Daten.
     */
    initializeApplication() {
        mylog("ApplicationCoordinator: Startet die Modulinitialisierung.");
        setAdminStatusGetter(this.#getAdminModeStatusLocal); 

        // 1. Initialisierung der Map
        const mapInitResult = initMap(); 
        this.#map = mapInitResult.map;
        this.#markers = mapInitResult.markers;
        this.#appShellCoordinator.setMapInstance(this.#map);

        // 2. Initialisierung der Kerndienste und UIs
        this.#updatePoiUI = UpdatePoiUI.getInstance();
        this.#backendService = new BackendService();
        this.#bottomSheetUI = new BsUI('wrapper', 'bottom-sheet', 'bottom-sheet-content-area', 'bottom-sheet-actions-area');
        this.#insertPoiUI = new InsertPoiUI('add-button', 'add-icon', {
            onSave: (stoneData) => handleSaveStone(stoneData, this.#bottomSheetUI, this.#refreshMapMarkers.bind(this), this.#backendService)
        });
        this.#locationTracker = LocationTrackingCoordinator.getInstance();
        this.#mapLocationUI = new MapLocationUI(this.#map); 
        this.#addressSheetUI = new AddressSheetUI();
        this.#addrsCoordinator = new AddressSheetCoordinator(this.#addressSheetUI, this.#backendService);
        const settingsUIInstance = new SettingsUI();
        this.#settingsCoordinator = new SettingsCoordinator(settingsUIInstance, this.#getAdminModeStatusLocal); 

        // 3. Einrichten der Listener
        this.#setupAllListeners();
        
        // 🚨 VORLADEN DER DATEN SOFORT STARTEN (Paralleles Laden)
        mylog("ApplicationCoordinator: Starte paralleles Vorladen der POI-Daten und der Standort-Initialisierung.");
        
        // Standort-Tracking (Promise speichern)
        this.#locationTrackingPromise = this.#locationTracker.startTrackingAndHandlePermission().catch(error => {
            console.error("Fehler beim Vorladen der Standortabfrage (ignoriert):", error);
        });

        // POI-Daten im Hintergrund laden (Promise speichern)
        this.#poisLoadPromise = fetchPOIs(
            this.#map, this.#markers, this.#bottomSheetUI, this.#backendService, 
            this.#getAdminModeStatusLocal, this.#insertPoiUI, this.#updatePoiUI, this.#appShellCoordinator.updateLoadingText.bind(this.#appShellCoordinator)
        )
        // ✅ Spinner ausblenden, wenn POIs geladen sind (entkoppelt vom Klick)
        .then(() => {
            mylog("ApplicationCoordinator: POI-Daten erfolgreich vorgeladen. Blende Spinner aus.");
            this.#appShellCoordinator.hideLoadingSpinner();
        })
        .catch(error => {
            console.error("Fehler beim Vorladen der POI-Daten:", error);
            showToast("Fehler beim Vorladen der POI-Daten.", "Fehler");
            // ✅ Auch bei Fehler den Spinner ausblenden
            this.#appShellCoordinator.hideLoadingSpinner();
        });
    }

    // ===============================================
    // 📡 EVENT-ABONNEMENT UND LOGIK
    // ===============================================
    
    #setupAllListeners() {
        // --- Kartenspezifische Manager ---
        setupMapEventListeners(this.#map, this.#bottomSheetUI, this.#backendService, this.#getAdminModeStatusLocal, this.#insertPoiUI, this.#updatePoiUI);
        setupClusterEventListeners(this.#map, this.#markers, this.#bottomSheetUI, this.#backendService, this.#getAdminModeStatusLocal);
        
        // Bottom Sheet & Add Stone Logik
        updateSearchFieldWithAddress(null);
        this.#bottomSheetUI.onClose(() => { updateSearchFieldWithAddress(null); });
        this.#bottomSheetUI.onHeaderClick((zoom) => { centerMapOnBottomSheetContent(this.#map, this.#bottomSheetUI, zoom); }, this.#markers);
        this.#bottomSheetUI.onResize(() => { centerMapOnBottomSheetContent(this.#map, this.#bottomSheetUI); });
        initAddStoneLogic(this.#bottomSheetUI, this.#insertPoiUI, this.#refreshMapMarkers.bind(this), this.#backendService);
        
        // Adress-Logik
        setupGuiAddrsCoordinator(this.#addrsCoordinator, {
            map: this.#map, markerClusterGroup: this.#markers, bottomSheetUI: this.#bottomSheetUI, backendService: this.#backendService,
            getAdminModeStatus: this.#getAdminModeStatusLocal
        });
        setupAddrsCoordinatorListeners(this.#map, this.#addrsCoordinator, this.#bottomSheetUI);

        // --- AppShell Coordinator Events (ORCHESTRIERUNG HIER) ---
        this.#appShellCoordinator.onSearchTriggered(() => {
            mylog("[DEBUG] AppCoord: Search-Triggered Event erhalten, öffne Adress-Sheet.");
            this.#addrsCoordinator.triggerSheetOpened(); 
            this.#addressSheetUI.openResults();
        });
        this.#appShellCoordinator.onSettingsClicked(() => {
            mylog("[DEBUG] AppCoord: Settings-Event erhalten, delegiere an SettingsCoordinator.");
            this.#settingsCoordinator.toggleSettings();
        });
        this.#appShellCoordinator.onAdminTriggered(() => {
            mylog("[DEBUG] AppCoord: Admin-Triggered Event erhalten.");
            this.#handleAdminModeActivated();
        });

        // 4. Location Permission: Warte auf die bereits gestarteten Promises
        this.#appShellCoordinator.onLocationPermissionGranted(this.#handleLocationPermissionGranted.bind(this)); 
    }

    // ===============================================
    // ⚙️ HANDLER FÜR ADMIN-EVENT 
    // ===============================================
    
    /**
     * Führt die Logik aus, wenn die Tap-Sequenz erfolgreich war.
     * @private
     */
    #handleAdminModeActivated() {
        this.#isAdminModeActive = true; 
        showToast("Zusatzfunktionen aktiviert");
        console.log("Zusatzfunktionen aktiviert durch Taps!");
    }

    // ===============================================
    // ⚙️ ASYNCHRONE ORCHESTRIERUNG (Wartet auf bereits gestartete Promises)
    // ===============================================

    /**
     * Behandelt das Event, wenn der Benutzer auf "Stolpersteine anzeigen" klickt.
     * Wartet auf die bereits in initializeApplication() gestarteten Promises.
     * @private
     */
    async #handleLocationPermissionGranted() {
        mylog("ApplicationCoordinator: Klick erhalten. Warte auf Abschluss der vorab gestarteten Daten-Promises.");
        
        // WICHTIG: Sollte der Spinner in initializeApplication() noch nicht ausgeblendet worden sein, 
        // wird er hier wieder sichtbar gemacht/aktualisiert.
        // Da die Promise-API keine einfache "isRunning"-Prüfung bietet, zeigen wir ihn erneut an,
        // falls das Laden (trotz schneller Initialisierung) noch läuft.
        this.#appShellCoordinator.showLoadingSpinner();
        this.#appShellCoordinator.updateLoadingText("Warte auf verbleibende Daten und Standort...");


        // Auf die bereits gestarteten Promises warten
        await Promise.allSettled([ 
            this.#locationTrackingPromise,
            this.#poisLoadPromise
        ]);
        
        // Spinner ausblenden (wird hier final entfernt)
        this.#appShellCoordinator.hideLoadingSpinner();
        
        // Karte und Steuerelemente sichtbar machen
        this.#appShellCoordinator.showMapAndControls();

        // Sichtbarkeit des Add-Buttons basierend auf Standort-Tracking
        if (this.#locationTracker.isTrackingActive() && this.#insertPoiUI.buttonElement) {
            this.#insertPoiUI.buttonElement.classList.remove("hidden");
        } else if (this.#insertPoiUI.buttonElement) {
            this.#insertPoiUI.buttonElement.classList.add("hidden");
        }
        this.#settingsCoordinator.initializeSettingsState();
        mylog("ApplicationCoordinator: Daten-Promises abgeschlossen, Karte sichtbar.");
    }
    
    /**
     * Aktualisiert die Marker auf der Karte und fokussiert optional einen neuen Marker.
     * @param {object | null} focusData
     * @private
     */
    #refreshMapMarkers(focusData = null) {
        mylog("AppCoord: Karte wird mit neuen Markern aktualisiert. Fokus-Daten:", focusData);
        fetchPOIs(this.#map, this.#markers, this.#bottomSheetUI, this.#backendService, this.#getAdminModeStatusLocal, this.#insertPoiUI, this.#updatePoiUI) 
            .then(() => {
                if (focusData && focusData.newGid) {
                    const newMarker = this.#markers.getLayers().find(m => m.options.data.gid === focusData.newGid);
                    if (newMarker) {
                        this.#markers.zoomToShowLayer(newMarker, () => {
                            newMarker.fire('click');
                        });
                    } else {
                        console.warn(`Fehler beim Fokussieren: Neuer Marker mit GID ${focusData.newGid} nicht gefunden nach Refresh.`);
                    }
                }
            })
            .catch(error => {
                console.error("Fehler beim Aktualisieren der Karte nach Insert:", error);
            });
    }
}