// loc-tracking-co.js
import { showToast, mylog, getColorCodeAndText } from './utilities.js';
import { fitMapToTarget } from './map-gen-mgr.js';
import { getPoiData } from './poi-store.js';
import { L, getMap, getMarkers} from './map-service.js';

/**
 * Eine Klasse zur Verwaltung des Benutzerstandorts, implementiert als Singleton.
 */
export class LocationTrackingCoordinator {
    static #instance = null;

    static getInstance() {
        if (!LocationTrackingCoordinator.#instance) {
            LocationTrackingCoordinator.#instance = new LocationTrackingCoordinator();
        }
        return LocationTrackingCoordinator.#instance;
    }

    constructor() {
        if (LocationTrackingCoordinator.#instance) {
            throw new Error("Verwenden Sie LocationTrackingCoordinator.getInstance()");
        }

        this._isManuallyDeactivatedByUser = false;
        this._trackingActive = false;
        this._watchId = null;
        this._lastKnownPosition = null;
        this._trackingStateChangeListeners = [];
        this._newPositionListeners = [];

        mylog("LocationTrackingCoordinator: Singleton-Instanziiert.");
    }

    // --- Observer / Dispatcher Methoden ---

    onTrackingStateChange(callback) {
        if (typeof callback === 'function') {
            this._trackingStateChangeListeners.push(callback);
        }
    }

    onNewPosition(callback) {
        if (typeof callback === 'function') {
            this._newPositionListeners.push(callback);
        }
    }

    _dispatchTrackingState(newState) {
        this._trackingStateChangeListeners.forEach(callback => {
            try { callback(newState); } catch (e) { console.error(e); }
        });
        mylog(`LocationTrackingCoordinator: Status -> ${newState ? 'aktiv' : 'inaktiv'}`);
    }

    _dispatchNewPosition(position) {
        this._lastKnownPosition = position;
        this._newPositionListeners.forEach(callback => {
            try { callback(position, false); } catch (e) { console.error(e); }
        });
    }

    _dispatchInitialPosition(position) {
        this._lastKnownPosition = position;
        this._newPositionListeners.forEach(callback => {
            try { callback(position, true); } catch (e) { console.error(e); }
        });
    }

    _setTrackingActive(newState) {
        if (this._trackingActive !== newState) {
            this._trackingActive = newState;
            this._dispatchTrackingState(newState);
        }
    }

    // --- Model Query Methoden ---

    isTrackingActive() {
        return this._trackingActive && !this._isManuallyDeactivatedByUser;
    }

    getUserPosition() {
        if (this._lastKnownPosition) {
            return [this._lastKnownPosition.coords.latitude, this._lastKnownPosition.coords.longitude];
        }
        return null;
    }

