{% extends "base.html" %}
{% set active_page = "fileshare" %}
{% block page_title %}Dateifreigaben{% endblock %}
{% block page_sub %}<div class="topbar-sub">{{ selected_share }}{% if rel_path %} / {{ rel_path }}{% endif %}</div>{% endblock %}

{% block content %}
{% import "_hint_icon.html" as hi %}

{% macro render_tree_node(share, path, name, expanded_map, active_path) %}
<li class="tree-node" data-share="{{ share }}" data-path="{{ path }}">
  <div class="tree-row{{ ' active' if path == active_path else '' }}">
    {% if path in expanded_map %}
    <button type="button" class="tree-toggle" aria-expanded="true">▼</button>
    {% else %}
    <button type="button" class="tree-toggle" aria-expanded="false">▶</button>
    {% endif %}
    <span class="tree-label">
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:14px; height:14px; margin-right:5px; vertical-align:-2px; color:var(--accent);"><path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z"/></svg>
      {{ name }}
    </span>
  </div>
  <ul class="tree-children{{ '' if path in expanded_map else ' hidden' }}"{% if path in expanded_map %} data-loaded="1"{% endif %}>
    {% if path in expanded_map %}
    {% for child in expanded_map[path] %}
      {{ render_tree_node(share, (path ~ '/' ~ child) if path else child, child, expanded_map, active_path) }}
    {% endfor %}
    {% endif %}
  </ul>
</li>
{% endmacro %}

<div class="section-head">
  <div>
    <h2 style="font-size:16px;">Dateifreigaben</h2>
    <div class="hint">Freigaben je nach AD-Gruppenmitgliedschaft für diese Sitzung gemountet — wird beim Abmelden wieder ausgehängt.</div>
  </div>
</div>

