/**
 * @fileoverview map-gen-mgr.js
 * Hauptmodul für das Management der POIs (Points of Interest).
 * Dieses Modul kümmert sich um das Laden der Daten, die Marker-Erstellung und die Klick-Events.
 */

import { getColorCodeAndText, getMarkerIcon, calculateClusterColor } from './marker-display-utils.js';
import { updateMapOnMarkerClick, UpdateMarkerIcon, handleMarkerSelectionMap } from './map-poi-mgr.js';
import { mylog, is_development, updateSpinner, forceRedraw, wait, showToast } from './sc-utilities.js';
import { updateBsForPoi, handleMarkerSelectionBs } from './bs-poi-co.js';
import { setClusterMarkerIndex } from './bs-cluster-co.js';
import { restoreClusterOriginalStyles } from './map-cluster-mgr.js';
import { removeAddressMarker } from './gui-address-co.js';
import { LocationTrackingCoordinator } from './loc-tracking-co.js';
import { MapLocationUI } from './map-loc-ui.js';
import { getMap, getMarkers, mapState } from './map-markers-co.js';
import { updateSearchFieldWithAddress } from './app-shell-co.js';
import { handleBsUpdate } from './bs-gen-co.js';
// Datenmodell und zentraler Speicher
import { ScStone } from './ScStone.js';
import { updatePoiStore, getPoiData } from './poi-store.js';
import { demarcate_route } from './map-poi-navigation.js';

/**
 * Ruft POI-Daten vom Server ab und erstellt Marker.
 */
export async function fetchPOIs(
    bottomSheetUI,
    backendService,
    insertPoiUI,
    updatePoiUI,
    loadingUpdateCallback = () => { }) {

    const map = getMap();
    const markers = getMarkers();

    if (markers && markers.clearLayers) {
        markers.clearLayers();
    }

    const CHUNK_SIZE = 20000;
    let currentStartId = 0;
    let totalMarkersLoaded = 0;

    try {
        while (true) {
            loadingUpdateCallback(`${currentStartId} Stolpersteine`);

            const dataChunk = await backendService.fetchPOIs(currentStartId, currentStartId + CHUNK_SIZE);

            if (!Array.isArray(dataChunk) || dataChunk.length === 0) break;

            const poiMarkers = [];

            for (const feature of dataChunk) {
                const props = feature.properties;
                let coords = feature.geometry?.coordinates;

                if (coords) {
                    // 1. Datenmodell erstellen
                    const poiInstance = new ScStone({
                        ...props,
                        lat: coords[1],
                        lng: coords[0]
                    }, backendService);

                    // 2. Im Store registrieren
                    updatePoiStore([poiInstance]);

                    // 3. Marker-Optik
                    const statusInfo = getColorCodeAndText(poiInstance.last_cleaned);
                    const colorCode = statusInfo.colorCode;

                    // 4. Leaflet Marker erstellen
                    const marker = L.marker([poiInstance.lat, poiInstance.lng], {
                        icon: L.divIcon({
                            className: "poi-icon " + colorCode,
                            html: getMarkerIcon(poiInstance.caretaker, colorCode),
                            iconSize: mapState.originalActiveMarkerSize,
                        }),
                        gid: poiInstance.gid,
                        data: poiInstance // Wichtig für map-poi-mgr.js (Crash-Prävention)
                    });

                    marker.stone = poiInstance;

                    // 5. Klick-Event
                    marker.on('click', function (event) {
                        L.DomEvent.stopPropagation(event);

                        // Karte aufräumen 
                        removeAddressMarker();
                        demarcate_route(getMap());

                        const gid = this.options.gid;
                        // Aufruf der neuen zentralen Funktion
                        handleMarkerSelection(
                            gid,
                            { bottomSheetUI, backendService, mapState, insertPoiUI, updatePoiUI, map },
                            this.__parent || null // Das Cluster, falls vorhanden
                        );
                    });

                    poiMarkers.push(marker);
                }
            }

            markers.addLayers(poiMarkers);
            totalMarkersLoaded += dataChunk.length;
            currentStartId += CHUNK_SIZE;
        }

        if (totalMarkersLoaded > 0) {
            map.addLayer(markers);
        }

    } catch (error) {
        console.error("Fehler beim Abrufen der POIs:", error.message);
    } finally {
        await wait(500);
    }
}

/**
 * Zentraler Einstiegspunkt für jede Selektion (Click, Swipe, Suche)
 */

export function handleMarkerSelection(gid, allParams, parentCluster = null) {
    const { bottomSheetUI, backendService, mapState } = allParams;
    const markersGroup = getMarkers();

    // 1. Marker-Instanz finden
    const marker = findMarkerByGid(gid);
    if (!marker) return;

    // 2. Cluster-Lookup (via __parent oder getVisibleParent)
    let cluster = parentCluster;
    if (!cluster && markersGroup) {
        if (marker.__parent && typeof marker.__parent.getAllChildMarkers === 'function') {
            cluster = marker.__parent;
        } else {
            const vp = markersGroup.getVisibleParent(marker);
            if (vp && typeof vp.getAllChildMarkers === 'function') {
                cluster = vp;
            }
        }
    }

    // 3. Zustand im mapState speichern
    // WICHTIG: Vor dem Highlighting den alten Marker de-markieren
    if (mapState.activeMarkerOrCluster && mapState.activeMarkerOrCluster !== marker) {
        demarcateElement(mapState.activeMarkerOrCluster, mapState);
    }

    mapState.activeMarkerOrCluster = marker;
    mapState.parentClusterOfActiveMarker = (cluster && cluster.getAllChildMarkers) ? cluster : null;

    // 4. VISUELLES HIGHLIGHTING (Marker hervorheben)
    // Wir nutzen die existierende UpdateMarkerIcon Funktion
    if (typeof UpdateMarkerIcon === 'function') {
        UpdateMarkerIcon(marker, true, mapState);
    }

    // 5. Adresse im BS und im Suchfeld aktualisieren
    const data = marker.options.data || marker.stone;
    if (data) {
        bottomSheetUI.updateAddress(data.street, data.house_no, data.localdistrict);
        if (typeof updateSearchFieldWithAddress === 'function') {
            updateSearchFieldWithAddress(bottomSheetUI.currentAddress);
        }
    }

    // 6. Navigation und UI-Spezialisten
    if (cluster) {
        setClusterMarkerIndex(marker, cluster);
    }

    // Ruft die Karten-spezifische Logik (Pan/Zoom) und BS-Logik auf
    handleMarkerSelectionMap(marker, allParams);
    handleMarkerSelectionBs(gid, allParams);
}
/**
 * Erstellt effizient einen einzelnen neuen Marker aus Store-Daten.
 */
