// MedLink — ambient polish: AnimatedNumber, NotificationCenter, PresencePip
// AnimatedNumber: count-up for numeric KPI values, passthrough for strings.
// NotificationCenter: bell-dropdown + background trickle of lifelike events.
// PresencePip: small "X schaut gerade" badge.

// ---------------- AnimatedNumber ----------------
const AnimatedNumber = ({ value, duration = 900 }) => {
  // If the value is a pure integer (e.g. 18), animate it. If it's a string
  // like "94%", "1m 42s", "96%", try to parse the leading number; if that
  // fails, pass through.
  const str = String(value ?? "");
  const m = str.match(/^(-?\d+)(.*)$/);
  const isNumeric = typeof value === "number" || (m && m[1]);
  const target = isNumeric ? parseInt(m ? m[1] : value, 10) : null;
  const suffix = isNumeric && m ? m[2] : "";

  const [display, setDisplay] = React.useState(isNumeric ? 0 : str);
  const mounted = React.useRef(false);

  React.useEffect(() => {
    if (!isNumeric) { setDisplay(str); return; }
    mounted.current = true;
    const start = performance.now();
    const from = 0;
    const ease = (t) => 1 - Math.pow(1 - t, 3); // easeOutCubic
    let raf;
    const tick = (now) => {
      if (!mounted.current) return;
      const t = Math.min(1, (now - start) / duration);
      const v = Math.round(from + (target - from) * ease(t));
      setDisplay(v + suffix);
      if (t < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => { mounted.current = false; cancelAnimationFrame(raf); };
  }, [value]);

  return <>{display}</>;
};
window.AnimatedNumber = AnimatedNumber;

// ---------------- PresencePip ----------------
const PresencePip = ({ who = "Jemand", verb = "schaut gerade" }) => (
  <span className="presence" title={`${who} ${verb}`}>
    <span className="dot" />
    <span>{who} {verb}</span>
  </span>
);
window.PresencePip = PresencePip;

// ---------------- Notifications ----------------
const NOTIF_SEEDS = [
  { kind: "approve",  icon: "check",        title: "Dr. Schneider hat ANF-239 freigegeben",  sub: "Metformin 500 mg · Hr. Müller · Rosenhof",        age: 3 },
  { kind: "new",      icon: "inbox",        title: "Neue Anfrage · ANF-248",                 sub: "Pantoprazol 40 mg · Fr. Schmidt · Haus Linde",    age: 9 },
  { kind: "delivery", icon: "truck",        title: "Apotheke Adler bestätigt Lieferung",     sub: "ANF-235 · heute 10:42 · Pflegeheim Sonnenhof",    age: 14 },
  { kind: "alert",    icon: "warning",      title: "Rückfrage vom Arzt",                     sub: "ANF-241 · Dosierung prüfen · Dr. Weber",          age: 22 },
  { kind: "new",      icon: "stethoscope",  title: "Visite V-104 in 15 Min.",                sub: "Rosenhof · 4 Bewohner · Dr. Schneider",           age: 28 },
];

const NOTIF_TRICKLE = [
  { kind: "new",      icon: "inbox",        title: "Neue Anfrage · ANF-249",              sub: "Enoxaparin 40 mg · Hr. Weber · Rosenhof" },
  { kind: "approve",  icon: "check",        title: "Dr. Weber hat ANF-246 freigegeben",   sub: "Ibuprofen 400 mg · Fr. Lehmann · Linde" },
  { kind: "delivery", icon: "truck",        title: "Lieferung eingetroffen",              sub: "ANF-242 · Apotheke Schwanen · Sonnenhof" },
  { kind: "new",      icon: "activity",     title: "Therapie-Termin bestätigt",           sub: "Fr. Koch · Physio · Do 14:00" },
  { kind: "alert",    icon: "warning",      title: "Vitalwerte außerhalb Norm",           sub: "Hr. Müller · RR 162/98 · vor 2 Min." },
  { kind: "new",      icon: "pill",         title: "eRezept eingegangen",                 sub: "Bisoprolol 5 mg · Fr. Schulze" },
  { kind: "approve",  icon: "check",        title: "3 Anfragen stapelweise freigegeben",  sub: "Dr. Schneider · Rosenhof" },
];

let NOTIF_COUNTER = 0;
const makeNotif = (obj, now = Date.now()) => ({
  id: `N${++NOTIF_COUNTER}-${now.toString(36).slice(-4)}`,
  ts: now,
  unread: true,
  ...obj,
});

const timeAgo = (ts) => {
  const s = Math.max(0, Math.floor((Date.now() - ts) / 1000));
  if (s < 60) return "jetzt";
  const m = Math.floor(s / 60);
  if (m < 60) return `${m} Min`;
  const h = Math.floor(m / 60);
  if (h < 24) return `${h} Std`;
  return `${Math.floor(h / 24)} Tg`;
};

const NotificationCenter = ({ onAction }) => {
  const [open, setOpen] = React.useState(false);
  const [items, setItems] = React.useState(() =>
    NOTIF_SEEDS.map((s) => makeNotif({ ...s, unread: s.age <= 15 }, Date.now() - s.age * 60_000))
  );
  const [, tick] = React.useState(0); // re-render for timeAgo
  const trickleIdx = React.useRef(0);
  const panelRef = React.useRef(null);

  const unread = items.filter((i) => i.unread).length;

  // Toggle via event dispatched from Shell's bell button
  React.useEffect(() => {
    const toggle = () => setOpen((v) => !v);
    const add = (e) => {
      const n = makeNotif(e.detail);
      setItems((xs) => [n, ...xs].slice(0, 40));
    };
    window.addEventListener("medlink:bell", toggle);
    window.addEventListener("medlink:notify", add);
    return () => {
      window.removeEventListener("medlink:bell", toggle);
      window.removeEventListener("medlink:notify", add);
    };
  }, []);

  // Close on outside click / Escape
  React.useEffect(() => {
    if (!open) return;
    const onClick = (e) => {
      if (panelRef.current && !panelRef.current.contains(e.target)) setOpen(false);
    };
    const onKey = (e) => e.key === "Escape" && setOpen(false);
    const t = setTimeout(() => document.addEventListener("click", onClick), 0);
    document.addEventListener("keydown", onKey);
    return () => { clearTimeout(t); document.removeEventListener("click", onClick); document.removeEventListener("keydown", onKey); };
  }, [open]);

  // Refresh timeAgo every 30s
  React.useEffect(() => {
    const i = setInterval(() => tick((x) => x + 1), 30_000);
    return () => clearInterval(i);
  }, []);

  // Background trickle — one new event every 28-45s
  React.useEffect(() => {
    let timer;
    const schedule = () => {
      const delay = 28_000 + Math.random() * 17_000;
      timer = setTimeout(() => {
        const next = NOTIF_TRICKLE[trickleIdx.current % NOTIF_TRICKLE.length];
        trickleIdx.current++;
        setItems((xs) => [makeNotif(next), ...xs].slice(0, 40));
        schedule();
      }, delay);
    };
    schedule();
    return () => clearTimeout(timer);
  }, []);

  // Dot on bell (visually nudge the existing button in Topbar)
  React.useEffect(() => {
    document.querySelectorAll('button[title="Benachrichtigungen"]').forEach((btn) => {
      btn.classList.toggle("notif-anchor", true);
      let dot = btn.querySelector(".notif-dot");
      if (unread > 0) {
        if (!dot) {
          dot = document.createElement("span");
          dot.className = "notif-dot";
          btn.appendChild(dot);
        }
      } else if (dot) {
        dot.remove();
      }
    });
  }, [unread, items]);

  const markAllRead = () => setItems((xs) => xs.map((i) => ({ ...i, unread: false })));
  const clickItem = (it) => {
    setItems((xs) => xs.map((i) => (i.id === it.id ? { ...i, unread: false } : i)));
    onAction?.(it);
  };

  if (!open) return null;

  return (
    <div ref={panelRef} className="notif-panel" onClick={(e) => e.stopPropagation()}>
      <div className="notif-head">
        <Icon name="bell" size={13} />
        <span>Benachrichtigungen</span>
        <span className="count">{unread} neu</span>
        <span className="spacer" />
        <button onClick={markAllRead}>Alle gelesen</button>
      </div>
      <div className="notif-list">
        {items.length === 0 && (
          <div style={{ padding: "28px 14px", textAlign: "center", fontSize: 12, color: "var(--fg-subtle)" }}>
            Keine Benachrichtigungen.
          </div>
        )}
        {items.map((it) => (
          <div
            key={it.id}
            className={`notif-item ${it.unread ? "unread" : ""}`}
            data-kind={it.kind}
            onClick={() => clickItem(it)}
          >
            <span className="notif-ic"><Icon name={it.icon || "bell"} size={13} /></span>
            <div className="notif-main">
              <div className="title">{it.title}</div>
              {it.sub && <div className="sub">{it.sub}</div>}
            </div>
            <span className="notif-time">{timeAgo(it.ts)}</span>
          </div>
        ))}
      </div>
      <div className="notif-foot">
        <span className="live" />
        <span>Live · Echtzeit-Sync aktiv</span>
      </div>
    </div>
  );
};
window.NotificationCenter = NotificationCenter;