<div class="fileshare-layout">
  <div class="fileshare-tree card">
    <div class="fileshare-tree-title">Freigaben</div>
    <ul class="tree-root" id="fileshareTree">
      {% for s in shares %}
        {{ render_tree_node(s, '', s, tree_expanded if s == selected_share else {}, rel_path if s == selected_share else None) }}
      {% endfor %}
    </ul>
  </div>

  <div class="fileshare-main">
    <div class="table-wrap">
      <div class="table-toolbar">
        <div class="search-input">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg>
          <input type="text" id="fileSearch" placeholder="Datei/Ordner suchen..." oninput="filterTable('fileSearch', 'fileTable')">
        </div>
        <div class="flex gap-2">
          {% if can_create %}
          <button type="button" class="btn btn-secondary btn-sm" data-open-modal="mkdirModal">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z"/><path d="M12 11v4M10 13h4"/></svg>
            Neuer Ordner
          </button>
          <button type="button" class="btn btn-primary btn-sm" data-open-modal="uploadModal">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><path d="M17 8l-5-5-5 5"/><path d="M12 3v12"/></svg>
            Hochladen
          </button>
          {% endif %}
        </div>
      </div>

      <div id="bulkActionsBar" class="flex gap-2 hidden" data-share="{{ selected_share }}" data-path="{{ rel_path }}" style="align-items:center; margin-bottom:10px; flex-wrap:wrap;">
        <span id="bulkSelectedCount" class="text-faint" style="font-size:12.5px; font-weight:600;"></span>
        <button type="button" class="btn btn-secondary btn-sm" onclick="bulkDownload()">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><path d="M7 10l5 5 5-5"/><path d="M12 15V3"/></svg>
          Herunterladen (ZIP)
        </button>
        {% if can_edit %}
        <button type="button" class="btn btn-sm" style="color:var(--danger); background:transparent; border-color:var(--danger-dim);" onclick="bulkDelete()">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2m3 0l-1 14a2 2 0 01-2 2H7a2 2 0 01-2-2L4 6"/></svg>
          Löschen
        </button>
        {% endif %}
      </div>

      {% if entries %}
      <div style="overflow-x:auto;">
      <table class="data-table" id="fileTable" data-sortable>
        <thead><tr>
          <th style="width:1%;"><input type="checkbox" id="selectAllFiles"></th>
          <th data-sort-key="name">Name</th>
          <th data-sort-key="size">Größe</th>
          <th data-sort-key="mtime">Geändert</th>
          <th style="width:1%;">Aktionen</th>
        </tr></thead>
        <tbody>
          {% for e in entries %}
          <tr data-sort-name="{{ e.name|lower }}" data-sort-size="{{ 0 if e.is_dir else e.size_str }}" data-sort-mtime="{{ e.mtime_str }}">
            <td><input type="checkbox" class="row-select" value="{{ e.name }}"></td>
            <td class="cell-name">
              {% if e.is_dir %}
              <a href="{{ url_for('fileshare', share=selected_share, path=(rel_path ~ '/' ~ e.name) if rel_path else e.name) }}">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:15px; height:15px; margin-right:6px; vertical-align:-2px; color:var(--accent);"><path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z"/></svg>
                {{ e.name }}
              </a>
              {% else %}
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:15px; height:15px; margin-right:6px; vertical-align:-2px; color:var(--text-faint);"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><path d="M14 2v6h6"/></svg>
              {{ e.name }}
              {% endif %}
            </td>
            <td class="text-faint">{{ e.size_str }}</td>
            <td class="text-faint">{{ e.mtime_str }}</td>
            <td>
              <div class="row-actions">
                {% if e.preview_kind %}
                <button type="button" class="icon-btn" title="Vorschau"
                        data-preview-kind="{{ e.preview_kind }}"
                        data-preview-name="{{ e.name }}"
                        data-preview-url="{{ url_for('fileshare_view', share=selected_share, path=(rel_path ~ '/' ~ e.name) if rel_path else e.name) }}">
                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
                </button>
                {% endif %}
                {% if not e.is_dir %}
                <a class="icon-btn" title="Herunterladen" href="{{ url_for('fileshare_download', share=selected_share, path=(rel_path ~ '/' ~ e.name) if rel_path else e.name) }}">
                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><path d="M7 10l5 5 5-5"/><path d="M12 15V3"/></svg>
                </a>
                {% endif %}
                {% if can_edit %}
                <button type="button" class="icon-btn" title="Umbenennen" onclick="openRenameModal('{{ e.name|e }}')">
                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
                </button>
                <form method="post" action="{{ url_for('fileshare_delete') }}" data-confirm="„{{ e.name }}“ wirklich endgültig löschen?">
                  <input type="hidden" name="share" value="{{ selected_share }}">
                  <input type="hidden" name="path" value="{{ rel_path }}">
                  <input type="hidden" name="name" value="{{ e.name }}">
                  <button type="submit" class="icon-btn" style="color:var(--danger);" title="Löschen">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2m3 0l-1 14a2 2 0 01-2 2H7a2 2 0 01-2-2L4 6"/></svg>
                  </button>
                </form>
                {% endif %}
              </div>
            </td>
          </tr>
          {% endfor %}
        </tbody>
      </table>
      </div>
      {% else %}
      <div style="padding:40px 16px; text-align:center; color:var(--text-faint);">Dieser Ordner ist leer.</div>
      {% endif %}
    </div>
  </div>
</div>

{% if can_create %}
<div class="modal-overlay" id="uploadModal">
  <div class="modal">
    <form method="post" action="{{ url_for('fileshare_upload') }}" enctype="multipart/form-data">
      <input type="hidden" name="share" value="{{ selected_share }}">
      <input type="hidden" name="path" value="{{ rel_path }}">
      <div class="modal-header">
        <h3>Datei(en) hochladen</h3>
        <button type="button" class="modal-close" data-close-modal>&times;</button>
      </div>
      <div class="modal-body">
        <div class="field">
          <label>Datei(en) {{ hi.hint_icon("Insgesamt maximal 15 MB pro Upload-Vorgang. Mehrfachauswahl möglich (auch mehrmals nacheinander — bereits hinzugefügte Dateien bleiben dabei erhalten).", "Datei(en)") }}</label>
          <input type="file" name="file" id="uploadFileInput" multiple required>
          <div id="uploadFileList" class="upload-file-list"></div>
        </div>
        <div class="field-hint">Wird in „{{ selected_share }}{% if rel_path %} / {{ rel_path }}{% endif %}“ hochgeladen. Eine bereits vorhandene Datei gleichen Namens wird überschrieben.</div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-close-modal>Abbrechen</button>
        <button type="submit" class="btn btn-primary">Hochladen</button>
      </div>
    </form>
  </div>
