// 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 './utilities.js';
import { BackendService } from './backend-db.js';
import { fetchAdressesFromHere, fetchAdressesFromNominatim } from './backend-geo.js';

export class AddressSheetCoordinator {

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

        // Callbacks für die Events
        this.guiLocationRequestedCallbacks = [];
        this.currentLocationSelectedCallbacks = [];
        this.nextDirtyStoneSelectedCallbacks = []; 
        this.stateChangeCallbacks = [];
        this.sheetTriggeredCallbacks = [];

        this._addEventListeners();
        console.log("AddressSheetCoordinator initialisiert (Vollständige Version).");
    }

    /**
     * Registriert alle notwendigen Event-Listener.
     * @private
     */
    _addEventListeners() {
        // Verarbeitung für die "ajax" such liste
        this.addressSheetUI.registerSearchInputCb(this.handleSearchInput.bind(this));
        // Verarbeitung für Speicherung der aktuellen Sucheingabe
        this.addressSheetUI.registerSearchInputCb(this.saveCurrentSearchInput.bind(this));

        this.addressSheetUI.searchResultSelected(this._handleSearchResultSelected.bind(this));
        this.addressSheetUI.onCurrentLocationSelected(this._handleCurrentLocationSelectedFromUI.bind(this));
        this.addressSheetUI.onNextDirtyStoneSelected(this._handleNextDirtyStoneSelectedFromUI.bind(this));
    }

    /**
     * Handler für das UI-Event "addressSelected".
     */
    _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".
     */
    _handleCurrentLocationSelectedFromUI() {
        console.log('DEBUG (Coordinator): "Aktueller Standort" vom UI ausgewählt.');
        this.addressSheetUI.closeResults();
        this._emit('currentLocationSelected');
    }

    /**
     * Handler für das UI-Event "nextDirtyStoneSelected".
     */
    _handleNextDirtyStoneSelectedFromUI() {
        console.log('DEBUG (Coordinator): "Pflegebedarf" vom UI ausgewählt.');
        this.addressSheetUI.closeResults();
        this._emit('nextDirtyStoneSelected');
    }

    /**
     * Löst manuell ein Coordinator-Event "sheetOpened" aus.
     */
    triggerSheetOpened() {
        console.log("DEBUG (Coordinator): 'Sheet Opened' empfangen.");
        const currentQuery = this.addressSheetUI.searchInputEl.value || "";
        this.handleSearchInput(currentQuery);
        this._emit('sheetOpened');
    }

    /**
     * Registrierungsmethoden für externe Module
     */
    onGuiLocationRequested(callback) { this.guiLocationRequestedCallbacks.push(callback); }
    onCurrentLocationSelected(callback) { this.currentLocationSelectedCallbacks.push(callback); }
    onNextDirtyStoneSelected(callback) { this.nextDirtyStoneSelectedCallbacks.push(callback); }
    onSheetOpened(callback) { this.sheetTriggeredCallbacks.push(callback); }

    /**
     * Hilfsfunktion zum Auslösen von benutzerdefinierten Events.
     */
    _emit(eventName, data) {
        const callbacks = {
            'GuiLocationRequested': this.guiLocationRequestedCallbacks,
            'currentLocationSelected': this.currentLocationSelectedCallbacks,
            'sheetOpened': this.sheetTriggeredCallbacks,
            'nextDirtyStoneSelected': this.nextDirtyStoneSelectedCallbacks,
        };

        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);
                }
            });
        }
    }

    saveCurrentSearchInput(query) {
        this.searchBuffer = query;
    }

    async handleSearchInput(query) {
        const trimmedQuery = query.trim();

        // 1. Sofortige Prüfung für den Hinweistext
        if (trimmedQuery.length === 0) {
            clearTimeout(this.searchTimeout);
            this.addressSheetUI.setValidationHint(true);
            this.addressSheetUI.renderResults([]);
            return;
        } else {
            this.addressSheetUI.setValidationHint(false); 
        }

        // 2. Abbruch bei zu kurzer Eingabe
        if (trimmedQuery.length < 3) {
            clearTimeout(this.searchTimeout);
            return;
        }

        // 3. Suche mit Delay
        clearTimeout(this.searchTimeout);
  this.searchTimeout = setTimeout(async () => {
    // 1. INPUT REINIGEN (Live-Replace)
    // Wir ersetzen Bindestriche, Kommas und Slashes durch Leerzeichen
    // und reduzieren Mehrfach-Leerzeichen auf eines.
    const sanitizedQuery = query
        .replace(/[-,\/]/g, ' ')
        .replace(/\s+/g, ' ')
        .trim();

    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: 'noSourceButSpinner', lat: 0, lng: 0 }]);
    
    let finalResults = [];
    const houseNrRegex = /[.\s]\d{1,5}[a-zA-Z]?/;
    const isHouseNrQuery = houseNrRegex.test(sanitizedQuery);

    // A: Namenssuche (nutzt die bereinigte Query)
    const nameComponents = this._extractNameComponents(sanitizedQuery);
    const { nameParts, yearOfBirth, invalid } = nameComponents;

    if (!invalid) {
        const hasYear = yearOfBirth !== null;
        // Wir erlauben die Suche, wenn Teile da sind
        if ((nameParts.length > 0 && hasYear) || (nameParts.length > 1 && !hasYear)) {
            try {
                // Wir schicken die sauberen nameParts (Array) ans Backend
                const poiNameResults = await this.backendService.fetchPoisByName(nameParts, yearOfBirth);
                if (poiNameResults) finalResults.push(...poiNameResults);
            } catch (e) { console.error("Fehler POI Name:", e); }
        }
    }

    // B: Adress-POI Suche
    const addressComponents = this._extractAddressComponents(sanitizedQuery);
    if (addressComponents.street) {
        try {
            const poiAddressResults = await this.backendService.fetchPoisByAddress(
                addressComponents.street, 
                addressComponents.houseNr || ""
            );
            if (poiAddressResults) finalResults.push(...poiAddressResults);
        } catch (e) { console.error("Fehler POI Adresse:", e); }
    }

    // C: Externe APIs (Nominatim/HERE profitieren auch von der sauberen Query)
    try {
        const nominatimResults = await fetchAdressesFromNominatim(sanitizedQuery);
        finalResults.push(...nominatimResults);
        
        const nominatimFoundHouseNr = nominatimResults.some(item => item.houseNr && item.source === 'OSM');
        if (isHouseNrQuery && !nominatimFoundHouseNr) {
            const hereResults = await fetchAdressesFromHere(sanitizedQuery);
            if (hereResults) finalResults.push(...hereResults);
        }
    } catch (e) { console.error("Fehler Externe APIs:", e); }

    // Dubletten-Check (nach GID), falls Adress- und Namenssuche denselben POI finden
    const uniqueResults = Array.from(new Map(finalResults.map(item => [item.gid || item.display_name, item])).values());

    if (uniqueResults.length > 0) {
        this.addressSheetUI.renderResults(uniqueResults);
    } else {
        this.addressSheetUI.renderResults([]);
        showToast(`Keine Treffer für "${sanitizedQuery}" gefunden.`, 'Information');
    }
}, 500);
    }

    _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) {
            if (/^\d{4}$/.test(token)) {
                const yr = parseInt(token, 10);
                if (yr >= 1840 && yr <= 1945) {
                    yearOfBirth = yearOfBirth ?? yr;
                    continue;
                }
                return { invalid: true, nameParts: [], yearOfBirth: null };
            }
            if (nameRegex.test(token)) {
                nameParts.push(token);
                continue;
            }
            return { invalid: true, nameParts: [], yearOfBirth: null };
        }
        return { invalid: false, nameParts, yearOfBirth };
    }

    _extractAddressComponents(query) {
        const components = { street: null, houseNr: null };
        const streetAndNumberPart = query.split(',')[0].trim(); 
        const firstDigitMatch = streetAndNumberPart.match(/(\s*\d+)/); 
        if (firstDigitMatch && firstDigitMatch.index > 0) {
            components.street = streetAndNumberPart.substring(0, firstDigitMatch.index).trim();
            components.houseNr = streetAndNumberPart.substring(firstDigitMatch.index).trim(); 
        } else {
            components.street = streetAndNumberPart.trim();
            components.houseNr = null;
        }
        return components;
    }
}