/* WFW-Aushang PWA
 * - Listet Dateien aus public WebDAV Share
 * - Öffnet PDFs über PDF.js
 * - Install/Update Overlay mit beforeinstallprompt.prompt()
 */

const APP_VERSION = "2025.12.24.8";
const TOKEN = "T9e7WESBXxy6rSD";
const BASE = "https://home.x-s.at";
const SHARE_DAV = `${BASE}/public.php/dav/files/${TOKEN}`;
const PDFJS = `${BASE}/pdfjs/web/viewer.html?file=`;

// relative to /zuss/
const VERSION_URL = "./version.json";
const LIST_START_DIR = "/"; // share root

let deferredInstallPrompt = null;
let latestKnown = APP_VERSION;

const $ = (id) => document.getElementById(id);

function showError(msg) {
  const el = $("err");
  el.style.display = "block";
  el.textContent = msg;
}
function clearError() {
  const el = $("err");
  el.style.display = "none";
  el.textContent = "";
}
function setStatus(msg) { $("status").textContent = msg; }

function showOverlay(title, text, primaryText, showPrimary = true) {
  $("ovTitle").textContent = title;
  $("ovText").textContent = text;
  $("ovPrimaryBtn").textContent = primaryText;
  $("ovPrimaryBtn").style.display = showPrimary ? "flex" : "none";
  $("ovHint").style.display = "none";
  $("installOverlay").style.display = "block";
}
function hideOverlay() {
  $("installOverlay").style.display = "none";
}
function showManualInstallHint() {
  $("ovHint").style.display = "block";
  $("ovHint").textContent =
    "Hinweis: Falls kein Install-Dialog erscheint: Chrome Menü (⋮) → „App installieren“ / „Zum Startbildschirm hinzufügen“.";
}

function compareVersions(a, b) {
  // "2025.12.24.3" style; compare numeric segments
  const pa = String(a).split(".").map(n => parseInt(n, 10) || 0);
  const pb = String(b).split(".").map(n => parseInt(n, 10) || 0);
  const len = Math.max(pa.length, pb.length);
  for (let i = 0; i < len; i++) {
    const da = pa[i] || 0, db = pb[i] || 0;
    if (da > db) return 1;
    if (da < db) return -1;
  }
  return 0;
}

async function fetchLatestVersion() {
  try {
    const r = await fetch(VERSION_URL, { cache: "no-store" });
    if (!r.ok) throw new Error(`version.json HTTP ${r.status}`);
    const j = await r.json();
    if (j && j.version) {
      latestKnown = j.version;
      sessionStorage.setItem("wfw_latest", latestKnown);
    }
  } catch (e) {
    // not fatal
    console.warn("Could not fetch version.json:", e);
  }
}

function getInstalledVersion() {
  return localStorage.getItem("wfw_installed_version") || null;
}
function markInstalledVersion(v) {
  localStorage.setItem("wfw_installed_version", v);
}
function markOverlayDismissed(v) {
  localStorage.setItem("wfw_dismissed_version", v);
}
function getDismissedVersion() {
  return localStorage.getItem("wfw_dismissed_version") || null;
}

async function checkInstallOrUpdateOverlay() {
  await fetchLatestVersion();

  const installed = getInstalledVersion();
  const dismissed = getDismissedVersion();
  const isStandalone = window.matchMedia("(display-mode: standalone)").matches || window.navigator.standalone === true;

  // If installed version < latest -> show update overlay
  if (installed && compareVersions(installed, latestKnown) < 0) {
    showOverlay(
      "Update verfügbar",
      `Neue Version verfügbar (${latestKnown}). Bitte updaten für die neuesten Fixes.`,
      "Update jetzt"
    );
    $("ovPrimaryBtn").onclick = async () => {
      try {
        // ask SW to update + reload
        const reg = await navigator.serviceWorker.getRegistration();
        if (reg) await reg.update();
      } catch {}
      markInstalledVersion(latestKnown);
      location.reload();
    };
    $("ovContinueBtn").onclick = () => {
      markOverlayDismissed(latestKnown);
      hideOverlay();
    };
    return;
  }

  // If not installed (or standalone not detected), show install overlay until latest dismissed/installed
  if (!installed && dismissed !== latestKnown && !isStandalone) {
    showOverlay(
      "WFW-Aushang",
      "Installiere mich!",
      "Installieren"
    );

    $("ovPrimaryBtn").onclick = async (e) => {
      e.preventDefault(); e.stopPropagation();
      await doInstall();
    };
    $("ovContinueBtn").onclick = (e) => {
      e.preventDefault(); e.stopPropagation();
      markOverlayDismissed(latestKnown);
      hideOverlay();
    };
  }
}