</div>

<div class="modal-overlay" id="mkdirModal">
  <div class="modal">
    <form method="post" action="{{ url_for('fileshare_mkdir') }}">
      <input type="hidden" name="share" value="{{ selected_share }}">
      <input type="hidden" name="path" value="{{ rel_path }}">
      <div class="modal-header">
        <h3>Neuer Ordner</h3>
        <button type="button" class="modal-close" data-close-modal>&times;</button>
      </div>
      <div class="modal-body">
        <div class="field">
          <label>Ordnername</label>
          <input type="text" name="name" required autofocus>
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-close-modal>Abbrechen</button>
        <button type="submit" class="btn btn-primary">Anlegen</button>
      </div>
    </form>
  </div>
</div>
{% endif %}

{% if can_edit %}
<div class="modal-overlay" id="renameModal">
  <div class="modal">
    <form method="post" action="{{ url_for('fileshare_rename') }}">
      <input type="hidden" name="share" value="{{ selected_share }}">
      <input type="hidden" name="path" value="{{ rel_path }}">
      <input type="hidden" name="old_name" id="renameOldName">
      <div class="modal-header">
        <h3>Umbenennen</h3>
        <button type="button" class="modal-close" data-close-modal>&times;</button>
      </div>
      <div class="modal-body">
        <div class="field">
          <label>Neuer Name</label>
          <input type="text" name="new_name" id="renameNewName" required>
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-close-modal>Abbrechen</button>
        <button type="submit" class="btn btn-primary">Umbenennen</button>
      </div>
    </form>
  </div>
</div>
{% endif %}

<div class="modal-overlay" id="previewModal">
  <div class="modal" style="max-width:900px; width:90vw;">
    <div class="modal-header">
      <h3 id="previewTitle">Vorschau</h3>
      <button type="button" class="modal-close" data-close-modal>&times;</button>
    </div>
    <div class="modal-body" id="previewBody" style="max-height:75vh; overflow:auto;"></div>
  </div>
</div>

{% endblock %}

{% block scripts %}
<script src="{{ url_for('static', filename='js/vendor/mammoth.browser.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/vendor/xlsx.full.min.js') }}"></script>
<script>
const FILESHARE_SUBFOLDERS_URL = "{{ url_for('fileshare_subfolders') }}";
const FILESHARE_BASE_URL = "{{ url_for('fileshare') }}";
const FILESHARE_DOWNLOAD_MULTI_URL = "{{ url_for('fileshare_download_multi') }}";
const FILESHARE_DELETE_MULTI_URL = "{{ url_for('fileshare_delete_multi') }}";

function openRenameModal(name) {
    document.getElementById("renameOldName").value = name;
    document.getElementById("renameNewName").value = name;
    PoeUI.openModal("renameModal");
}

function filterTable(inputId, tableId) {
    const q = document.getElementById(inputId).value.trim().toLowerCase();
    document.querySelectorAll(`#${tableId} tbody tr`).forEach(row => {
        if (row.classList.contains("empty-row")) return;
        row.style.display = row.innerText.toLowerCase().includes(q) ? "" : "none";
    });
}

/* ---------------- Mehrfachauswahl (Herunterladen als ZIP / Löschen) ---------------- */

function getSelectedFileNames() {
    return Array.from(document.querySelectorAll("#fileTable .row-select:checked")).map(function (cb) { return cb.value; });
}

function updateBulkBar() {
    const names = getSelectedFileNames();
    const bar = document.getElementById("bulkActionsBar");
    const countEl = document.getElementById("bulkSelectedCount");
    if (!bar) return;
    if (names.length > 0) {
        bar.classList.remove("hidden");
        countEl.textContent = names.length + " ausgewählt";
    } else {
        bar.classList.add("hidden");
    }
    const selectAll = document.getElementById("selectAllFiles");
    const allBoxes = document.querySelectorAll("#fileTable .row-select");
    if (selectAll && allBoxes.length) {
        selectAll.checked = names.length === allBoxes.length;
        selectAll.indeterminate = names.length > 0 && names.length < allBoxes.length;
    }
}

