import { ScStone } from './ScStone.js';
import { showToast, is_development } from './sc-utilities.js';
import { updateSearchFieldWithAddress } from './app-shell-co.js';
import { getColorCodeAndText } from './marker-display-utils.js';
import { UpdateMarkerIcon, isMarkerHighlighted } from './map-poi-mgr.js';
import { createUpdateClickHandler } from './update-poi-details-co.js';
import { attachSwipeListeners, detachClusterBsListener } from './bs-cluster-co.js';
import { LocationTrackingCoordinator } from './loc-tracking-co.js';; // ⬅️ NEU: Import für das Singleton

// **WICHTIG:** Hier sind die Funktionen für die Sprachausgabe
// Sie müssen hier in DIESER Datei definiert sein, nicht importiert werden.

// Variable, um den Zustand der Sprachausgabe zu verfolgen.1
let isSpeaking = false;
let poiReadButtonHandler = null;

// Funktion zum Abbrechen der Sprachausgabe von überall im Code
function cancelSpeech() {
    isSpeaking = false;
    window.speechSynthesis.cancel();
}

// Funktion, die den Text aus der API abruft
async function getBiographyText(url) {
    try {
        const response = await fetch(url);
        if (!response.ok) {
            throw new Error(`Netzwerk-Antwort war nicht ok: ${response.statusText}`);
        }
        const htmlText = await response.text();
        const parser = new DOMParser();
        const doc = parser.parseFromString(htmlText, 'text/html');
        const contentContainer = doc.querySelector('.biography-text .field__item');
        if (contentContainer) {
            return contentContainer.textContent.trim();
        } else {
            console.error('FEHLER: Biografie-Container nicht gefunden. Überprüfe den HTML-Selektor.');
            return 'Entschuldigung, die Biografie konnte nicht geladen werden.';
        }
    } catch (error) {
        console.error('Fehler beim Abrufen oder Verarbeiten der Biografie:', error);
        return 'Entschuldigung, die Biografie konnte nicht geladen werden.';
    }
}

// Funktion, die einen langen Text in Chunks vorliest
async function speakChunks(text, lang) {
    if (isSpeaking) {
        return;
    }
    isSpeaking = true;
    const sentences = text.split(/(?<=[.?!;])\s*/);

    for (const sentence of sentences) {
        if (!isSpeaking) break;
        if (sentence.trim() === '') continue;

        await new Promise(resolve => {
            const utterance = new SpeechSynthesisUtterance(sentence.trim());
            utterance.lang = lang;

            utterance.onerror = function (event) {
                console.error('Sprachfehler im Chunk:', event.error);
                resolve();
            };

            utterance.onend = function () {
                resolve();
            };

            window.speechSynthesis.speak(utterance);
        });
    }
    isSpeaking = false;
}

/**
 * Die Hauptfunktion, die das Bottom Sheet aktualisiert.
 * @param {L.Marker} clickedMarker
 * @param {BsUI} bottomSheetUI
 * @param {BackendService} backendService
 * @param {Object} mapState
 * @param {function(): boolean} getAdminModeStatus
 * @param {L.MarkerClusterGroup} markers
 * @param {L.Map} map
 * @param {InsertPoiUI} addButtonUIInstance
 * @param {UpdatePoiUI} updatePoiUIInstance
 */
