// MedLink — lightweight in-session store.
// Keeps the existing window.ANFRAGEN / TRAIL arrays mutable in place.
// Bumps a version counter that subscribed components listen to for re-renders.
// Actions dispatch toasts + notifications so the whole app feels alive.

(function () {
  const now = () => {
    const d = new Date();
    const dd = String(d.getDate()).padStart(2, "0");
    const mm = String(d.getMonth() + 1).padStart(2, "0");
    const hh = String(d.getHours()).padStart(2, "0");
    const mi = String(d.getMinutes()).padStart(2, "0");
    return `${dd}.${mm}.${d.getFullYear()} · ${hh}:${mi}`;
  };

  // ---------- Offline-Mutations-Queue ----------
  const QUEUE_KEY = "medlink.offline.queue";
  const readQueue = () => {
    try { return JSON.parse(localStorage.getItem(QUEUE_KEY) || "[]"); }
    catch { return []; }
  };
  const writeQueue = (q) => {
    try { localStorage.setItem(QUEUE_KEY, JSON.stringify(q)); } catch {}
  };
  const enqueue = (action, args) => {
    const q = readQueue();
    q.push({ action, args, ts: Date.now() });
    writeQueue(q);
    window.dispatchEvent(new CustomEvent("medlink:queue-change", { detail: { size: q.length } }));
  };
  const drainQueue = () => {
    const q = readQueue();
    if (!q.length) return 0;
    const store = window.STORE;
    if (!store) return 0;
    let drained = 0;
    for (const item of q) {
      try {
        const fn = store[item.action];
        if (typeof fn === "function") { fn.apply(store, Array.isArray(item.args) ? item.args : [item.args]); drained++; }
      } catch (err) {
        console.warn("[queue] replay failed:", err);
      }
    }
    writeQueue([]);
    window.dispatchEvent(new CustomEvent("medlink:queue-change", { detail: { size: 0, drained } }));
    if (drained > 0) {
      window.dispatchEvent(new CustomEvent("medlink:toast", { detail: `${drained} Aktion${drained > 1 ? "en" : ""} synchronisiert` }));
    }
    return drained;
  };
  // Auf online-Event automatisch drainen
  window.addEventListener("online", () => {
    setTimeout(drainQueue, 300);
  });

  // ---------- Push / Local Notifications ----------
  const MedlinkPush = {
    supported: () => typeof window !== "undefined" && "Notification" in window && "serviceWorker" in navigator,
    permission: () => (typeof Notification !== "undefined" ? Notification.permission : "denied"),
    async requestPermission() {
      if (!this.supported()) return "denied";
      if (Notification.permission !== "default") return Notification.permission;
      const res = await Notification.requestPermission();
      return res;
    },
    async notify(title, body, url) {
      if (!this.supported() || Notification.permission !== "granted") return false;
      const reg = await navigator.serviceWorker.getRegistration();
      if (reg) {
        reg.active?.postMessage({ type: "show-notification", title, body, url });
        return true;
      }
      // Fallback: direkter Notification constructor
      try { new Notification(title, { body, icon: "/icon-192.png" }); return true; }
      catch { return false; }
    },
  };
  window.MedlinkPush = MedlinkPush;
  window.MedlinkQueue = { read: readQueue, drain: drainQueue, enqueue, clear: () => writeQueue([]) };

  const emit = (toast, notif) => {
    if (toast) window.dispatchEvent(new CustomEvent("medlink:toast", { detail: toast }));
    if (notif) window.dispatchEvent(new CustomEvent("medlink:notify", { detail: notif }));
    // Push-Benachrichtigung bei aktivierter Permission (nur für high-signal Events)
    if (notif && window.MedlinkPush?.permission?.() === "granted" && (notif.kind === "approve" || notif.kind === "new" || notif.kind === "alert")) {
      try {
        window.MedlinkPush.notify(notif.title || "MedLink", notif.sub || "");
      } catch {}
    }
  };

  // Wrapper: record action for offline replay (demo: always records, even if online)
  const recordMutation = (action, args) => {
    if (!navigator.onLine) {
      try {
        const q = JSON.parse(localStorage.getItem("medlink.offline.queue") || "[]");
        q.push({ action, args, ts: Date.now() });
        localStorage.setItem("medlink.offline.queue", JSON.stringify(q));
        window.dispatchEvent(new CustomEvent("medlink:queue-change", { detail: { size: q.length } }));
        window.dispatchEvent(new CustomEvent("medlink:toast", { detail: "Offline — Aktion wartet auf Sync" }));
      } catch {}
    }
  };

  const ensureTrail = (id) => {
    if (!window.TRAIL) return;
    if (!window.TRAIL[id]) window.TRAIL[id] = [];
    return window.TRAIL[id];
  };

  const bewName = (bid) => (window.BEWOHNER || []).find((b) => b.id === bid)?.name || bid;
  const heimName = (hid) => (window.HEIMS || []).find((h) => h.id === hid)?.name || hid;

  const STORE = {
    _version: 0,
    _listeners: new Set(),
    bump() {
      this._version++;
      this._listeners.forEach((fn) => { try { fn(this._version); } catch {} });
    },
    subscribe(fn) {
      this._listeners.add(fn);
      return () => this._listeners.delete(fn);
    },

    // --- Anfrage lifecycle ---
    approveAnfrage(id) {
      const a = (window.ANFRAGEN || []).find((x) => x.id === id);
      if (!a || a.status === "freigegeben" || a.status === "geliefert") return;
      recordMutation("approveAnfrage", [id]);
      a.status = "freigegeben";
      a.freigabeZeit = now();
      const trail = ensureTrail(id);
      trail?.push({ t: "ok", who: "Dr. Schneider", head: "Freigegeben · HBA-signiert", ts: now() });
      trail?.push({ t: "info", who: "System", head: "eRezept an Adler-Apotheke gesendet", ts: now() });
      emit(
        `${id} freigegeben · eRezept an Adler-Apotheke`,
        { kind: "approve", icon: "check", title: `${id} freigegeben`, sub: `${a.med} · ${bewName(a.bewohner)}` }
      );
      this.bump();
    },

    rejectAnfrage(id, reason) {
      const a = (window.ANFRAGEN || []).find((x) => x.id === id);
      if (!a) return;
      a.status = "abgelehnt";
      a.abgelehntZeit = now();
      a.ablehnungsgrund = reason || "Rückfrage an Pflege";
      const trail = ensureTrail(id);
      trail?.push({ t: "warn", who: "Dr. Schneider", head: `Abgelehnt · ${a.ablehnungsgrund}`, ts: now() });
      emit(
        `${id} abgelehnt · Pflege wurde benachrichtigt`,
        { kind: "alert", icon: "warning", title: `${id} abgelehnt`, sub: `${a.med} · ${bewName(a.bewohner)}` }
      );
      this.bump();
    },

    deliverAnfrage(id) {
      const a = (window.ANFRAGEN || []).find((x) => x.id === id);
      if (!a || a.status === "geliefert") return;
      a.status = "geliefert";
      a.geliefertZeit = now();
      const trail = ensureTrail(id);
      trail?.push({ t: "ok", who: "Adler-Apotheke", head: "Geliefert · Kurier quittiert", ts: now() });
      emit(
        `${id} geliefert · bei Pflege eingetroffen`,
        { kind: "delivery", icon: "truck", title: `${id} geliefert`, sub: `${a.med} · ${heimName(a.heim)}` }
      );
      this.bump();
    },

    kommAnfrage(id) {
      const a = (window.ANFRAGEN || []).find((x) => x.id === id);
      if (!a) return;
      a.kommissioniert = true;
      a.kommZeit = now();
      const trail = ensureTrail(id);
      trail?.push({ t: "info", who: "Adler-Apotheke", head: "Kommissioniert · wartet auf Kurier", ts: now() });
      emit(
        `${id} kommissioniert · Liefertour 14:30`,
        { kind: "delivery", icon: "truck", title: `${id} kommissioniert`, sub: `${a.med} · ${heimName(a.heim)}` }
      );
      this.bump();
    },

    createAnfrage({ bewohner, typ, med, dosis, dauer, prio, notiz, von, arzt, heim }) {
      const list = window.ANFRAGEN;
      if (!list) return null;
      const maxN = list.reduce((mx, a) => Math.max(mx, parseInt((a.id || "A-0").split("-")[1] || 0, 10)), 2800);
      const id = `A-${maxN + 1}`;
      const b = (window.BEWOHNER || []).find((x) => x.id === bewohner);
      const next = {
        id,
        bewohner,
        heim: heim || b?.heim || "ros",
        arzt: arzt || b?.arzt || "schn",
        med, typ: typ || "Neu",
        dosis: dosis || "",
        dauer: dauer || "",
        prio: prio || "N",
        status: "offen",
        erstellt: "jetzt",
        von: von || "Sie",
        notiz: notiz || "",
      };
      list.unshift(next);
      ensureTrail(id)?.push({ t: "ok", who: next.von, head: "Anfrage erstellt", ts: now() });
      ensureTrail(id)?.push({ t: "info", who: "System", head: `Zugestellt an ${(window.DOCTORS||[]).find(d=>d.id===next.arzt)?.name || "Arzt"}`, ts: now() });
      emit(
        `${id} an ${(window.DOCTORS||[]).find(d=>d.id===next.arzt)?.name?.replace("Dr. med. ","Dr. ") || "Arzt"} gesendet`,
        { kind: "new", icon: "inbox", title: `Neue Anfrage · ${id}`, sub: `${med} · ${bewName(bewohner)}` }
      );
      this.bump();
      return id;
    },
  };

  window.STORE = STORE;

  // React hook — call at top of any component that reads mutable data.
  // Forces a re-render when STORE.bump() is called.
  window.useStoreVersion = function () {
    const [, force] = React.useState(0);
    React.useEffect(() => {
      const unsub = STORE.subscribe((v) => force(v));
      return unsub;
    }, []);
  };
})();