function submitBulkForm(actionUrl, names) {
    // data-share/data-path statt Jinja-Werte direkt in einen JS-String-
    // Literal zu setzen -- Ordnernamen kommen von der echten Freigabe und
    // koennten Anfuehrungszeichen o.ae. enthalten, ueber HTML-Attribute
    // (von Jinja automatisch escaped) ist das unproblematisch.
    const bar = document.getElementById("bulkActionsBar");
    const form = document.createElement("form");
    form.method = "post";
    form.action = actionUrl;
    form.style.display = "none";
    [["share", bar.dataset.share], ["path", bar.dataset.path]].forEach(function (pair) {
        const input = document.createElement("input");
        input.type = "hidden";
        input.name = pair[0];
        input.value = pair[1];
        form.appendChild(input);
    });
    names.forEach(function (name) {
        const input = document.createElement("input");
        input.type = "hidden";
        input.name = "names";
        input.value = name;
        form.appendChild(input);
    });
    document.body.appendChild(form);
    form.submit();
}

function bulkDownload() {
    const names = getSelectedFileNames();
    if (!names.length) return;
    submitBulkForm(FILESHARE_DOWNLOAD_MULTI_URL, names);
}

function bulkDelete() {
    const names = getSelectedFileNames();
    if (!names.length) return;
    window.confirmAction(
        names.length + " ausgewählte Elemente wirklich endgültig löschen?",
        function () { submitBulkForm(FILESHARE_DELETE_MULTI_URL, names); },
        "Auswahl löschen?"
    );
}

document.addEventListener("DOMContentLoaded", function () {
    const selectAll = document.getElementById("selectAllFiles");
    if (selectAll) {
        selectAll.addEventListener("change", function () {
            document.querySelectorAll("#fileTable .row-select").forEach(function (cb) { cb.checked = selectAll.checked; });
            updateBulkBar();
        });
    }
    document.querySelectorAll("#fileTable .row-select").forEach(function (cb) {
        cb.addEventListener("change", updateBulkBar);
    });
});

/* ---------------- Mehrfach-Upload (Multiauswahl + mehrmals nacheinander) ---------------- */
/* Ein <input type=file multiple> ERSETZT bei jeder erneuten Dateiauswahl
   die vorherige -- fuer "mehrmals nacheinander hinzufuegen" wird deshalb
   selbst eine "angesammelte" Auswahl per DataTransfer gepflegt und nach
   jeder Aenderung zurueck auf das Input-Feld geschrieben, sodass das
   normale <form>-Submit (kein fetch() noetig) am Ende alle gesammelten
   Dateien mitschickt. DataTransfer-Zuweisung an .files wird von allen
   gaengigen Mobil-Browsern (Android Chrome, iOS Safari) mitgetragen; falls
   nicht, faellt es einfach auf das native Verhalten (letzte Auswahl zaehlt)
   zurueck, ohne den Upload an sich zu verhindern. */
(function () {
    const input = document.getElementById("uploadFileInput");
    const listEl = document.getElementById("uploadFileList");
    if (!input || !listEl) return;
    let staged = null;
    try { staged = new DataTransfer(); } catch (e) { staged = null; }

    function render() {
        listEl.innerHTML = "";
        if (!staged) return;
        Array.from(staged.files).forEach(function (file, idx) {
            const row = document.createElement("div");
            row.className = "upload-file-row";
            const name = document.createElement("span");
            name.textContent = file.name;
            const removeBtn = document.createElement("button");
            removeBtn.type = "button";
            removeBtn.className = "upload-file-remove";
            removeBtn.setAttribute("aria-label", "Entfernen");
            removeBtn.textContent = "×";
            removeBtn.addEventListener("click", function () {
                const dt = new DataTransfer();
                Array.from(staged.files).forEach(function (f, i) {
                    if (i !== idx) dt.items.add(f);
                });
                staged = dt;
                input.files = staged.files;
                render();
            });
            row.appendChild(name);
            row.appendChild(removeBtn);
            listEl.appendChild(row);
        });
    }

    input.addEventListener("change", function () {
        if (!staged) return; // kein DataTransfer-Support -- natives Verhalten greift
        Array.from(input.files).forEach(function (file) { staged.items.add(file); });
        input.files = staged.files;
        render();
    });

    // Beim (Wieder-)Oeffnen des Modals eine frische Sammlung starten, statt
    // Dateien aus einem vorherigen, bereits abgeschickten Upload-Vorgang
    // versehentlich mitzuschleppen.
    document.querySelectorAll('[data-open-modal="uploadModal"]').forEach(function (btn) {
        btn.addEventListener("click", function () {
            try { staged = new DataTransfer(); } catch (e) { staged = null; }
            input.value = "";
            render();
        });
    });
})();

