// backend-poi
// .js
import { getCurrentUser, getCurrentTimestamp, terminateApp } from './utilities.js';

export class BackendService {
    static #instance = null;

    constructor() {
        if (BackendService.#instance) {
            return BackendService.#instance;
        }
        this.baseUrl = this.#getApiBaseUrl();
        BackendService.#instance = this;
    }

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

    #getApiBaseUrl() {
        // Robuste Ermittlung der Base-URL
        return window.location.href.substring(0, window.location.href.lastIndexOf('/'));
    }

    /**
  * Zentraler POST-Mechanismus
  * Erledigt das URL-Management und die Parameter-Weitergabe (Türsteher) automatisch.
  */
    async _post(endpoint, data) {
        // 1. Wir nehmen die aktuellen URL-Parameter der Seite
        const urlParams = new URLSearchParams(window.location.search);

        // 2. Wir bauen die URL sauber zusammen
        // Falls endpoint schon ein "?" hat (manuelle Parameter), hängen wir mit "&" an, sonst mit "?"
        const separator = endpoint.includes('?') ? '&' : '?';
        const finalUrl = `${this.baseUrl}/${endpoint}${urlParams.toString() ? separator + urlParams.toString() : ''}`;

        try {
            const response = await fetch(finalUrl, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(data)
            });

            if (!response.ok) {
                // Versuche Fehlermeldung vom PHP-Türsteher zu lesen
                const errorData = await response.json().catch(() => ({}));
                const msg = errorData.error || errorData.message || `Serverfehler: ${response.status}`;

                // Wenn der Türsteher (400) oder Serverfehler (500) schlägt
                if (response.status === 400) {
                    if (typeof terminateApp === 'function') terminateApp(msg);
                }
                throw new Error(msg);
            }

            return await response.json();
        } catch (error) {
            console.error(`BackendService: Fehler bei POST ${endpoint}:`, error);
            throw error;
        }
    }


    async updateStoneCaretakerStatus(gid, isChecked) {
        const payload = {
            gid: gid,
            caretaker: isChecked ? "anonym" : "",
            username: getCurrentUser()
        };
        return this._post("update_poi_caretaker.php", payload);
    }