export function addNewMarkerFromStore(gid, uiParams) {
    const poi = getPoiData(gid);
    if (!poi) {
        console.error(`addNewMarkerFromStore: GID ${gid} nicht im Store.`);
        return;
    }

    const markers = getMarkers();
    const statusInfo = getColorCodeAndText(poi.last_cleaned);
    const colorCode = statusInfo.colorCode;

    // Marker-Struktur erstellen
    const marker = L.marker([poi.lat, poi.lng], {
        icon: L.divIcon({
            className: "poi-icon " + colorCode,
            html: getMarkerIcon(poi.caretaker, colorCode),
            iconSize: mapState.originalActiveMarkerSize,
        }),
        gid: poi.gid,
        data: poi
    });

    marker.stone = poi;

    // Der Klick-Handler nutzt bereits handleMarkerSelection
    marker.on('click', function (event) {
        if (event) L.DomEvent.stopPropagation(event);

        // Karte aufräumen 
        removeAddressMarker();
        demarcate_route(getMap());

        handleMarkerSelection(
            gid,
            uiParams,
            this.__parent || null
        );
    });

    // In Cluster einfügen
    markers.addLayer(marker);

    // Zoom-to-Animation und DIREKTE Logik statt fire('click')
    markers.zoomToShowLayer(marker, () => {
        setTimeout(() => {
            // KONSEQUENT: Direkter Aufruf der zentralen Logik
            handleMarkerSelection(
                gid,
                uiParams,
                marker.__parent || null
            );
        }, 100);
    });
}
/**
 * Prüft auf Überdeckung durch das BottomSheet.
 */
export function shouldPanToElement(latLng) {
    const map = getMap();
    if (!map) return false;
    const mapPx = map.latLngToContainerPoint(latLng);
    const mapHeight = map.getSize().y;
    const thresholdY = mapHeight * 0.65;
    return mapPx.y > thresholdY;
}

/**
 * Setup der Karten-weiten Event-Listener.
 */
export function setupMapEventListeners(bottomSheetUI, backendService, insertPoiUI, updatePoiUI) {
    const map = getMap();
    if (!map) return;
    map.on('click', function (e) {

        if (e.originalEvent && e.originalEvent.cancelBubble) return;
        removeAddressMarker();
        if (bottomSheetUI.isOpen()) {
            bottomSheetUI.close();
        }
    });
}

/**
 * Zentriert die Karte über dem BottomSheet.
 */
export function centerMapOnBottomSheetContent(bottomSheetUI, zoom) {
    const map = getMap();
    if (!map) return;
    const coords = bottomSheetUI.getDisplayCoords();
    if (shouldPanToElement(coords)) {
        if (coords && coords.lat !== null && coords.lng !== null) {
            const pointPixel = map.latLngToContainerPoint([coords.lat, coords.lng]);
            const sheetHeight = bottomSheetUI.bottomSheet.offsetHeight;
            const yOffset = sheetHeight / 2;
            const newPixelPoint = new L.Point(pointPixel.x, pointPixel.y + yOffset);
            const newCenterLatLng = map.containerPointToLatLng(newPixelPoint);
            map.setView(newCenterLatLng, zoom || map.getZoom());
        }
    }
}

/**
 * Entfernt Markierungen von Elementen.
 */
export function demarcateElement(element, mapState) {
    const isMarker = element.options && (element.options.gid || element.options.data);
    if (isMarker) {
        UpdateMarkerIcon(element, false, mapState);
    } else if (element._icon) {
        restoreClusterOriginalStyles(element._icon, element);
    }
}

/**
 * Listener für Adress-Koordinaten.
 */
export function setupAddrsCoordinatorListeners(addrsCoordinator, bottomSheetUI, mapLocationUI) {
    const map = getMap();
    const addressSheetUI = addrsCoordinator.addressSheetUI;
    const locTrackingCoordinator = LocationTrackingCoordinator.getInstance();

    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 && locTrackingCoordinator.isTrackingActive();
        addressSheetUI.updateCurrentLocationButton(isEnabled);
    });
}
/*
 * Sucht den Marker direkt in der Leaflet MarkerClusterGroup
 */
export function findMarkerByGid(gid) {
    // getMarkers() gibt deine MarkerClusterGroup zurück
    const clusterGroup = getMarkers();

    // Wir durchsuchen alle Layer, die in der ClusterGroup registriert sind
    const allLayers = clusterGroup.getLayers();

    // Wir finden den Marker, dessen options.gid übereinstimmt
    // (Wir nutzen == statt ===, falls die GID mal als String/Zahl gemischt kommt)
    return allLayers.find(marker => marker.options && marker.options.gid == gid) || null;
}