export function updateBsForPoi(
    clickedMarker,
    bottomSheetUI,
    backendService,
    mapState,
    getAdminModeStatus,
    markers,
    map,
    addButtonUIInstance,
    updatePoiUIInstance
) {
    // 1. Controller-spezifische Listener entfernen.
    detachClusterBsListener(bottomSheetUI);
    detachPoiButtonListeners(bottomSheetUI);

    console.log("DEBUG: --- updateBsForPoi START ---");
    cancelSpeech();

    if (!bottomSheetUI || !clickedMarker || !clickedMarker.options || !clickedMarker.options.data) {
        console.error("FEHLER: Ungültige Objekte oder Daten im Marker-Klick-Handler. Breche ab.");
        showToast("Fehler: Marker-Daten unvollständig.");
        return;
    }

    const gidValue = clickedMarker.options.data.gid;
    const scStoneInstance = new ScStone({ gid: gidValue }, backendService);


    const { contentHtml, options } = getBottomSheetDataAndActions(clickedMarker, getAdminModeStatus);

    // Header setzen (inkl. Pfeil)
    bottomSheetUI.setBsHeaderText(`${clickedMarker.options.data.first_name || ''} ${clickedMarker.options.data.last_name || ''} ↗`);

    bottomSheetUI.setContent(contentHtml);
    bottomSheetUI.setActions(options); // Setzt nun die korrekten showMainActionDiv / showFallbackButton-Werte

    // Suchfeld-Aktualisierung
    const locationText = `${clickedMarker.options.data.street || ''} ${clickedMarker.options.data.house_no || ''}`;
    updateSearchFieldWithAddress(locationText);

    // Koordinaten für Aktionen setzen
    const latToUse = clickedMarker.getLatLng().lat;
    const lngToUse = clickedMarker.getLatLng().lng;
    bottomSheetUI.setCoords({ lat: latToUse, lng: lngToUse });

    // Open/Nav-Pfeil Logik
    const parentCluster = mapState.currentlySpiderfiedCluster;
    /*
    
     */
    if (parentCluster) {
        bottomSheetUI.setNavButtonsState(true, true);
        // alle Parameter in einem Objekt bündeln
        const allParams = {
            bottomSheetUI,
            markers,
            map,
            backendService,
            getAdminModeStatus,
   //         locTrackingCoordinator: LocationTrackingCoordinator.getInstance(), // ⬅️ Singleton-Instanz hier abrufen
            mapState,
            addButtonUIInstance,
            updatePoiUIInstance
        };
        attachSwipeListeners(bottomSheetUI, parentCluster, allParams);
    } else {
        bottomSheetUI.setNavButtonsState(false, false);
    }

    bottomSheetUI.openWithMarker(clickedMarker);

    attachActionListeners(
        bottomSheetUI,
        markers,
        clickedMarker,
        map,
        scStoneInstance,
        getAdminModeStatus,
        addButtonUIInstance,
        updatePoiUIInstance,
        backendService,
        mapState
    );
    console.log("DEBUG: --- updateBsForPoi END ---");
}


/**
 * Hängt Event-Listener an die Aktionen im Bottom-Sheet an und steuert die Sichtbarkeit der Buttons.
 * @param {BsUI} bottomSheetUI
 * @param {L.MarkerClusterGroup} clusterGroup
 * @param {L.Marker} marker
 * @param {L.Map} map
 * @param {ScStone} scStoneInstance
 * @param {function(): boolean} getAdminModeStatus
 * @param {InsertPoiUI} addButtonUIInstance
 * @param {UpdatePoiUI} updatePoiUIInstance
 * @param {BackendService} backendService
 * @param {Object} mapState
 */
