// addrs-co.js
// Dieses Modul koordiniert die Interaktion zwischen der Adress-UI (addrs-ui.js) 
// und der Karte (gui-address-co.js), indem es Suchanfragen durchführt und Events weiterleitet.

import { AddressSheetUI } from './addrs-ui.js';
import { showToast } from './sc-utilities.js';
import { BackendService } from './backend-poi.js';
import { fetchAdressesFromHere, fetchAdressesFromNominatim } from './backend-geo.js';

export class AddressSheetCoordinator {

    constructor(addressSheetUI, backendService) {
        this.addressSheetUI = addressSheetUI;
        this.backendService = backendService;
        this.searchTimeout = null;

        // Callbacks für die Events, die gui-address-co.js abfangen soll
        this.guiLocationRequestedCallbacks = [];
        this.currentLocationSelectedCallbacks = [];
        this.stateChangeCallbacks = [];
        this.sheetTriggeredCallbacks = [];
      

        this._addEventListeners();
        console.log("AddressSheetCoordinator initialisiert (volle Entkopplung).");
    }

    /**
     * Registriert alle notwendigen Event-Listener.
     * @private
     */
    _addEventListeners() {
        this.addressSheetUI.onSearchInput(this.handleSearchInput.bind(this));
        /**
  * Registriert einen Callback für das "GuiLocationRequested"-Event.
  * Dies wird vom aufrufenden Code als addrsCoordinator.searchResultSelected erwartet.
  * @param {function({lat: number, lon: number, displayName: string, source: string}): void} callback
  */
        this.addressSheetUI.searchResultSelected(this._handleSearchResultSelected.bind(this));
        /**
     * Registriert einen Callback für das "currentLocationSelected"-Event.
     * @param {function(): void} callback
     */
        this.addressSheetUI.onCurrentLocationSelected(this._handleCurrentLocationSelectedFromUI.bind(this));

        }

    /**
     * Handler für das UI-Event "addressSelected".
     * Löst ein Coordinator-Event "GuiLocationRequested" aus.
     * @param {{lat: number, lon: number, displayName: string, source: string}} addressData
     * @private
     */
    _handleSearchResultSelected(addressData) {
        console.log("DEBUG (Coordinator): Adresse vom UI ausgewählt, gebe 'GuiLocationRequested' Event weiter.", addressData);
        this.addressSheetUI.closeResults();
        this._emit('GuiLocationRequested', addressData);
    }

    /**
     * Handler für das UI-Event "currentLocationSelected".
     * Löst ein Coordinator-Event "currentLocationSelected" aus.
     * @private
     */
    _handleCurrentLocationSelectedFromUI() {
        console.log('DEBUG (Coordinator): "Aktueller Standort" vom UI ausgewählt, gebe "currentLocationSelected" Event weiter.');
        this.addressSheetUI.closeResults();
        this._emit('currentLocationSelected');
    }




    // ⭐ WICHTIGE ÄNDERUNG: Methode umbenannt und öffentlich gemacht für den App-Shell Aufruf
    /**
     * Löst manuell ein Coordinator-Event "sheetOpened" aus (von externen Triggern aufgerufen).
     * Hier ist dies eine einfache Weiterleitung, da die eigentliche Öffnungslogik in der UI liegt.
     */
    triggerSheetOpened() { // ⬅️ KORREKTUR
        console.log("DEBUG (Coordinator): 'Sheet Opened' von App-Shell empfangen, gebe Event weiter.");
        this._emit('sheetOpened');
    }


    /**
     * Registriert einen Callback für das "GuiLocationRequested"-Event.
     * Dies ist das "abstrahierte" Event, das die App-Logik (Karten-Zoom, Validierung) abonnieren sollte.
     * @param {function({lat: number, lon: number, displayName: string, source: string}): void} callback
     */
    onGuiLocationRequested(callback) {
        this.guiLocationRequestedCallbacks.push(callback);
    }

    /**
     * Registriert einen Callback für das "currentLocationSelected"-Event.
     * @param {function(): void} callback
     */
    onCurrentLocationSelected(callback) {
        this.currentLocationSelectedCallbacks.push(callback);
    }



    /**
     * Registriert einen Callback für das "sheetOpened"-Event.
     * @param {function(): void} callback
     */
    onSheetOpened(callback) { // Die Registrierungsmethode behält den Namen
        this.sheetTriggeredCallbacks.push(callback);
    }

    /**
     * Hilfsfunktion zum Auslösen von benutzerdefinierten Events.
     * @param {string} eventName - Name des auszulösenden Events.
     * @param {*} [data] - Daten, die mit dem Event übergeben werden sollen.
     * @private
     */
    _emit(eventName, data) {
        const callbacks = {
            'GuiLocationRequested': this.guiLocationRequestedCallbacks,
            'currentLocationSelected': this.currentLocationSelectedCallbacks,
            'sheetOpened': this.sheetTriggeredCallbacks,
        };

        if (callbacks[eventName]) {
            callbacks[eventName].forEach(cb => {
                try {
                    cb(data);
                } catch (e) {
                    console.error(`Fehler beim Ausführen des Event-Listeners für '${eventName}':`, e);
                }
            });
        }
    }

