// toast.jsx — unified operation feedback для админ-панели.
//
// Принципы (из обсуждения):
//   - LOUD: операционная панель должна громко сообщать об ошибках
//   - dedupe одинаковых ошибок (3-сек window — частая mutation не спамит)
//   - severity-based TTL: ok → быстро, err → долго
//   - max 5 toast на экране — старые auto-dismiss
//   - manual dismiss кнопкой ×
//   - не блокируют UI (поверх, не модалка)
//
// API:
//   window.__toast.push({ kind: "ok"|"info"|"warn"|"err", text: string })
//   window.__toast.dismiss(id)
//   <Toaster />  — компонент, монтируется один раз в <App>

(function () {
  "use strict";

  // ============================================================
  //  store
  // ============================================================

  const toasts = []; // [{id, kind, text, ts, expiresAt}]
  const listeners = new Set();
  let nextId = 1;
  let cleanupTimer = null;

  // TTL по severity (мс). err держим долго чтобы оператор успел прочитать.
  const TTL = { info: 3000, ok: 2500, warn: 5000, err: 8000 };

  // Dedupe window: если push с тем же kind+text прилетел в течение этого
  // времени с предыдущего — продлеваем существующий, не плодим новый.
  const DEDUPE_WINDOW_MS = 3000;

  // Лимит одновременных toast'ов. При переполнении дропаем самый старый.
  const MAX_TOASTS = 5;

  function _notify() {
    listeners.forEach((fn) => fn());
  }

  function _ensureCleanup() {
    if (cleanupTimer) return;
    cleanupTimer = setInterval(() => {
      const now = Date.now();
      let changed = false;
      for (let i = toasts.length - 1; i >= 0; i--) {
        if (toasts[i].expiresAt <= now) {
          toasts.splice(i, 1);
          changed = true;
        }
      }
      if (changed) _notify();
      if (toasts.length === 0) {
        clearInterval(cleanupTimer);
        cleanupTimer = null;
      }
    }, 500);
  }

  function push(opts) {
    if (!opts || !opts.text) return;
    const kind = opts.kind || "info";
    const text = String(opts.text).slice(0, 240);
    const now = Date.now();

    // Dedupe — продлеваем TTL у существующего вместо нового
    const dup = toasts.find(
      (t) => t.kind === kind && t.text === text && now - t.ts < DEDUPE_WINDOW_MS
    );
    if (dup) {
      dup.ts = now;
      dup.expiresAt = now + (TTL[kind] || 3000);
      _notify();
      return dup.id;
    }

    const id = nextId++;
    toasts.push({
      id,
      kind,
      text,
      ts: now,
      expiresAt: now + (TTL[kind] || 3000),
    });

    // Лимит — дропаем самый старый
    while (toasts.length > MAX_TOASTS) toasts.shift();

    _notify();
    _ensureCleanup();
    return id;
  }

  function dismiss(id) {
    const i = toasts.findIndex((t) => t.id === id);
    if (i >= 0) {
      toasts.splice(i, 1);
      _notify();
    }
  }

  function subscribe(fn) {
    listeners.add(fn);
    return () => listeners.delete(fn);
  }

  function getSnapshot() {
    // Возвращаем стабильный snapshot — список меняется по ссылке через _notify
    return toasts;
  }

  // expose до того как Toaster что-то отрисует
  window.__toast = { push, dismiss };

  // Optional hook для использования из компонентов
  window.useToast = function useToast() {
    return window.__toast;
  };

  // ============================================================
  //  <Toaster /> — компонент
  // ============================================================

  function Toaster() {
    const [, force] = React.useState(0);
    React.useEffect(() => subscribe(() => force((n) => n + 1)), []);
    const list = getSnapshot();

    if (list.length === 0) return null;

    const styleByKind = {
      info: "bg-zinc-900/95 border-zinc-700 text-zinc-200",
      ok: "bg-emerald-950/95 border-emerald-700/60 text-emerald-200",
      warn: "bg-amber-950/95 border-amber-700/60 text-amber-200",
      err: "bg-rose-950/95 border-rose-700/60 text-rose-200",
    };
    const iconByKind = { info: "info", ok: "check", warn: "alert", err: "x" };

    return (
      <div className="fixed top-4 right-4 z-[9999] flex flex-col gap-2 max-w-[400px] pointer-events-none">
        {list.map((t) => (
          <div
            key={t.id}
            className={
              "px-3.5 py-2.5 rounded-lg shadow-lg border text-[13px] flex items-start gap-2 backdrop-blur-sm pointer-events-auto " +
              (styleByKind[t.kind] || styleByKind.info)
            }
            role={t.kind === "err" ? "alert" : "status"}
          >
            {/* Icon — берём из существующего <Icon/> если есть */}
            {typeof Icon !== "undefined" && (
              <Icon name={iconByKind[t.kind] || "info"} className="w-3.5 h-3.5 mt-0.5 shrink-0" />
            )}
            <span className="flex-1 break-words leading-snug">{t.text}</span>
            <button
              onClick={() => dismiss(t.id)}
              className="opacity-50 hover:opacity-100 transition-opacity ml-1 shrink-0 -mr-1"
              title="Закрыть"
            >
              ×
            </button>
          </div>
        ))}
      </div>
    );
  }

  window.Toaster = Toaster;
})();