/* ---------------- Baum-Navigation (Freigaben links) ---------------- */

function buildTreeNode(share, path, name) {
    const li = document.createElement("li");
    li.className = "tree-node";
    li.dataset.share = share;
    li.dataset.path = path;

    const row = document.createElement("div");
    row.className = "tree-row";

    const toggle = document.createElement("button");
    toggle.type = "button";
    toggle.className = "tree-toggle";
    toggle.textContent = "▶";
    toggle.setAttribute("aria-expanded", "false");

    const label = document.createElement("span");
    label.className = "tree-label";
    label.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:14px;height:14px;margin-right:5px;vertical-align:-2px;color:var(--accent);"><path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z"/></svg>';
    label.append(document.createTextNode(name));

    row.appendChild(toggle);
    row.appendChild(label);

    const childUl = document.createElement("ul");
    childUl.className = "tree-children hidden";

    li.appendChild(row);
    li.appendChild(childUl);
    return li;
}

function toggleTreeNode(btn) {
    const li = btn.closest(".tree-node");
    const childUl = li.querySelector(":scope > .tree-children");
    if (childUl.classList.contains("hidden")) {
        if (childUl.dataset.loaded === "1") {
            childUl.classList.remove("hidden");
            btn.textContent = "▼";
            btn.setAttribute("aria-expanded", "true");
        } else {
            loadTreeChildren(li, childUl, btn);
        }
    } else {
        childUl.classList.add("hidden");
        btn.textContent = "▶";
        btn.setAttribute("aria-expanded", "false");
    }
}

function loadTreeChildren(li, childUl, btn) {
    const share = li.dataset.share;
    const path = li.dataset.path;
    const prevLabel = btn.textContent;
    btn.textContent = "…";
    fetch(FILESHARE_SUBFOLDERS_URL + "?share=" + encodeURIComponent(share) + "&path=" + encodeURIComponent(path))
        .then(r => r.json())
        .then(data => {
            childUl.innerHTML = "";
            (data.folders || []).forEach(name => {
                const childPath = path ? path + "/" + name : name;
                childUl.appendChild(buildTreeNode(share, childPath, name));
            });
            childUl.dataset.loaded = "1";
            childUl.classList.remove("hidden");
            btn.textContent = "▼";
            btn.setAttribute("aria-expanded", "true");
        })
        .catch(() => { btn.textContent = prevLabel; });
}

function navigateTree(share, path) {
    window.location.href = FILESHARE_BASE_URL + "?share=" + encodeURIComponent(share) + "&path=" + encodeURIComponent(path);
}

document.getElementById("fileshareTree").addEventListener("click", function (e) {
    const toggle = e.target.closest(".tree-toggle");
    if (toggle) { toggleTreeNode(toggle); return; }
    const label = e.target.closest(".tree-label");
    if (label) {
        const li = label.closest(".tree-node");
        navigateTree(li.dataset.share, li.dataset.path);
    }
});

/* ---------------- Datei-Vorschau ---------------- */

const fileTableEl = document.getElementById("fileTable");
if (fileTableEl) {
    fileTableEl.addEventListener("click", function (e) {
        const btn = e.target.closest("[data-preview-kind]");
        if (!btn) return;
        openPreview(btn.dataset.previewKind, btn.dataset.previewName, btn.dataset.previewUrl);
    });
}