    // ====================================================================
    // HILFSFUNKTIONEN FÜR POI-NAMENSSUCHE (Name/Jahr)
    // ====================================================================

    /**
     * Extrahiert Namensbestandteile (mind. 1 Komponente) 
     * und ein optionales 4-stelliges Geburtsjahr aus der Query.
     * @param {string} query Die rohe Benutzereingabe (z.B. "Max-Emil Mustermann geb. 1900").
     * @returns {{nameParts: string[], yearOfBirth: number|null}}
     */

    _extractNameComponents(query) {
        let yearOfBirth = null;

        const rawParts = query
            .split(/\s+/)
            .map(p => p.trim())
            .filter(Boolean);

        const nameParts = [];
        const nameRegex = /^[a-zA-ZäöüÄÖÜß\-]+$/;

        for (const token of rawParts) {

            // A) gültiges Jahr
            if (/^\d{4}$/.test(token)) {
                const yr = parseInt(token, 10);
                if (yr >= 1840 && yr <= 1945) {
                    yearOfBirth = yearOfBirth ?? yr;
                    continue;
                }
                // Jahr 4-stellig, aber ungültig → Abbruch
                return { invalid: true, nameParts: [], yearOfBirth: null };
            }

            // B) gültiger alphabetischer Name
            if (nameRegex.test(token)) {
                nameParts.push(token);
                continue;
            }

            // ❌ C) alles andere → Abbruch
            return { invalid: true, nameParts: [], yearOfBirth: null };
        }

        // Jetzt sind nur gültige Tokens enthalten.
        return { invalid: false, nameParts, yearOfBirth };
    }


    // ====================================================================
    // VORHANDENE HILFSFUNKTIONEN FÜR ADRESSSUCHE
    // ====================================================================

 /**
 * Versucht, eine Adresse (Straße, Hausnummer) aus einer Freitext-Abfrage zu extrahieren.
 * TRENNSICHERHEIT: Trennt den String beim ersten Auftreten einer Ziffer.
 * @param {string} query Die Freitext-Abfrage (z.B. "Alexanderstraße 6-7, Mitte").
 * @returns {{street: string | null, houseNr: string | null}}
 * @private
 */
_extractAddressComponents(query) {
    const components = { street: null, houseNr: null };
    // Entfernt Kommas und trimmt Ränder
    const streetAndNumberPart = query.split(',')[0].trim(); 

    // Regulärer Ausdruck: Finde den Index des ersten Ziffernblocks (\d+)
    // (\s*): Erlaubt optionale Leerzeichen vor der Ziffer (optional, aber nützlich)
    const firstDigitMatch = streetAndNumberPart.match(/(\s*\d+)/); 

    if (firstDigitMatch && firstDigitMatch.index > 0) {
        
        // 1. Straße: Alles vom Anfang bis zum Index des ersten Ziffern-Matches
        let streetRaw = streetAndNumberPart.substring(0, firstDigitMatch.index);
        
        // 2. Hausnummer: Alles vom Index des ersten Ziffern-Matches bis zum Ende
        let houseNrRaw = streetAndNumberPart.substring(firstDigitMatch.index);

        // Komponenten zuweisen und zusätzliche Leerzeichen entfernen
        components.street = streetRaw.trim();
        components.houseNr = houseNrRaw.trim(); 
        
        // --- Zusätzlicher Schritt: Leerzeichen zwischen Street und HouseNr entfernen ---
        // (Wird bereits durch die trim()-Aufrufe in den Substrings und der Trennung am Index erledigt.)
        
        // Zusätzliches Debugging für die neue Logik
        console.log("DEBUG: SUCCESSFUL Simple Separation:", components); 

    } else {
        // Wenn keine Ziffer gefunden wird, wird der gesamte String als Straße behandelt.
        components.street = streetAndNumberPart.trim();
        components.houseNr = null;
        console.log("DEBUG: FAILED Simple Separation, whole string treated as street:", components);
    }

    return components;
}




    // ====================================================================
    // HAUPTLOGIK: handleSearchInput (Jetzt mit POI Name/Jahr Priorität)
    // ====================================================================