function attachActionListeners(
    bottomSheetUI, clusterGroup, marker, map, scStoneInstance, getAdminModeStatus,
    addButtonUIInstance, updatePoiUIInstance, backendService, mapState) { 

    console.debug('DEBUG: attachActionListeners: Starte Listener-Attachement für POI.');

    // --- Referenzen zu den Buttons abrufen ---
    const poiCleanButton = bottomSheetUI._poiCleanButton;
    const poiDirtyButton = bottomSheetUI._poiDirtyButton;
    const fallbackButton = bottomSheetUI._fallbackButton;


    const { options } = getBottomSheetDataAndActions(marker, getAdminModeStatus);

    // ***************************************************************
    // ✨ KRITISCHE KORREKTUR: Sichtbarkeit der spezifischen Buttons
    // ***************************************************************

    // 1. Fallback Button (Zu weit entfernt)
    if (options.showFallbackButton && fallbackButton) {
        fallbackButton.classList.remove('hidden');
        fallbackButton.textContent = options.fallbackButtonText;

        // Handler für den Fallback-Button ("Zu weit entfernt")
        const fallbackClickHandler = function () {
            showToast("Bitte nähere dich dem Stolperstein, um ihn zu markieren.");
        };
        fallbackButton.addEventListener('click', fallbackClickHandler);
        fallbackButton._fallbackButtonListener = fallbackClickHandler;
    }

    // 2. POI Clean/Dirty Buttons (Nur wenn ShowActiveState/isNearby ODER Admin Mode aktiv)
    else if (options.showMainActionDiv) {
        if (options.showPoiCleanButton && poiCleanButton) {
            // Zeige Clean Button (wenn Marker als Dirty markiert ist)
            poiCleanButton.classList.remove('hidden');
            poiCleanButton.textContent = "Der Zustand ist gut";

            // Handler für "Ist sauber" Button (Clean)
            const cleanClickHandler = createCleanClickHandler(clusterGroup, marker, mapState, scStoneInstance);
            poiCleanButton.addEventListener('click', cleanClickHandler);
            poiCleanButton._cleanButtonListener = cleanClickHandler;
        }

        if (options.showPoiDirtyButton && poiDirtyButton) {
            // Zeige Dirty Button (wenn Marker als Clean markiert ist)
            poiDirtyButton.classList.remove('hidden');
            poiDirtyButton.textContent = "Der Zustand ist schlecht";

            // Handler für "Ist schmutzig" Button (Dirty)
            const dirtyClickHandler = createDirtyClickHandler(clusterGroup, marker, mapState, scStoneInstance);
            poiDirtyButton.addEventListener('click', dirtyClickHandler);
            poiDirtyButton._dirtyButtonListener = dirtyClickHandler;
        }
    }

    // ***************************************************************
    // Ende der Korrektur für die Sichtbarkeit
    // ***************************************************************


    // --- TTS (Read) Button Logik ---
    // ✅ LÖSUNG: Den globalen Body-Listener nur einmal registrieren und die Referenz speichern!
    if (!poiReadButtonHandler) {
        // Annahme: poiReadButtonHandler und handleReadButtonClick sind außerhalb dieses Scopes definiert
        poiReadButtonHandler = handleReadButtonClick;
        document.body.addEventListener('click', poiReadButtonHandler);
        console.log("DEBUG: TTS-Body-Listener einmalig ATTACHED.");
    }

    // --- Caretaker Checkbox ---
    const caretakerCheckbox = bottomSheetUI._caretakerCheckbox;
    if (caretakerCheckbox) {
        const handleCaretakerChange = async function () {
            const gid = parseInt(marker.options.data.gid, 10);
            const isChecked = this.checked;
            if (isNaN(gid)) {
                console.error("Fehler: GID des Markers ist keine gültige Zahl.");
                return;
            }
            // Annahme: handleCaretakerCheckboxChange ist außerhalb dieses Scopes definiert
            await handleCaretakerCheckboxChange(marker, mapState, isChecked, scStoneInstance);
        };
        caretakerCheckbox.addEventListener('change', handleCaretakerChange);
        caretakerCheckbox._caretakerChangeListener = handleCaretakerChange;
    }

    // --- Edit Button ---
    const editButton = bottomSheetUI.editButton;
    if (editButton) {
        const handleEditClick = function (event) {
            event.stopPropagation();

            // Annahme: createUpdateClickHandler ist außerhalb dieses Scopes definiert
            createUpdateClickHandler(
                bottomSheetUI,
                marker,
                backendService,
                mapState,
                getAdminModeStatus,
                clusterGroup,
                map,
                addButtonUIInstance,
                updatePoiUIInstance
            )(); // <-- Wichtig: Sofort ausführen, da createUpdateClickHandler eine Closure zurückgibt
        };

        editButton.addEventListener('click', handleEditClick);
        editButton._editButtonListener = handleEditClick;
    }
    console.debug('DEBUG: attachActionListeners: Listener-Attachement für POI abgeschlossen.');
}

/**
 * Erstellt die aufbereiteten Daten für das Bottom Sheet und die Aktionen.
 * @param {L.Marker} marker
 * @param {function(): boolean} getAdminModeStatus
 * @returns {{contentHtml: string, options: Object}}
 */
