/**
 * SecNote App Module (secnote-app.js)
 *
 * Hauptlogik der SecNote-Anwendung im Browser. Verwaltet zwei Hauptabläufe:
 *
 * 1. CREATE-FLOW (Erstellen einer Nachricht):
 *    - Benutzer gibt Text ein (optional: Bild, Passwort)
 *    - Text/Bild wird clientseitig mit AES-256-GCM verschlüsselt
 *    - Verschlüsselte Daten werden an den Server gesendet
 *    - Server gibt eine ID zurück, Client hängt den Schlüssel als URL-Fragment an
 *    - Der generierte Link wird dem Benutzer angezeigt
 *
 * 2. VIEW-FLOW (Lesen einer Nachricht):
 *    - Empfänger öffnet den Link mit ID (?id=...) und Schlüssel (#...)
 *    - Verschlüsselte Daten werden vom Server geladen
 *    - Bei Passwort: Passwort-Eingabeformular wird angezeigt
 *    - Daten werden clientseitig entschlüsselt und angezeigt
 *    - Nachricht wird vom Server gelöscht (einmaliges Lesen)
 *
 * Abhängigkeiten:
 * - SecNoteCrypto (secnote-crypto.js): Verschlüsselungsfunktionen
 * - forge (forge.min.js): Kryptographie-Bibliothek
 * - ClipboardJS (clipboard.min.js): Kopieren in Zwischenablage
 * - window.SECNOTE_CONFIG: Serverseitige Konfiguration (CSRF-Token, URL, Messages)
 */
