// loc-tracking-co.js
import { showToast, mylog } from './sc-utilities.js';
import { getMap, getMarkers, mapState } from './map-markers-co.js';
import { getColorCodeAndText } from './marker-display-utils.js';
import { handleFoundAddressOnGui } from './gui-address-co.js';
import { showPedestrianRoute } from './map-poi-navigation.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;
        }
        console.log("DEBUG: User Position gefunden:", userPos);

        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;

        markersGroup.eachLayer(marker => {
            if (marker instanceof L.Marker && marker.options?.data) {
                const color = getColorCodeAndText(marker.options.data.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) {
            console.log("DEBUG: Nächster Stein gefunden:", bestCandidate.options.data.address);
            
            await handleFoundAddressOnGui(
                dependencies.bottomSheetUI, 
                { targetMarker: bestCandidate, lat: bestCandidate.getLatLng().lat, lng: bestCandidate.getLatLng().lng }, 
                true, 
                dependencies.backendService
            );
            console.log("DEBUG: handleFoundAddressOnGui abgeschlossen");

            const map = getMap();
            if (map) {
                console.log("DEBUG: Starte Routing-Aufruf...");
                showPedestrianRoute(
                    map, 
                    { lat: userPos[0], lng: userPos[1] }, 
                    { lat: bestCandidate.getLatLng().lat, lng: bestCandidate.getLatLng().lng },
                    dependencies.backendService
                );
            } else {
                console.error("DEBUG: Map-Instanz konnte nicht geholt werden!");
            }
            map.setView(bestCandidate.getLatLng(), 18);  // zentrieren
        } else {
            console.log("DEBUG: Kein Stein mit Pflegebedarf gefunden.");
        }
    }

    // --- 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: 13000, 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) {
        this._stopTracking();
        showToast('Standortfehler: ' + error.message, 'Fehler');
    }
}