function getBottomSheetDataAndActions(marker, getAdminModeStatus) { 
    const props = marker.options.data;
    const latlng = marker.getLatLng();
    const coords = latlng ? [latlng.lat, latlng.lng] : null;

    let isCaretaker = props.caretaker !== "" && props.caretaker !== null;
    let caretakerStatus = props.caretaker || "";
    let isCaretakerAnonym = caretakerStatus === "anonym";

    // 🚨 Abrufen der Singleton-Instanz
    const locTrackingCoordinator = LocationTrackingCoordinator.getInstance();;
    const currentUserPosition = locTrackingCoordinator.getUserPosition();
    let isNearby = false;
    if (currentUserPosition && coords) {
        // Annahme: L ist in diesem Scope verfügbar
        const distance = L.latLng(currentUserPosition).distanceTo(L.latLng(coords[0], coords[1]));
        isNearby = (distance <= 99);
    }

    const isAdmin = getAdminModeStatus();
    const showActiveState = isNearby || isAdmin; // Zeigt Clean/Dirty/Caretaker an
    const showFallback = !isNearby && !isAdmin; // Zeigt Fallback an

    // NEU: Status des POI (brauchen wir, um zu entscheiden, ob Clean ODER Dirty Button angezeigt werden soll)
    const isClean = !props.needs_cleaning;

    const options = {
        showCaretaker: showActiveState,
        isCaretaker: isCaretaker,
        caretakerLabelText: 'Putzpatenschaft', // das wird angezeigt!!

        // Haupt-Aktions-Container (wird in BsUI.js sichtbar gemacht)
        showMainActionDiv: showActiveState,

        // Fallback Button
        showFallbackButton: showFallback,
        fallbackButtonText: "Adresse aufsuchen, um den Zustand zu erfassen",
        fallbackButtonClass: "primary disabled",

        // ✨ KRITISCHE KORREKTUR: Hinzufügen der spezifischen Button-Flags!
        // Wir zeigen den Clean Button, wenn der Stein NICHT sauber (d.h. schmutzig) ist, 
        // und den Dirty Button, wenn er sauber ist (um Status zu ändern).
        showPoiCleanButton: showActiveState, // && !isClean,  // Zeige Clean, wenn needs_cleaning=true
        showPoiDirtyButton: showActiveState, // && isClean,   // Zeige Dirty, wenn needs_cleaning=false

        // Admin/Edit-Buttons
        showAddButton: isAdmin || isNearby,
        showEditButton: isAdmin|| isNearby,
    };

    if (isCaretaker && !isCaretakerAnonym) {
        options.caretakerLabelText = `Putzpatenschaft--`;
    }

    return {
        contentHtml: getPOIContentHtml(marker),
        options: options
    };
}

/**
 * Erstellt einen Klick-Handler für den "Ist sauber" Button.
 * @param {L.MarkerClusterGroup} clusterGroup
 * @param {L.Marker} marker
 * @param {Object} mapState
 * @param {ScStone} scStoneInstance
 * @returns {Function} Der asynchrone Klick-Handler.
 */
export function createCleanClickHandler(clusterGroup, marker, mapState, scStoneInstance) {
    return async function () {
        const poiId = parseInt(marker.options.data.gid, 10);
        if (isNaN(poiId)) {
            showToast("Fehler: Stolperstein-ID ungültig.");
            return;
        }
        try {
            // false = needs_cleaning = false (ist sauber)
            const result = await scStoneInstance.updateCleaningStatus(false);
            if (result.success && result.last_cleaned) {
                // LOKALE DATEN AKTUALISIEREN
                marker.options.data.last_cleaned = result.last_cleaned;
                marker.options.data.needs_cleaning = false;
                UpdateMarkerIcon(
                    marker,
                    isMarkerHighlighted(marker.options.data.gid, mapState));
                clusterGroup.refreshClusters();
                showToast("Zustand als gut markiert ✅");
            } else {
                showToast("Fehler", `Fehler beim Aktualisieren des Status: ${result.error || 'Backend hat kein Datum zurückgegeben.'}`);
            }
        } catch (error) {
            console.error("Fehler beim Senden der Statusaktualisierung:", error);
            showToast("Fehler", "Fehler beim Senden der Statusaktualisierung.");
        }
    };
}

