/**
 * Die Basis-URL für alle Authentifizierungs-Anfragen.
 * Zentralisiert, damit wir sie bei Server-Umzügen nur an einer Stelle ändern müssen.
 */
const API_BASE_URL = 'https://api-lobby.void-genesis.de/api/auth';

/**
 * Führt den Login-Request an das Backend aus.
 * 
 * @param {string} identifier - Benutzername oder E-Mail-Addresse
 * @param {string} password - Das eingegebene Klartext-Passwort
 * 
 * @returns {Promise<Object>} - Ein Objekt mit 'ok' (boolean) und den 'data' (JSON)
 */
export async function loginUser(identifier, password) {
    try {
        const response = await fetch(`${API_BASE_URL}/login`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ identifier, password })
        });

        const data = await response.json();
        return { ok: response.ok, data };

    } catch (error) {
        console.error("Netzwerkfehler beim Login:", error);
        throw error;
    }
}

/**
 * Führt den Registrierungs-Request an das Backend aus.
 * 
 * @param {string} username - Der gewünschete Benutzername
 * @param {string} email - Die E-Mail-Addresse
 * @param {string} password - Das Klartext-Passwort
 * 
 * @returns {Promise<Object>} - Ein Objekt mit 'ok' (boolean) und den 'data' (JSON)
 */
export async function registerUser(username, email, password) {
    try {
        const response = await fetch(`${API_BASE_URL}/register`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ username, email, password })
        });

        const data = await response.json();
        return { ok: response.ok, data };

    } catch (error) {
        console.error("Netzwerkfehler bei der Registrierung:", error);
        throw error;
    }
}

/**
 * Verifiziert die E-Mail-Addresse mit dem 6-stelligen OTP Code.
 * 
 * @param {string} email - Die E-Mail-Addresse des Nutzers
 * @param {string} otpCode - Der eingegebende 6-stellige Code aus der E-Mail
 * 
 * @returns {Promise<Object>} - Ein Objekt mit 'ok' (boolean) und den 'data' (JSON)
 */
export async function verifyEmailUser(email, otpCode) {
    try {
        const response = await fetch(`${API_BASE_URL}/verify-email`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ email, otpCode })
        });

        const data = await response.json();
        return { ok: response.ok, data };

    } catch (error) {
        console.error("Netzwerkfehler bei der Verifizierung:", error);
        throw error;
    }
}

/**
 * Fordert einen neuen OTP-Code an, falls der alte abgelaufen ist (Resend-Funktion)
 * 
 * @param {string} email - Die E-Mail-Addresse des Nutzers
 * 
 * @returns {Promise<Object>} - Ein Objekt mit 'ok' (boolean) und den 'data' (JSON)
 */
export async function resendOTPCode(email) {
    try {
        console.log ("Email:", email);
        const response = await fetch(`${API_BASE_URL}/resend-otp`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ email })
        });

        const data = await response.json();
        return { ok: response.ok, data };

    } catch (error) {
        console.error("Netzwerkfehler beim erneutem Senden des OTP:", error);
        throw error;
    }
}

/**
 * Leitet den Prozess zum Zurücksetzen des Passworts ein (sendet die Email mit Code).
 * 
 * @param {string} email - Die E-Mail-Addresse des Nutzers
 * 
 * @returns {Promise<Object>} - Ein Objekt mit 'ok' (boolean) und den 'data' (JSON)
 */
export async function requestPasswordResetUser(email) {
    try {
        const response = await fetch(`${API_BASE_URL}/forgot-password`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ email })
        });

        const data = await response.json();
        return { ok: response.ok, data };

    } catch (error) {
        console.error("Netzwerkfehler bei, Passwort-Reset-Anfrage:", error);
        throw error;
    }
}

/**
 * Setzt das Passwort final zurück.
 * 
 * @param {string} email - Die E-Mail-Addresse des Nutzers
 * @param {string} otpCode - Der 6-stellige Code aus der Reset-E-Mail
 * @param {string} newPassword - Das neu gewählte Passwort
 * 
 * @returns {Promise<Object>} - Ein Objekt mit 'ok' (boolean) und den 'data' (JSON)
 */
export async function resetPasswordUser(email, otpCode, newPassword) {
    try {
        const response = await fetch(`${API_BASE_URL}/reset-password`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ email, otpCode, newPassword })
        });

        const data = await response.json();
        return { ok: response.ok, data };

    } catch (error) {
        console.error("Netzwerkfehler bei, Passwort-Reset:", error);
        throw error;
    }
}

/**
 * Nutzt das Refresh-Token, um ein neues Access-Token anzufordern (Auto-Login).
 * 
 * @param {string} refreshToken
 * 
 * @returns {Promise<Object>}
 */
export async function refreshAccessTokenUser(refreshToken) {
    try {
        const response = await fetch(`${API_BASE_URL}/refresh`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ refreshToken })
        });

        const data = await response.json();
        return { ok: response.ok, data };

    } catch (error) {
        console.error("Netzwerkfehler beim Token-Refresh:", error);
        throw error;
    }
}