    async handleSearchInput(query) {
        if (query.length < 3) {
            clearTimeout(this.searchTimeout);
            this.addressSheetUI.setInitialResultsContent();
            return;
        }

        clearTimeout(this.searchTimeout);

        this.searchTimeout = setTimeout(async () => {

            const html = '<p style="--status-color: #888; --status-padding: 20px; text-align: center; color: var(--status-color); padding: var(--status-padding);"><i class="fas fa-spinner fa-spin"></i> Suchen...</p>';

            this.addressSheetUI.renderResults([
                { display_name: html, source: 'status', lat: 0, lon: 0 }
            ]);

            let finalResults = [];

            // --- Hilfsvariable für Adress-Logik ---
            // Prüfen, ob eine Hausnummer in der Query ist (wird für POI-Adress- und HERE-Fallback genutzt)
            const hausnummerRegex = /[.\s]\d{1,5}[a-zA-Z]?/;
            const isHouseNrQuery = hausnummerRegex.test(query);


            // =========================================================
            // 1. POI-DB nach Name/Jahr abfragen (höchste Priorität)
            // =========================================================
            const nameComponents = this._extractNameComponents(query);
            const { nameParts, yearOfBirth, invalid } = nameComponents;

            if (!invalid) {
                const hasYear = yearOfBirth !== null;
                const isValidYear = Number.isInteger(yearOfBirth) &&
                    yearOfBirth >= 1840 &&
                    yearOfBirth <= 1945;

                const caseA = (nameParts.length > 0 && isValidYear);  // 1+ Namen + gültiges Jahr
                const caseB = (nameParts.length > 1 && !hasYear);      // 2+ Namen ohne Jahr

                const shouldCallAPI = caseA || caseB;

                if (shouldCallAPI) {
                    try {
                        const poiNameResults = await this.backendService.fetchPoisByName(nameParts, yearOfBirth);
                        console.log(`DEBUG: POI-Backend (Name/Jahr) hat ${poiNameResults.length} Treffer gefunden.`);
                        finalResults.push(...poiNameResults);
                    } catch (e) {
                        console.error("POI-Suche (Name/Jahr) fehlgeschlagen:", e.message);
                    }
                } else {
                    console.log("DEBUG: POI-Suche (Name/Jahr) übersprungen (Regeln nicht erfüllt).");
                }
            }


            // =========================================================
            // 2. POI-DB nach Adresse abfragen (NEUE PRIORITÄT)
            // =========================================================
            const addressComponents = this._extractAddressComponents(query);

            if (isHouseNrQuery && addressComponents.street && addressComponents.houseNr) {
                // Status: POI-Datenbank Suche (Adresse)...
                this.addressSheetUI.renderResults([
                    { display_name: '<p style="text-align: center; color: #888; padding: 20px;"><i class="fas fa-database"></i> Suche in POI-Datenbank (Adresse)...</p>', source: 'status', lat: 0, lon: 0 }
                ]);

                try {
                    const poiAddressResults = await this.backendService.fetchPoisByAddress(
                        addressComponents.street,
                        addressComponents.houseNr
                    );

                    if (poiAddressResults && poiAddressResults.length > 0) {
                        console.log(`DEBUG: POI-Backend (Adresse) hat ${poiAddressResults.length} Treffer gefunden.`);
                        finalResults.push(...poiAddressResults);
                    }

                } catch (e) {
                    console.error("POI-Suche (Adresse) fehlgeschlagen:", e.message);
                }
            }


            // =========================================================
            // 3. Nominatim (OSM) abfragen (Standard-Geo-Suche)
            // =========================================================
            let nominatimResults = [];
            try {
                // Status: Nominatim (OSM) Suche...
                this.addressSheetUI.renderResults([
                    { display_name: '<p style="text-align: center; color: #888; padding: 20px;"><i class="fas fa-globe-europe"></i> Suche in OpenStreetMap (Nominatim)...</p>', source: 'status', lat: 0, lon: 0 }
                ]);

                nominatimResults = await fetchAdressesFromNominatim(query);
                console.log(`DEBUG: Nominatim (OSM) hat ${nominatimResults.length} Treffer gefunden.`);
                finalResults.push(...nominatimResults);

            } catch (e) {
                console.error("Nominatim-Suche fehlgeschlagen:", e.message);
            }


            // =========================================================
            // 4. HERE-Fallback abfragen (Wenn Nominatim keine Hausnummer fand)
            // =========================================================
            const nominatimFoundHouseNr = nominatimResults.some(item => item.houseNr && item.source === 'OSM');

            if (isHouseNrQuery && !nominatimFoundHouseNr) {

                // Status: Spezifische Suche (HERE)...
                this.addressSheetUI.renderResults([
                    { display_name: '<p style="text-align: center; color: #888; padding: 20px;"><i class="fas fa-search-location"></i> Spezifische Suche (HERE)...</p>', source: 'status', lat: 0, lon: 0 }
                ]);

                try {
                    const hereResults = await fetchAdressesFromHere(query);
                    if (hereResults && hereResults.length > 0) {
                        console.log(`DEBUG: HERE hat ${hereResults.length} Treffer gefunden.`);
                        // Fügen Sie HERE-Ergebnisse am Ende der finalResults hinzu
                        finalResults.push(...hereResults);
                    }
                } catch (e) {
                    console.error("HERE-Suche fehlgeschlagen:", e.message);
                }
            }


            // =========================================================
            // ERGEBNISSE RENDERN
            // =========================================================
            if (finalResults.length > 0) {
                this.addressSheetUI.renderResults(finalResults);
            } else {
                console.log("DEBUG: Alle Suchen waren erfolglos.");
                this.addressSheetUI.renderResults([]);
                showToast(`Keine Treffer für "${query}" gefunden.`, 'Information');
            }

            
        }, 500);
    }
}