async function doInstall() {
  if (!deferredInstallPrompt) {
    showManualInstallHint();
    return;
  }
  try {
    deferredInstallPrompt.prompt(); // <-- IMPORTANT
    const res = await deferredInstallPrompt.userChoice;
    deferredInstallPrompt = null;

    if (res && res.outcome === "accepted") {
      // We'll also set installed version on appinstalled event
      $("ovTitle").textContent = "Installiert ✓";
      $("ovText").textContent = "Danke! Du kannst die App jetzt wie eine normale App starten.";
      markInstalledVersion(latestKnown);
      setTimeout(() => hideOverlay(), 800);
    } else {
      showManualInstallHint();
    }
  } catch (e) {
    console.warn("Install prompt failed:", e);
    showManualInstallHint();
  }
}

/** WebDAV listing **/
async function propfind(dir) {
  const url = `${SHARE_DAV}${dir.endsWith("/") ? dir : dir + "/"}`;
  const body = `<?xml version="1.0" encoding="utf-8"?>
<d:propfind xmlns:d="DAV:">
  <d:prop>
    <d:displayname/>
    <d:getcontenttype/>
    <d:getcontentlength/>
    <d:resourcetype/>
    <d:getlastmodified/>
  </d:prop>
</d:propfind>`;
  const r = await fetch(url, {
    method: "PROPFIND",
    headers: { "Depth": "1", "Content-Type": "application/xml" },
    body
  });
  if (!r.ok) {
    const t = await r.text().catch(()=> "");
    throw new Error(`PROPFIND ${r.status} ${r.statusText}\n${t.slice(0, 400)}`);
  }
  return await r.text();
}

function parseDavMultistatus(xmlText, dir) {
  const p = new DOMParser();
  const xml = p.parseFromString(xmlText, "application/xml");
  const responses = Array.from(xml.getElementsByTagNameNS("DAV:", "response"));

  const items = [];

  for (const resp of responses) {
    const hrefEl = resp.getElementsByTagNameNS("DAV:", "href")[0];
    if (!hrefEl) continue;
    const href = decodeURIComponent(hrefEl.textContent || "");

    // Skip the directory itself (first response)
    const shareRoot = `/public.php/dav/files/${TOKEN}`;
    if (href.endsWith(shareRoot + (dir === "/" ? "/" : dir))) continue;

    const displayEl = resp.getElementsByTagNameNS("DAV:", "displayname")[0];
    const name = displayEl ? (displayEl.textContent || "").trim() : "";

    const rtEl = resp.getElementsByTagNameNS("DAV:", "resourcetype")[0];
    const isCollection = rtEl && rtEl.getElementsByTagNameNS("DAV:", "collection").length > 0;

    const ctEl = resp.getElementsByTagNameNS("DAV:", "getcontenttype")[0];
    const contentType = ctEl ? (ctEl.textContent || "").trim() : "";

    const lmEl = resp.getElementsByTagNameNS("DAV:", "getlastmodified")[0];
    const lastMod = lmEl ? (lmEl.textContent || "").trim() : "";

    items.push({
      href,
      name: name || href.split("/").filter(Boolean).slice(-1)[0] || "",
      isDir: !!isCollection,
      contentType,
      lastMod
    });
  }

  // directories first, then by name
  items.sort((a,b)=> (a.isDir === b.isDir ? a.name.localeCompare(b.name) : (a.isDir ? -1 : 1)));
  return items;
}

function toPdfJsUrl(publicPath) {
  // publicPath must be the share file path relative to share root, starting with "/"
  const fileUrl = `${SHARE_DAV}${publicPath}`; // direct public dav file URL
  return `${PDFJS}${encodeURIComponent(fileUrl)}#zoom=page-width`;
}