(function() {
    'use strict';

    // Referenz auf das Crypto-Modul und die serverseitige Konfiguration
    var C = SecNoteCrypto;
    var CFG = window.SECNOTE_CONFIG;
    var MSG = CFG.messages;

    // === BROWSER-KOMPATIBILITÄTSPRÜFUNG =========================================
    // Prüft, ob die forge-Bibliothek geladen wurde.
    // Ohne forge ist keine Verschlüsselung möglich.
    if (typeof forge === 'undefined') {
        document.getElementById('haupt').innerHTML =
            '<h3>secnote.eblok.de</h3><p>' + MSG.browser_nicht_unterstuetzt + '</p>';
        return;  // Skript-Ausführung abbrechen
    }

    // === HILFSFUNKTIONEN ========================================================

    /**
     * Escaped einen String für sichere HTML-Ausgabe (XSS-Schutz).
     * Erstellt ein temporäres DOM-Element und nutzt textContent/innerHTML.
     *
     * @param {string} str - Zu escapender String
     * @returns {string} HTML-sicherer String
     */
    function escapeHtml(str) {
        var div = document.createElement('div');
        div.appendChild(document.createTextNode(str));
        return div.innerHTML;
    }

    /**
     * Liest eine Datei (Bild) als ArrayBuffer ein.
     * Wird für den Bild-Upload verwendet, um die Bilddaten als Bytes zu erhalten.
     *
     * @param {File} file - Die zu lesende Datei (aus dem File-Input)
     * @returns {Promise<Uint8Array>} Dateiinhalt als Byte-Array
     */
    function readFileAsArrayBuffer(file) {
        return new Promise(function(resolve, reject) {
            var reader = new FileReader();
            reader.onload = function() { resolve(new Uint8Array(reader.result)); };
            reader.onerror = function() { reject(reader.error); };
            reader.readAsArrayBuffer(file);
        });
    }

    // === CREATE-FLOW (Nachricht erstellen) ======================================

    // Event-Listener auf das Formular setzen (nur wenn es existiert, d.h. auf der Erstellen-Seite)
    var form = document.getElementById('secnote-form');
    if (form) {
        form.addEventListener('submit', function(e) {
            e.preventDefault();  // Standard-Formular-Submit verhindern (wird per AJAX gemacht)
            handleCreate();
        });
    }

    /**
     * Hauptfunktion für den Create-Flow.
     *
     * Ablauf:
     * 1. Formulardaten auslesen und validieren
     * 2. Zufälligen AES-256-Schlüssel generieren
     * 3. Text und/oder Bild clientseitig verschlüsseln
     * 4. Verschlüsselte Daten per AJAX an den Server senden
     * 5. Bei Erfolg: Link mit Schlüssel anzeigen
     */
    async function handleCreate() {
        // DOM-Elemente referenzieren
        var textEl = document.getElementById('secnote-text');       // Textarea
        var bildEl = document.getElementById('secnote-bild');       // Bild-Upload-Input
        var pwEl = document.getElementById('pw');                   // Passwort-Eingabe
        var fehlerEl = document.getElementById('secnote-fehler');   // Fehlversuche-Dropdown
        var submitBtn = document.getElementById('secnote-submit');  // Absende-Button
        var resultDiv = document.getElementById('secnote-result');  // Ergebnis-Container
        var formDiv = document.getElementById('schreiben');         // Formular-Container

        // Formulardaten auslesen
        var text = textEl ? textEl.value : '';
        var password = pwEl ? pwEl.value : '';
        var fehler = fehlerEl ? fehlerEl.value : '0';
        var bildFile = (bildEl && bildEl.files.length > 0) ? bildEl.files[0] : null;

        // --- Validierung ---
        // Mindestens Text oder Bild muss vorhanden sein
        if (text.trim() === '' && !bildFile) {
            alert(MSG.eingabe_leer);
            return;
        }

        // Bildgröße prüfen (max. 5 MB aus Konfiguration)
        if (bildFile && bildFile.size > CFG.maxImageSize) {
            alert(MSG.bild_zu_gross);
            return;
        }

        // --- Formular deaktivieren während der Verarbeitung ---
        submitBtn.disabled = true;
        submitBtn.value = MSG.wird_verschluesselt;  // Button-Text: "Wird verschlüsselt..."
        form.classList.add('secnote-processing');    // Visuelles Feedback: Ausgegraut

        try {
            // --- Schritt 1: Zufälligen AES-256-Schlüssel generieren ---
            var key = await C.generateKey();
            var keyStr = await C.exportKeyToBase64url(key);  // Für URL-Fragment (#)

            // --- Schritt 2: Text verschlüsseln ---
            var encryptedMsg = '';
            if (text.trim() !== '') {
                var textBytes = C.stringToBytes(text);  // UTF-8 Encoding
                var encBytes;
                if (password) {
                    // Doppelte Verschlüsselung: Schlüssel + Passwort
                    encBytes = await C.encryptWithPassword(textBytes, key, password);
                } else {
                    // Einfache Verschlüsselung: Nur mit Schlüssel
                    encBytes = await C.encrypt(textBytes, key);
                }
                encryptedMsg = C.base64Encode(encBytes);  // Als Base64 für Übertragung
            }

            // --- Schritt 3: Bild verschlüsseln (falls vorhanden) ---
            var encryptedImg = '';
            if (bildFile) {
                var imgRaw = await readFileAsArrayBuffer(bildFile);
                // Bild als JSON-Objekt mit MIME-Type verpacken
                var imgPayload = JSON.stringify({
                    mime: bildFile.type,           // z.B. "image/jpeg"
                    data: C.base64Encode(imgRaw)   // Bilddaten als Base64
                });
                var imgBytes = C.stringToBytes(imgPayload);
                var encImgBytes;
                if (password) {
                    encImgBytes = await C.encryptWithPassword(imgBytes, key, password);
                } else {
                    encImgBytes = await C.encrypt(imgBytes, key);
                }
                encryptedImg = C.base64Encode(encImgBytes);
            }

            // --- Schritt 4: Verschlüsselte Daten an den Server senden ---
            var fd = new FormData();
            fd.append('msg', encryptedMsg);                   // Verschlüsselter Text (Base64)
            fd.append('img', encryptedImg);                   // Verschlüsseltes Bild (Base64)
            fd.append('passwort', password ? '1' : '0');      // Passwort-Flag
            fd.append('fehler', fehler);                      // Erlaubte Fehlversuche
            fd.append('csrf_token', CFG.csrfToken);           // CSRF-Schutz

            var resp = await fetch('index.php?cont=api_create', {
                method: 'POST',
                body: fd
            });
            var data = await resp.json();

            // --- Schritt 5: Ergebnis anzeigen ---
            if (data.success) {
                // Vollständigen Link zusammensetzen: Server-URL + Schlüssel als Fragment
                // Wichtig: Das Fragment (#keyStr) wird NICHT an den Server gesendet!
                var fullUrl = data.url + '#' + keyStr;

                // Formular ausblenden, Ergebnis-Container einblenden
                formDiv.style.display = 'none';
                resultDiv.style.display = '';
                document.getElementById('url').textContent = fullUrl;
                document.getElementById('hinweis').innerHTML = MSG.hinweis;

                // Clipboard.js initialisieren (Kopier-Button)
                if (typeof ClipboardJS !== 'undefined') {
                    new ClipboardJS('.btn');
                } else if (typeof Clipboard !== 'undefined') {
                    new Clipboard('.btn');
                }
            } else {
                // Fehler vom Server: Meldung anzeigen und Formular wieder freigeben
                alert(data.error || 'Fehler beim Speichern.');
                submitBtn.disabled = false;
                submitBtn.value = MSG.link_erstellen;
                form.classList.remove('secnote-processing');
            }
        } catch (err) {
            // Clientseitiger Fehler (Verschlüsselung fehlgeschlagen)
            console.error('Encryption error:', err);
            alert(MSG.entschluesselung_fehler);
            submitBtn.disabled = false;
            submitBtn.value = MSG.link_erstellen;
            form.classList.remove('secnote-processing');
        }
    }

    // === VIEW-FLOW (Nachricht lesen) ============================================

    // View-Flow nur starten, wenn der Viewer-Container existiert (d.h. auf der Anzeige-Seite)
    var viewerContainer = document.getElementById('viewer-container');
    if (viewerContainer) {
        handleView();
    }

    /**
     * Hauptfunktion für den View-Flow.
     *
     * Ablauf:
     * 1. Nachrichten-ID und Schlüssel aus der URL extrahieren
     * 2. Verschlüsselte Daten vom Server laden (API-Fetch)
     * 3a. Ohne Passwort: Direkt entschlüsseln und anzeigen
     * 3b. Mit Passwort: Passwort-Formular anzeigen, dann entschlüsseln
     * 4. Nachricht vom Server löschen (einmaliges Lesen)
     */
    async function handleView() {
        // DOM-Referenzen für die verschiedenen Viewer-Bereiche
        var loadingDiv = document.getElementById('viewer-loading');    // Ladeindikator
        var contentDiv = document.getElementById('viewer-content');    // Nachrichteninhalt
        var errorDiv = document.getElementById('viewer-error');        // Fehlermeldungen
        var passwordDiv = document.getElementById('viewer-password');  // Passwort-Eingabe

        // --- Schritt 1: ID und Schlüssel aus der URL extrahieren ---
        var params = new URLSearchParams(window.location.search);
        var id = params.get('id');                        // Nachrichten-ID aus ?id=...
        var hash = window.location.hash.substring(1);     // Schlüssel aus #... (ohne #)

        // Ohne Schlüssel kann nicht entschlüsselt werden
        if (!hash) {
            showError(MSG.schluessel_fehlt);
            return;
        }

        try {
            // --- Schritt 2: Verschlüsselte Daten vom Server laden ---
            var resp = await fetch('index.php?cont=api_fetch&id=' + encodeURIComponent(id));
            var data = await resp.json();

            // Nachricht nicht gefunden (bereits gelöscht oder ungültiger Link)
            if (!data.found) {
                showError(MSG.keine_Nachricht);
                return;
            }

            // Schlüssel aus dem URL-Fragment importieren
            var key = await C.importKeyFromBase64url(hash);

            // --- Schritt 3: Entschlüsselung ---
            if (data.passwort === 1) {
                // 3b: Passwortgeschützte Nachricht -> Passwort-Formular anzeigen
                showPasswordForm(data, key, id);
            } else {
                // 3a: Nicht passwortgeschützt -> Direkt entschlüsseln
                await decryptAndShow(data, key, id, null);
            }
        } catch (err) {
            console.error('View error:', err);
            showError(MSG.entschluesselung_fehler);
        }

        /**
         * Zeigt eine Fehlermeldung im Viewer an.
         * Blendet den Ladeindikator aus und zeigt den Fehler-Container.
         *
         * @param {string} msg - HTML-Fehlermeldung
         */
        function showError(msg) {
            loadingDiv.style.display = 'none';
            errorDiv.style.display = '';
            errorDiv.innerHTML = msg;
        }

        /**
         * Zeigt das Passwort-Eingabeformular an.
         * Wird aufgerufen, wenn die Nachricht passwortgeschützt ist.
         * Enthält:
         * - Hinweistext für den Empfänger
         * - Passwort-Eingabefeld mit Anzeige-Checkbox
         * - Anzeige der verbleibenden Versuche
         * - Submit-Button
         *
         * @param {Object} data - Verschlüsselte Nachrichtendaten vom Server
         * @param {Uint8Array} key - AES-Schlüssel aus der URL
         * @param {string} id - Nachrichten-ID
         */
        function showPasswordForm(data, key, id) {
            loadingDiv.style.display = 'none';
            passwordDiv.style.display = '';

            // Passwort-Formular als HTML zusammensetzen
            passwordDiv.innerHTML =
                '<span id="empfaengerhinweis">' + MSG.empfaengerhinweis + '</span>' +
                '<label for="pw">Passwort</label> ' +
                '<input id="pw" type="password" size="8" />' +
                ' <input id="check" type="checkbox" />' +
                '<label for="check"> ' + MSG.zeigen + '</label><br />' +
                '<span id="passworthinweis">' + MSG.passworthinweisEmpf + '</span><br />' +
                // Verbleibende Versuche anzeigen (nur wenn > 0)
                (data.fehler > 0 ? '<u>' + MSG.versuche_uebrig.replace('{n}', data.fehler) + '</u><br /><br />' : '') +
                '<input type="submit" id="pw-submit" value="' + MSG.zeigen + '" />';

            // Checkbox: Passwort anzeigen/verstecken
            var checkBox = document.getElementById('check');
            var pwInput = document.getElementById('pw');
            checkBox.onclick = function() {
                pwInput.type = this.checked ? 'text' : 'password';
            };

            // Submit-Button: Passwort prüfen und entschlüsseln
            document.getElementById('pw-submit').addEventListener('click', async function() {
                var pw = document.getElementById('pw').value;
                if (!pw) return;  // Leeres Passwort ignorieren

                // Button deaktivieren während der Verarbeitung
                this.disabled = true;
                this.value = MSG.wird_entschluesselt;  // "Wird entschlüsselt..."

                try {
                    // Entschlüsselung versuchen (wirft Fehler bei falschem Passwort)
                    await decryptAndShow(data, key, id, pw);
                } catch (err) {
                    console.error('Decrypt error:', err);

                    // --- Falsches Passwort: Fehlversuch an Server melden ---
                    try {
                        var aResp = await fetch('index.php?cont=api_attempt', {
                            method: 'POST',
                            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                            body: 'id=' + encodeURIComponent(id) + '&csrf_token=' + encodeURIComponent(CFG.csrfToken)
                        });
                        var aData = await aResp.json();

                        if (aData.deleted) {
                            // Keine Versuche mehr -> Nachricht wurde gelöscht
                            passwordDiv.style.display = 'none';
                            showError(MSG.passwort_falsch + '<br />' + MSG.nachricht_geloescht);
                        } else {
                            // Noch Versuche übrig -> Formular aktualisieren
                            document.getElementById('pw-submit').disabled = false;
                            document.getElementById('pw-submit').value = MSG.zeigen;
                            data.fehler = aData.remaining;  // Verbleibende Versuche aktualisieren
                            showPasswordForm(data, key, id);  // Formular neu rendern
                        }
                    } catch (attemptErr) {
                        showError(MSG.entschluesselung_fehler);
                    }
                }
            });
        }

        /**
         * Entschlüsselt die Nachricht und zeigt sie an.
         * Wird sowohl für passwortgeschützte als auch ungeschützte Nachrichten verwendet.
         *
         * Ablauf:
         * 1. Text entschlüsseln (falls vorhanden)
         * 2. Bild entschlüsseln (falls vorhanden)
         * 3. HTML zusammensetzen und anzeigen
         * 4. Nachricht vom Server löschen (einmaliges Lesen)
         *
         * @param {Object} data - Verschlüsselte Daten {msg, img, passwort, fehler}
         * @param {Uint8Array} key - AES-Schlüssel aus der URL
         * @param {string} id - Nachrichten-ID (für Lösch-API)
         * @param {string|null} password - Passwort (null wenn ungeschützt)
         */
        async function decryptAndShow(data, key, id, password) {
            // Lade- und Passwort-Anzeige ausblenden
            loadingDiv.style.display = 'none';
            passwordDiv.style.display = 'none';

            var html = '<h2>Deine Nachricht... </h2>';

            // --- Schritt 1: Text entschlüsseln ---
            if (data.msg && data.msg !== '') {
                var msgBytes = C.base64Decode(data.msg);  // Base64 -> Bytes
                var plainBytes;
                if (password) {
                    // Doppelte Entschlüsselung (Passwort + Schlüssel)
                    plainBytes = await C.decryptWithPassword(msgBytes, key, password);
                } else {
                    // Einfache Entschlüsselung (nur Schlüssel)
                    plainBytes = await C.decrypt(msgBytes, key);
                }
                var plaintext = C.bytesToString(plainBytes);  // Bytes -> UTF-8 String
                // HTML-escaped und Zeilenumbrüche in <br /> umwandeln
                html += escapeHtml(plaintext).replace(/\n/g, '<br />');
            }

            // --- Schritt 2: Bild entschlüsseln ---
            if (data.img && data.img !== '') {
                var imgBytes = C.base64Decode(data.img);
                var imgPlainBytes;
                if (password) {
                    imgPlainBytes = await C.decryptWithPassword(imgBytes, key, password);
                } else {
                    imgPlainBytes = await C.decrypt(imgBytes, key);
                }
                // JSON-Payload parsen: {mime: "image/jpeg", data: "base64..."}
                var imgPayload = JSON.parse(C.bytesToString(imgPlainBytes));
                // Bild als Data-URL in einem <img>-Tag einbetten
                html += '<br /><img src="data:' + escapeHtml(imgPayload.mime) +
                    ';base64,' + imgPayload.data + '" style="max-width:100%;" />';
            }

            // Lösch-Bestätigung und Link zum Erstellen einer eigenen Nachricht
            html += '<br /><br />' + MSG.geloescht;
            html += '<br /><br /><br /><br /><a class="btn-neue-nachricht" href="index.php">' + MSG.selbstNachricht + '</a>';

            // Entschlüsselten Inhalt anzeigen
            contentDiv.innerHTML = html;
            contentDiv.style.display = '';

            // --- Schritt 3: Nachricht vom Server löschen ---
            // Die Nachricht wird nach dem Anzeigen unwiderruflich gelöscht
            // (Kernprinzip: Jede Nachricht kann nur einmal gelesen werden)
            try {
                await fetch('index.php?cont=api_delete', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                    body: 'id=' + encodeURIComponent(id) + '&csrf_token=' + encodeURIComponent(CFG.csrfToken)
                });
            } catch (delErr) {
                // Fehler beim Löschen nur loggen, Nachricht wurde dem Benutzer bereits angezeigt
                console.error('Delete error:', delErr);
            }
        }
    }
})();