async updateStoneDetails(stoneInstance) {
    // Hier wird die Methode direkt aufgerufen, ohne typeof-Sicherheitsgurt:
    const data = stoneInstance.toApiJson(); 
    return this._post("update_poi_details.php", data);
}


    /*
        async updateStoneCleaningStatus(gid, isDirty) {
            const payload = {
                gid: gid,
                username: getCurrentUser(),
                deviceInfo: { os: "macOS", browser: "Web", version: "1.1" }
            };
            const endpoint = isDirty ? "update_poi_dirty.php" : "update_poi_clean.php";
            return this._post(endpoint, payload); // Parameter kommen automatisch via _post
        }*/
    async updateStoneCleaningStatus(gid, timeCode = 0) {
        const payload = {
            gid: gid,
            time_code: timeCode, // 0 = aktuell, 1 = -1m, 2 = -3m, 4 = -12m
            username: getCurrentUser(),
            deviceInfo: { os: "macOS", browser: "Web", version: "1.1" }
        };

        // Wir nutzen jetzt nur noch den zentralen Endpunkt
        const endpoint = "update_poi_cleaning_status.php";

        return this._post(endpoint, payload);
    }
    /**
     * Holt POIs in Chunks (GeoJSON Format)
     * Nutzt _post für automatische URL-Parameter und Fehlerbehandlung.
     */
    async fetchPOIs(startId, endId) {
        const payload = {
            start_id: startId,
            end_id: endId
        };

        try {
            // _post erledigt: URL-Params (?db=...), response.ok Check und terminateApp()
            const result = await this._post("fetch_pois.php", payload);

            return (result && result.type === "FeatureCollection") ? result.features : [];
        } catch (error) {
            // Fehler wurde bereits zentral geloggt/behandelt
            return [];
        }
    }




    // --- Weitere Hilfsmethoden ---

    async fetchPoisByAddress(street, houseNr) {
        // Wir senden nur die 'db'-Info in der URL (erledigt _post automatisch)
        // Die Adresse wandert in den Body (das JSON-Paket)
        const payload = {
            street: street,
            houseNr: houseNr
        };

        try {
            // _post hängt ?db=... an die URL an, 
            // der Türsteher sieht NUR das und lässt dich rein.
            const json = await this._post("fetch_pois_by_address.php", payload);

            return (json.success && Array.isArray(json.data)) ? json.data : [];
        } catch (e) {
            console.error("Fetch Error:", e);
            return [];
        }
    }




    /**
         * Aktualisiert die Adresse und die geografische Position eines POIs.
         * @param {number} gid - Die ID des Stolpersteins.
         * @param {string} street - Der bereinigte Straßenname.
         * @param {string} houseNo - Die Hausnummer.
         * @param {string} district - Der Ortsteil.
         * @param {number} lat - Breitengrad (Latitude).
         * @param {number} lng - Längengrad (Longitude).
         */
    async updatePoiAddress(gid, street, houseNo, district, lat, lng) {
        const payload = {
            gid: gid,
            street: street,
            house_no: houseNo,
            localdistrict: district,
            lat: lat,
            lng: lng,
            username: getCurrentUser() // Falls dein Backend den User trackt
        };

        try {
            const result = await this._post("update_poi_address.php", payload);
            if (result && result.success) {
                return result;
            } else {
                throw new Error(result.error || "Update fehlgeschlagen.");
            }
        } catch (error) {
            console.error("BackendService: Fehler beim Adress-Update:", error);
            throw error;
        }
    }



    /**
     * Holt POI-Daten vom Backend basierend auf dem Namen und Geburtsjahr.
     * Nutzt die zentrale _post-Logik für einheitliche Validierung.
     * * @param {string[]} nameParts Array von Namensbestandteilen.
     * @param {number|null} yearOfBirth Das Geburtsjahr (kann null sein).
     * @returns {Promise<object[]>} Liste von POI-Ergebnissen.
     */
    async fetchPoisByName(nameParts, yearOfBirth) {
        const payload = {
            name_parts: nameParts,
            year_of_birth: yearOfBirth
        };

        try {
            const json = await this._post("fetch_pois_by_name.php", payload);

            if (json && json.success === true && Array.isArray(json.data)) {
                return json.data;
            }

            return [];
        } catch (error) {
            // Fehler wurde bereits in _post geloggt
            return [];
        }
    }
    /**
  * Fügt einen neuen Stolperstein im Backend ein.
  * @param {Poi} stone - Die Poi-Instanz, die eingefügt werden soll.
  * @returns {Promise<object>}
  */
    async insertStone(stone) {
        if (!stone.updated_by) {
            stone.updated_by = getCurrentUser();
            stone.updated_at = getCurrentTimestamp();
        }
        return this._post("insert-poi.php", stone.toApiJson());
    }



    /**
     * POIs laden
     */
    async fetchAllPois(loadingUpdateCallback) {
        const CHUNK_SIZE = 20000;
        let currentStartId = 0;
        let allFeatures = [];

        while (true) {
            if (loadingUpdateCallback) loadingUpdateCallback(`${currentStartId} geladen...`);

            // Nutzt deine bestehende fetchPOIs(start, end) Methode, die nur das Fetch macht
            const dataChunk = await this.fetchPOIs(currentStartId, currentStartId + CHUNK_SIZE);

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

            allFeatures = allFeatures.concat(dataChunk);
            currentStartId += CHUNK_SIZE;
        }
        return allFeatures;
    }

    // user-bezogene   serviceaufrufe

    // --- AUTH & USER SERVICES (EINHEITLICH) ---

    async loginUser(username, password) {
        return this._post("auth.php", { action: 'login', username, password });
    }

    async insertUser(username, password) {
        return this._post("auth.php", { action: 'register', username, password });
    }

    async logoutUser() {
        return this._post("auth.php", { action: 'logout' });
    }

    async checkSession() {
        return this._post("auth.php", { action: 'check' });
    }

    async changePassword(oldPassword, newPassword) {
        // 1. Hole das JSON vom Server
        const result = await this._post("auth.php", {
            action: 'chgPwd',
            oldPassword,
            newPassword
        });

        // 2. WICHTIG: Prüfen, ob die Logik im PHP "Erfolg" sagt
        if (result && result.success === true) {
            return result; // Nur jetzt geht es im UI zum alert("Erfolgreich...")
        } else {
            // 3. Wenn success: false, werfen wir einen Fehler mit der Meldung vom PHP
            throw new Error(result.error || "Passwortänderung fehlgeschlagen.");
        }
    }

    /**
     * Deaktiviert das Konto und anonymisiert alle zugehörigen 
     * Einträge (Logs & Fotos) in einem Rutsch.
     */
    async anonymizeAccount(password) {
        return this._post("auth.php", {
            action: 'anonymize',
            password // Kurzschreibweise für password: password
        });
    }

    /**
     * Exportiert die Nutzerdaten als Textdatei.
     * Nutzt die zentrale _post-Logik für Sicherheit und automatische Parameter.
     */
    async exportUserData(password) {
        const payload = {
            action: 'export',
            password: password
        };

        try {
            // 1. Der zentrale POST-Ruf (erledigt db-Parameter & response.ok Check)
            const result = await this._post("auth.php", payload);

            // 2. Prüfen, ob der Export-Inhalt im JSON steckt
            if (result && result.success && result.exportData) {

                // Blob aus dem Text im JSON-Feld erstellen
                const blob = new Blob([result.exportData], { type: 'text/plain;charset=utf-8' });
                const downloadUrl = window.URL.createObjectURL(blob);

                // Download-Link generieren
                const a = document.createElement('a');
                const timestamp = new Date().toISOString().slice(0, 10);
                const user = localStorage.getItem('currentUser') || 'user';

                // Nutzt den vom Server vorgeschlagenen Filename oder einen Fallback
                a.href = downloadUrl;
                a.download = result.filename || `meine_daten_${user}_${timestamp}.txt`;

                document.body.appendChild(a);
                a.click();

                // Cleanup
                window.URL.revokeObjectURL(downloadUrl);
                a.remove();

                return { success: true };
            } else {
                throw new Error(result.error || "Export-Daten unvollständig.");
            }
        } catch (error) {
            // Fehler wird hier gefangen, falls _post ein reject wirft (z.B. Passwort falsch)
            console.error("Export-Fehler im Frontend:", error.message);
            throw error; // Reiche den Fehler an das UI weiter (z.B. für einen Alert)
        }
    }

    /**
     * Holt die Aktivitäts-Logs (Heute/Monat/Jahr)
     */
    async getLogStats() {
        // Wir senden ein leeres Objekt, da wir nur lesen, aber die _post-Logik nutzen wollen
        return await this._post('get_log_stats.php', {});
    }

    /**
     * Holt die Reinigungs-Statistiken (die 5 Kategorien)
     */
    async getCleaningStats() {
        // Ruft dein neues PHP-Skript auf
        return await this._post('fetch_poi_cleaning_status_stats.php', {});
    }
}