function renderList(items, currentDir) {
  const list = $("list");
  list.innerHTML = "";

  // no folder browsing (kiosk): show only PDFs in root+subdirs? you asked "only directory content" of share root.
  // We'll show only currentDir content; no folder nav UI.
  const pdfs = items.filter(it => !it.isDir && (it.name.toLowerCase().endsWith(".pdf") || it.contentType.includes("pdf")));

  if (pdfs.length === 0) {
    setStatus("Keine PDFs gefunden.");
    return;
  }

  setStatus(`PDFs: ${pdfs.length}`);

  for (const it of pdfs) {
    const a = document.createElement("a");
    a.className = "row";
    a.href = "#";
    a.addEventListener("click", (e) => {
      e.preventDefault();

      // Build relative path within share
      // href includes /public.php/dav/files/<token>/...; we want path after that
      const marker = `/public.php/dav/files/${TOKEN}`;
      const idx = it.href.indexOf(marker);
      let rel = "/";
      if (idx >= 0) rel = it.href.slice(idx + marker.length);
      if (!rel.startsWith("/")) rel = "/" + rel;

      window.location.href = toPdfJsUrl(rel);
    });

    const ico = document.createElement("div");
    ico.className = "ico";
    ico.innerHTML = `<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
      <path d="M7 3h7l3 3v15a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z" stroke="currentColor" stroke-width="2" opacity=".9"/>
      <path d="M14 3v4h4" stroke="currentColor" stroke-width="2" opacity=".9"/>
      <path d="M7.5 14.5c2-2.5 3.5-5 4.2-7.5 1.1 3.8 2.8 7 4.8 9.5" stroke="currentColor" stroke-width="2" opacity=".9"/>
    </svg>`;

    const mid = document.createElement("div");
    const nm = document.createElement("div");
    nm.className = "name";
    nm.textContent = it.name;
    const sub = document.createElement("div");
    sub.className = "sub";
    sub.textContent = it.lastMod ? it.lastMod : "";
    mid.appendChild(nm);
    mid.appendChild(sub);

    const badge = document.createElement("div");
    badge.className = "badge";
    badge.textContent = "PDF";

    a.appendChild(ico);
    a.appendChild(mid);
    a.appendChild(document.createElement("div")).className = "spacer";
    a.appendChild(badge);

    list.appendChild(a);
  }
}

async function loadList() {
  clearError();
  setStatus("Lade Liste…");
  try {
    const xml = await propfind(LIST_START_DIR);
    const items = parseDavMultistatus(xml, LIST_START_DIR);
    renderList(items, LIST_START_DIR);
  } catch (e) {
    console.error(e);
    setStatus("Fehler");
    showError(String(e && e.message ? e.message : e));
  }
}

async function registerSW() {
  if (!("serviceWorker" in navigator)) return;
  try {
    const reg = await navigator.serviceWorker.register("./sw.js", { scope: "./" });
    // Trigger update check
    reg.update().catch(()=>{});
  } catch (e) {
    console.warn("SW register failed:", e);
  }
}

function closeAushang(){
  try { window.close(); } catch {}
  // Some browsers block close() once we navigated to pdf.js and back; fallback to back/blank
  setTimeout(() => {
    if (document.visibilityState === "hidden") return; // tab closed or navigating
    const ref = document.referrer || "";
    const cameFromPdf = ref.includes("/pdfjs/");
    if (ref && !cameFromPdf) {
      history.back();
      setTimeout(() => {
        if (document.visibilityState === "hidden") return;
        location.href = "about:blank";
      }, 180);
    } else {
      location.href = "about:blank";
    }
  }, 140);
}

function applyTheme(t){
  document.documentElement.setAttribute("data-theme", t);
  localStorage.setItem("wfw_theme", t);
  $("themeBtn").textContent = t === "dark" ? "🌙 Dunkel" : "☀️ Hell";
}

function initTheme(){
  const saved = localStorage.getItem("wfw_theme");
  if (saved){
    applyTheme(saved);
  } else {
    // Default: System
    const prefersLight = window.matchMedia("(prefers-color-scheme: light)").matches;
    applyTheme(prefersLight ? "light" : "dark");
  }
}


window.addEventListener("appinstalled", () => {
  // user installed the app
  markInstalledVersion(latestKnown);
  markOverlayDismissed(latestKnown);
  hideOverlay();
});

window.addEventListener("beforeinstallprompt", (e) => {
  // We want our own overlay, so we prevent default banner
  e.preventDefault();
  deferredInstallPrompt = e;
  // Show overlay if not yet installed
  checkInstallOrUpdateOverlay();
});

// Extra safety: capture clicks even if something gets weird on mobile
document.addEventListener("click", (e) => {
  const t = e.target;
  if (!t) return;

  if (t.id === "ovContinueBtn") {
    e.preventDefault(); e.stopPropagation();
    markOverlayDismissed(latestKnown);
    hideOverlay();
  }
  if (t.id === "ovPrimaryBtn") {
    // If handler was overwritten, still attempt install/update
    // (doInstall will show manual hint if prompt not available)
  }
}, { capture: true });

document.addEventListener("DOMContentLoaded", async () => {
  $("refreshBtn").addEventListener("click", (e) => { e.preventDefault(); loadList(); });
  $("closeBtn").addEventListener("click", (e) => { e.preventDefault(); closeAushang(); });
  initTheme();
  $("themeBtn").addEventListener("click", () => {
    const current = document.documentElement.getAttribute("data-theme") || "dark";
    applyTheme(current === "dark" ? "light" : "dark");
  }); 
  await registerSW();
  await checkInstallOrUpdateOverlay();
  await loadList();
});