/**
 * Erzwingt einen Logout, wenn die Sitzung nicht mehr erneuert werden kann.
 * Diese Funktion bereinigt alle Token-Speicherorte analog zum Logout-Button
 * und erzwingt einen Reload, um den Nutzer auf den Login-Bildschirm zu bringen.
 */
function forceLogout() {
    // Falls das Polling läuft, versuchen wir es sicherheitshalber zu stoppen
    if (typeof stopSectorPolling === 'function') {
        stopSectorPolling();
    }
    
    // Berereinigung des SessionStorages von allen anwendungsrelevanten Daten
    sessionStorage.removeItem('void_access_token');
    sessionStorage.removeItem('void_refresh_token');
    sessionStorage.removeItem('void_user');
    
    // Bereinigung des LocalStorages (wichtig für die langlebige Refresh-Variante)
    localStorage.removeItem('void_refresh_token');
    
    // Neuladen der Anwendung, um den unauthentifizierten Zustand zu aktivieren
    window.location.reload();
}

/**
 * Ein globaler Fetch-Wrapper, der automatisch abgelaufene JWT Access Tokens
 * mittels des Refresh-Tokens erneuert und fehlgeschlagene Requests lautlos wiederholt.
 * Ersetzt den nativen 'fetch' bei authentifizierten API-Aufrufen.
 * 
 * @param {string} url - Die Ziel-URL des API-Endpunkts
 * @param {Object} options - Die Fetch-Optionen (Method, Headers, Body etc.)
 * 
 * @returns {Promise<Response>} - Die Fetch-Response des ursprünglichen oder wiederholten Aufrufs
 */
export async function fetchWithAuth(url, options = {}) {
    // 1. Sicherstellen, dass das Options-Objekt existiert und Header-Objekt initialisiert ist
    options.headers = options.headers || {};

    // 2. Das aktuelle Access-Token direkt aus dem sessionStorage holen
    let accessToken = sessionStorage.getItem('void_access_token');

    // 3. Wenn ein Token existiert, fügen wir es automatisch dem Authorization-Header hinzu
    if (accessToken) {
        options.headers['Authorization'] = `Bearer ${accessToken}`;
    }

    try {
        // 4. Den eigentlichen (ersten) Request an das Backend senden
        let response = await fetch(url, options);

        // 5. Prüfen, ob das Backend den Zugriff verweigert (401 Unauthorized -> Token abgelaufen)
        if (response.status === 401) {
            console.warn("Access Token abgelaufen (401). Versuche automatischen Token-Refresh...");

            // 6. Refresh-Token beschaffen (zuerst im sessionStorage, falls nicht da, im localStorage suchen)
            const refreshToken = sessionStorage.getItem('void_refresh_token') || localStorage.getItem('void_refresh_token');

            // Wenn überhaupt kein Refresh-Token existiert, ist kein Auto-Refresh möglich -> Logout
            if (!refreshToken) {
                console.error("Kein Refresh-Token gefunden. Logout wird erzwungen.");
                forceLogout();
                return response;
            }

            // 7. Den Refresh-Endpunkt des Backends aufrufen, um neue Tokens zu generieren
            // Wir nutzen hier direkt die bereits in der auth.js existierende Funktion refreshAccessTokenUser
            const refreshResult = await refreshAccessTokenUser(refreshToken);

            // 8. Prüfen, ob das Backend erfolgreich ein neues Access Token ausgestellt hat
            if (refreshResult.ok && refreshResult.data && refreshResult.data.accessToken) {
                const newAccessToken = refreshResult.data.accessToken;
                
                // Das neue Access Token sofort für zukünftige Requests im sessionStorage sichern
                sessionStorage.setItem('void_access_token', newAccessToken);

                // Falls das Backend auch ein neues Refresh Token mitsendet, speichern wir dieses ebenfalls ab
                if (refreshResult.data.refreshToken) {
                    sessionStorage.setItem('void_refresh_token', refreshResult.data.refreshToken);
                    // Falls es vorher im localStorage war, dort ebenfalls aktualisieren
                    if (localStorage.getItem('void_refresh_token')) {
                        localStorage.setItem('void_refresh_token', refreshResult.data.refreshToken);
                    }
                }

                // 9. Den Authorization-Header der ursprünglichen Anfrage mit dem NEUEN Token aktualisieren
                options.headers['Authorization'] = `Bearer ${newAccessToken}`;

                console.log("Token-Refresh erfolgreich. Wiederhole die ursprüngliche Anfrage lautlos...");
                
                // 10. Den Request lautlos mit dem neuen Token wiederholen und das neue Ergebnis zurückgeben
                return await fetch(url, options);
            } else {
                // Falls der Refresh-Endpunkt fehlschlägt (z.B. Refresh Token auch abgelaufen / ungültig)
                console.error("Refresh-Token ist ungültig oder abgelaufen. Erzwinge Logout.");
                forceLogout();
                return response;
            }
        }

        // Wenn der erste Aufruf erfolgreich war (kein 401), geben wir die Response direkt zurück
        return response;

    } catch (error) {
        // Protokollierung von echten Netzwerkfehlern (z.B. Server Offline, Verbindungsabbruch)
        console.error("Netzwerkfehler im fetchWithAuth Wrapper:", error);
        throw error;
    }
}