/**
 * Erstellt einen Klick-Handler für das Markieren eines Stolpersteins als 'schmutzig'.
 * @param {L.MarkerClusterGroup} clusterGroup
 * @param {L.Marker} marker
 * @param {Object} mapState
 * @param {ScStone} scStoneInstance
 * @returns {Function} Der asynchrone Klick-Handler.
 */
export function createDirtyClickHandler(clusterGroup, marker, mapState, scStoneInstance) {
    return async function () {
        const poiId = parseInt(marker.options.data.gid, 10);
        if (isNaN(poiId)) {
            showToast("Fehler: Stolperstein-ID ungültig.");
            return;
        }

        try {
            // true = needs_cleaning = true (ist schmutzig)
            const result = await scStoneInstance.updateCleaningStatus(true);
            if (result.success && result.last_cleaned) {
                // LOKALE DATEN AKTUALISIEREN
                marker.options.data.last_cleaned = result.last_cleaned;
                marker.options.data.needs_cleaning = true;
                UpdateMarkerIcon(
                    marker,
                    isMarkerHighlighted(marker.options.data.gid, mapState));
                clusterGroup.refreshClusters();
                showToast("Zustand als schlecht markiert 🔴");
            } else {
                showToast("Fehler", `Fehler beim Aktualisieren des Status auf 'ungesäubert': ${result.error || 'Backend hat kein Datum zurückgegeben.'}`);
            }
        } catch (error) {
            console.error("Fehler beim Senden der Dirty-Statusaktualisierung:", error);
            showToast("Fehler", "Fehler beim Senden der Dirty-Statusaktualisierung.");
        }
    };
}


/**
 * Verwaltet die Business-Logik für die Putzpatenschafts-Checkbox.
 */
async function handleCaretakerCheckboxChange(marker, mapState, isChecked, scStoneInstance) {
    const action = isChecked ? 'set' : 'remove';
    try {
        const result = await scStoneInstance.updateCaretakerStatus(action);
        if (result.success) {
            marker.options.data.caretaker = isChecked ? 'anonym' : '';
            UpdateMarkerIcon(
                marker,
                isMarkerHighlighted(marker.options.data.gid, mapState));
            showToast(`Putzpatenschaft ${isChecked ? 'gesetzt' : 'entfernt'}!`);
        } else {
            showToast("Fehler", `Fehler beim Aktualisieren der Patenschaft: ${result.error || 'Unbekannter Fehler.'}`);
        }
    } catch (error) {
        console.error("Fehler beim Senden der Patenschaftsaktualisierung:", error);
        showToast("Fehler", "Fehler beim Senden der Patenschaftsaktualisierung.");
    }
}

function getPOIContentHtml(marker) {
    let ContentHtml = `<div class="POI-details">`;
    const data = marker.options.data;
    const color = getColorCodeAndText(data.last_cleaned).colorCode;

    function formatLastCleanedDate(dateString) {
        if (!dateString) {
            return '\?';
        }
        const date = new Date(dateString);
        const options = {
            day: '2-digit',
            month: '2-digit',
            year: 'numeric'
        };
        return date.toLocaleDateString('de-DE', options);
    }

    const formattedDate = formatLastCleanedDate(data.last_cleaned);
    const biographyUrl = data.url_kodb;
    const streetModified = data.street.slice(0, -1) + '*';
    const positionModified = data.stone_position ? '<br>Verlegeort: ' + data.stone_position : ''

    const wikipediaSearchTerms = [
        'Stolperstein',
        data.first_name,
        data.last_name,
        data.year_of_birth,
        streetModified
    ];
    const wikipediaUrl = `https://de.wikipedia.org/wiki/Spezial:Suche?search=${wikipediaSearchTerms.map(term => encodeURIComponent(term)).join('+')}`;

    ContentHtml += `
    <div class="poi-list-item ${color}-marker">
        <p>geboren ${data.year_of_birth}
        ${positionModified}
        <br>Reinigung: ${formattedDate}
        <br><a href="${biographyUrl}" target="_blank">Biographie</a>
        <button class="read-biography-btn" data-url="${biographyUrl}" style="cursor: pointer; background: none; border: none; padding: 0; color: #1e40af;">
            <i class="fas fa-volume-up"></i> Hören
        </button>
        <br><a href="${wikipediaUrl}" target="_blank">Wikipedia</a>
        <br>GID: ${data.gid}
    </div>
    `;
    return ContentHtml;
}