function openPreview(kind, name, url) {
    document.getElementById("previewTitle").textContent = name;
    const body = document.getElementById("previewBody");
    body.innerHTML = "";
    PoeUI.openModal("previewModal");

    if (kind === "pdf") {
        const iframe = document.createElement("iframe");
        iframe.src = url;
        iframe.style.width = "100%";
        iframe.style.height = "70vh";
        iframe.style.border = "0";
        body.appendChild(iframe);
    } else if (kind === "image") {
        const img = document.createElement("img");
        img.src = url;
        img.alt = name;
        img.style.maxWidth = "100%";
        img.style.display = "block";
        img.style.margin = "0 auto";
        body.appendChild(img);
    } else if (kind === "text") {
        body.textContent = "Lade …";
        // Nur die ersten 512KB anfordern -- bei sehr großen Textdateien
        // (Logs etc.) reicht das für eine Vorschau, ohne alles auf einmal
        // laden zu müssen. Server unterstützt Range ueber send_file(conditional=True).
        fetch(url, { headers: { "Range": "bytes=0-524287" } })
            .then(r => {
                // r.status ist bei einem Range-Request praktisch immer 206,
                // auch wenn die Datei kleiner als die angefragten 512KB ist
                // (der Server liefert dann trotzdem "206" mit der kompletten
                // Datei) -- ob wirklich abgeschnitten wurde, steht nur im
                // Content-Range-Header ("bytes 0-524287/<Gesamtgroesse>").
                const contentRange = r.headers.get("Content-Range") || "";
                const m = contentRange.match(/\/(\d+)$/);
                const truncated = !!m && parseInt(m[1], 10) > 524288;
                return r.text().then(text => ({ text: text, truncated: truncated }));
            })
            .then(({ text, truncated }) => {
                body.innerHTML = "";
                const pre = document.createElement("pre");
                pre.style.whiteSpace = "pre-wrap";
                pre.style.wordBreak = "break-word";
                pre.style.fontSize = "12.5px";
                pre.textContent = text;
                body.appendChild(pre);
                if (truncated) {
                    const hint = document.createElement("div");
                    hint.className = "text-faint";
                    hint.style.marginTop = "10px";
                    hint.style.fontSize = "12px";
                    hint.textContent = "Nur die ersten 512 KB angezeigt — bitte herunterladen für die komplette Datei.";
                    body.appendChild(hint);
                }
            })
            .catch(() => { body.textContent = "Vorschau konnte nicht geladen werden."; });
    } else if (kind === "docx") {
        body.textContent = "Lade …";
        fetch(url).then(r => r.arrayBuffer())
            .then(buf => mammoth.convertToHtml({ arrayBuffer: buf }))
            .then(result => {
                body.innerHTML = "";
                const wrap = document.createElement("div");
                wrap.className = "docx-preview";
                // mammoth erzeugt kontrolliertes HTML aus Words eigenem,
                // begrenztem Formatierungsmodell (Absätze/Tabellen/Listen/
                // Bilder) -- kein beliebiges, aus der Datei uebernommenes
                // Skript kann darin stecken, anders als bei generischem
                // "fremdes HTML direkt einbetten".
                wrap.innerHTML = result.value;
                body.appendChild(wrap);
            })
            .catch(() => { body.textContent = "Vorschau konnte nicht geladen werden (Format evtl. nicht unterstützt)."; });
    } else if (kind === "xlsx") {
        body.textContent = "Lade …";
        fetch(url).then(r => r.arrayBuffer())
            .then(buf => {
                const wb = XLSX.read(buf, { type: "array" });
                body.innerHTML = "";
                wb.SheetNames.forEach(function (sheetName, idx) {
                    const rows = XLSX.utils.sheet_to_json(wb.Sheets[sheetName], { header: 1, defval: "" });
                    const h4 = document.createElement("div");
                    h4.className = "xlsx-preview-sheet-title";
                    h4.textContent = sheetName;
                    body.appendChild(h4);
                    const wrap = document.createElement("div");
                    wrap.style.overflowX = "auto";
                    const table = document.createElement("table");
                    table.className = "data-table";
                    // Zellenwerte bewusst per textContent statt ueber die
                    // eingebaute HTML-Ausgabe von SheetJS gesetzt -- so ist
                    // die Vorschau unabhaengig von deren Escaping-Verhalten
                    // garantiert sicher gegen Inhalte in den Zellen.
                    rows.forEach(function (row) {
                        const tr = document.createElement("tr");
                        row.forEach(function (cell) {
                            const td = document.createElement("td");
                            td.textContent = (cell === null || cell === undefined) ? "" : String(cell);
                            tr.appendChild(td);
                        });
                        table.appendChild(tr);
                    });
                    wrap.appendChild(table);
                    body.appendChild(wrap);
                });
            })
            .catch(() => { body.textContent = "Vorschau konnte nicht geladen werden."; });
    }
}
</script>
{% endblock %}