    // --- FACHLOGIK NAVIGATION ---
/*
async navigateToNextCareNeed(dependencies) {
    console.log("DEBUG: navigateToNextCareNeed gestartet");
    const userPos = this.getUserPosition();

    if (!userPos) {
        console.warn("DEBUG: Kein userPos vorhanden!");
        showToast('Standort unbekannt. Bitte GPS aktivieren.', 'Info');
        return;
    }

    const userLatLng = L.latLng(userPos[0], userPos[1]);
    const markersGroup = getMarkers();

    if (!markersGroup) {
        console.error("DEBUG: markersGroup ist null!");
        return;
    }

    let bestCandidate = null;
    let minWeightedDistance = Infinity;

    // Suche nach dem nächsten Stein (Logik bleibt identisch)
    markersGroup.eachLayer(marker => {
        if (marker instanceof L.Marker && marker.options?.gid) {
            const storeData = getPoiData(marker.options.gid);
            if (!storeData) return;

            const color = getColorCodeAndText(storeData.last_cleaned).colorCode;
            let priorityBonus = (color === 'red') ? 0 : (color === 'gray' ? 10 : null);

            if (priorityBonus !== null) {
                const weightedDistance = userLatLng.distanceTo(marker.getLatLng()) + priorityBonus;
                if (weightedDistance < minWeightedDistance) {
                    minWeightedDistance = weightedDistance;
                    bestCandidate = marker;
                }
            }
        }
    });

    if (bestCandidate) {
        const targetLatLng = bestCandidate.getLatLng();
        
        // 1. UI vorbereiten (BottomSheet öffnen etc.)
        await handleFoundAddressOnGui(
            { targetMarker: bestCandidate, lat: targetLatLng.lat, lng: targetLatLng.lng },
            true,
            dependencies.backendService
        );

        // 2. Karte fokussieren
        // Dieser Schritt löst oft "demarcateRoute" aus, um Altdaten zu löschen
        fitMapToTarget(
            bestCandidate.options.gid,
            targetLatLng,
            null,
            'USER_POS'
        );

        // 3. Routing erst starten, wenn die UI-Events (Lösch-Events) durch sind
        const map = getMap();
        if (map) {
            // Ein kleiner Delay stellt sicher, dass die Route nicht 
            // sofort wieder von den Selektions-Events gelöscht wird.
            setTimeout(() => {
                console.log("DEBUG: Starte Routing-Aufruf (verzögert für UI-Stabilität)...");
                showPedestrianRoute(
                    map,
                    { lat: userPos[0], lng: userPos[1] },
                    { lat: targetLatLng.lat, lng: targetLatLng.lng },
                    dependencies.backendService
                );
            }, 600); // 600ms Puffer für BS-Animation und fitMap-Events
        }
        
        console.log("DEBUG: Navigation zum Stein eingeleitet.");
    } else {
        showToast("Kein Stein mit Pflegebedarf in der Nähe gefunden.", "Info");
    }
}*/
/**
 * Findet die GID des nächsten Steins mit Pflegebedarf (Rot/Grau).
 * @returns {number|null} Die GID des nächsten Kandidaten oder null.
 */
findNextCareNeedGid() {
    const userPos = this.getUserPosition();
    if (!userPos) return null;

    const userLatLng = L.latLng(userPos[0], userPos[1]);
    const markersGroup = getMarkers();
    if (!markersGroup) return null;

    let bestGid = null;
    let minWeightedDistance = Infinity;

    markersGroup.eachLayer(marker => {
        if (marker instanceof L.Marker && marker.options?.gid) {
            const storeData = getPoiData(marker.options.gid);
            if (!storeData) return;

            const color = getColorCodeAndText(storeData.last_cleaned).colorCode;
            
            // Priorisierung: Rot (0m Malus) vor Grau (10m Malus)
            let priorityBonus = (color === 'red') ? 0 : (color === 'gray' ? 10 : null);

            if (priorityBonus !== null) {
                const weightedDistance = userLatLng.distanceTo(marker.getLatLng()) + priorityBonus;
                if (weightedDistance < minWeightedDistance) {
                    minWeightedDistance = weightedDistance;
                    bestGid = marker.options.gid; // Wir speichern nur die GID
                }
            }
        }
    });

    return bestGid;
}

    // --- Controller Methoden ---

    _startWatchPosition(initialPosition) {
        if (this._trackingActive) return;
        this._setTrackingActive(true);
        this._dispatchInitialPosition(initialPosition);

        this._watchId = navigator.geolocation.watchPosition(
            (pos) => this._dispatchNewPosition(pos),
            (err) => this._handleGeolocationError(err),
            { enableHighAccuracy: true, timeout: 10000, maximumAge:0 }
        );
    }

    _stopTracking() {
        if (this._watchId !== null) {
            navigator.geolocation.clearWatch(this._watchId);
            this._watchId = null;
            this._setTrackingActive(false);
            this._lastKnownPosition = null;
        }
    }

    async startTrackingAndHandlePermission() {
        if (!navigator.geolocation) return false;
        try {
            const permissionStatus = await navigator.permissions.query({ name: 'geolocation' });
            if (permissionStatus.state === 'denied') return false;

            return new Promise(resolve => {
                navigator.geolocation.getCurrentPosition(
                    (position) => {
                        this._startWatchPosition(position);
                        resolve(true);
                    },
                    (error) => { resolve(false); },
                    { enableHighAccuracy: true, timeout: 5000 }
                );
            });
        } catch (e) { return false; }
    }
    _handleGeolocationError(error) {
    let message = '';
    let type = 'Fehler';

    switch (error.code) {
        case error.PERMISSION_DENIED:
            message = 'Standortzugriff verweigert.';
            this._stopTracking();
            break;
        case error.POSITION_UNAVAILABLE:
            message = 'Standortinformationen sind aktuell nicht verfügbar.';
            // Wir stoppen nicht, da das WLAN-Signal wiederkommen kann
            break;
        case error.TIMEOUT:
            // WICHTIG: Wenn das Tracking schon läuft, ignorieren wir den Timeout einfach.
            // Der Browser versucht es im nächsten Intervall von watchPosition automatisch neu.
            if (this._trackingActive) {
                mylog("ScUserLocation: Timeout beim Update – ignoriert (Hardware zu langsam).");
                return; // Beendet die Funktion hier, KEIN Toast, KEIN Stoppen!
            }
            message = 'Zeitüberschreitung beim ersten Abrufen.';
            this._stopTracking();
            break;
        default:
            message = `Ein Fehler ist aufgetreten: ${error.message}`;
            this._stopTracking();
            break;
    }
    if (message) showToast(message, type);
}
/*
    _handleGeolocationError(error) {
        this._stopTracking();
        showToast('Standortfehler: ' + error.message, 'Fehler');
    }
        */
}