async function handleReadButtonClick(event) {
    const button = event.target.closest('.read-biography-btn');
    if (!button) {
        return;
    }

    cancelSpeech();
    window.speechSynthesis.speak(new SpeechSynthesisUtterance(""));

    if (!('speechSynthesis' in window)) {
        alert("Entschuldigung, die Sprachausgabe wird von Ihrem Browser nicht unterstützt.");
        return;
    }

    const biographyUrl = button.dataset.url;

    try {
        const text = await getBiographyText(biographyUrl);
        const cleanedText = text.replace(/<[^>]*>?/gm, '');

        const voices = window.speechSynthesis.getVoices();
        const availableLanguages = [...new Set(voices.map(voice => voice.lang))];
        const germanVoices = voices.filter(voice => voice.lang.includes('de'));

        if (germanVoices.length === 0) {
            alert(`Entschuldigung, die deutsche Sprachausgabe ist auf Ihrem Gerät nicht verfügbar. Verfügbare Sprachen: ${availableLanguages.join(', ')}`);
            return;
        }

        await speakChunks(cleanedText, 'de-DE');

    } catch (error) {
        console.error("Fehler beim Laden der Biografie:", error);
        alert('Ein Fehler ist aufgetreten: Die Biografie konnte nicht geladen werden.');
    }
}

// NEU: Logik zum Entfernen der POI-Listener von Aktionen
export function detachPoiButtonListeners(bottomSheetUI) {
    // Entfernen der Clean Button Listener
    const poiCleanButton = bottomSheetUI._poiCleanButton;
    if (poiCleanButton && poiCleanButton._cleanButtonListener) {
        poiCleanButton.removeEventListener('click', poiCleanButton._cleanButtonListener);
        delete poiCleanButton._cleanButtonListener;
        console.log("DEBUG: POI Clean Button Listener detached.");
    }

    // Entfernen der Dirty Button Listener
    const poiDirtyButton = bottomSheetUI._poiDirtyButton;
    if (poiDirtyButton && poiDirtyButton._dirtyButtonListener) {
        poiDirtyButton.removeEventListener('click', poiDirtyButton._dirtyButtonListener);
        delete poiDirtyButton._dirtyButtonListener;
        console.log("DEBUG: POI Dirty Button Listener detached.");
    }

    // Entfernen der Fallback Button Listener
    const fallbackButton = bottomSheetUI._fallbackButton;
    if (fallbackButton && fallbackButton._fallbackButtonListener) {
        fallbackButton.removeEventListener('click', fallbackButton._fallbackButtonListener);
        delete fallbackButton._fallbackButtonListener;
        console.log("DEBUG: Fallback Button Listener detached.");
    }

    // Entfernen der Caretaker Checkbox Listener
    const caretakerCheckbox = bottomSheetUI._caretakerCheckbox;
    if (caretakerCheckbox && caretakerCheckbox._caretakerChangeListener) {
        caretakerCheckbox.removeEventListener('change', caretakerCheckbox._caretakerChangeListener);
        delete caretakerCheckbox._caretakerChangeListener;
        console.log("DEBUG: Caretaker Checkbox Listener detached.");
    }

    // Entfernen des Edit Button Listeners
    const editButton = bottomSheetUI.editButton;
    if (editButton && editButton._editButtonListener) {
        editButton.removeEventListener('click', editButton._editButtonListener);
        delete editButton._editButtonListener;
        console.log("DEBUG: Edit Button Listener detached.");
    }

    // Der globale TTS-Body-Listener (poiReadButtonHandler) bleibt bewusst erhalten, 
    // da er einmalig für das gesamte Dokument gesetzt wird.
}