// ============================================
// Reliq — UI feedback system
// Load order: after reliq-state.jsx, before app components.
//
// Provides:
//   reliqToast          — fire toast notifications from anywhere
//   reliqGatePrompt     — show locked-feature upgrade prompt
//   reliqConfirm        — show confirmation / destructive-action dialog
//
//   ToastContainer      — mount once in App
//   GatePromptContainer — mount once in App
//   ConfirmDialogContainer — mount once in App
//
//   FormField           — consistent form field wrapper with label + error
//   Spinner             — inline SVG spinner
//   EmptyState          — centred empty-state panel
//   LoadingState        — skeleton loading panel
//   LockedTabOverlay    — full-content locked panel for gated scan tabs
// ============================================

// ── Toast system ─────────────────────────────────────────────────────────────
// Usage from any component:
//   reliqToast.success("Copied to clipboard")
//   reliqToast.error("Failed to save settings", 5000)
//   reliqToast.info("Scan queued")
//   reliqToast.warning("Trial ends in 2 days")
const _TOAST_EV = "reliq-toast";

const reliqToast = {
  _fire(message, type, duration) {
    window.dispatchEvent(new CustomEvent(_TOAST_EV, {
      detail: { message, type, duration: duration || (type === "error" ? 5000 : 3500), id: Date.now() + Math.random() }
    }));
  },
  show(message, type = "info", duration)  { this._fire(message, type, duration); },
  success(message, duration) { this._fire(message, "success", duration); },
  error(message, duration)   { this._fire(message, "error",   duration); },
  info(message, duration)    { this._fire(message, "info",    duration); },
  warning(message, duration) { this._fire(message, "warning", duration); },
};

const _TOAST_STYLES = {
  success: { bg: "var(--teal-bg)", border: "var(--line-3)",               icon: "check-circle", color: "var(--teal)"  },
  error:   { bg: "var(--red-bg)",  border: "rgba(239,68,68,0.3)",         icon: "x-circle",     color: "var(--red)"   },
  warning: { bg: "var(--amber-bg)",border: "rgba(245,158,11,0.3)",        icon: "alert",        color: "var(--amber)" },
  info:    { bg: "var(--bg-2)",    border: "var(--line-2)",               icon: "info",         color: "var(--blue)"  },
};

const ToastContainer = () => {
  const [toasts, setToasts] = React.useState([]);

  React.useEffect(() => {
    const onToast = (e) => {
      const t = e.detail;
      setToasts(prev => [...prev.slice(-4), t]); // max 5 visible
      setTimeout(() => setToasts(prev => prev.filter(x => x.id !== t.id)), t.duration);
    };
    window.addEventListener(_TOAST_EV, onToast);
    return () => window.removeEventListener(_TOAST_EV, onToast);
  }, []);

  if (!toasts.length) return null;

  return (
    <div
      role="status"
      aria-live="polite"
      aria-atomic="false"
      style={{
        position: "fixed", bottom: 24, right: 24, zIndex: 99990,
        display: "flex", flexDirection: "column", gap: 8,
        maxWidth: 360, pointerEvents: "none",
      }}
    >
      {toasts.map(t => {
        const s = _TOAST_STYLES[t.type] || _TOAST_STYLES.info;
        return (
          <div
            key={t.id}
            style={{
              display: "flex", alignItems: "flex-start", gap: 10,
              padding: "12px 16px",
              background: s.bg, border: `1px solid ${s.border}`,
              borderRadius: "var(--r-md)",
              boxShadow: "0 6px 24px rgba(0,0,0,0.2)",
              fontSize: 13.5, color: "var(--fg-0)", lineHeight: 1.5,
              pointerEvents: "all",
              animation: "toastIn 0.18s ease-out",
            }}
          >
            <Icon name={s.icon} size={15} style={{ color: s.color, flexShrink: 0, marginTop: 1 }} />
            <span>{t.message}</span>
          </div>
        );
      })}
    </div>
  );
};

// ── useFocusTrap ──────────────────────────────────────────────────────────────
// Custom hook: traps Tab/Shift+Tab focus within a container while active.
// Also auto-focuses the first focusable child and restores previous focus on close.
// Usage:
//   const trapRef = useFocusTrap(isOpen);
//   <div ref={trapRef} role="dialog" aria-modal="true"> ... </div>
const useFocusTrap = (active) => {
  const ref = React.useRef(null);

  React.useEffect(() => {
    if (!active) return;
    const el = ref.current;
    if (!el) return;

    const previouslyFocused = document.activeElement;

    const FOCUSABLE = [
      'a[href]','button:not([disabled])','input:not([disabled])','select:not([disabled])',
      'textarea:not([disabled])','[tabindex]:not([tabindex="-1"])',
    ].join(",");

    const getFocusable = () =>
      Array.from(el.querySelectorAll(FOCUSABLE)).filter(n => !n.closest('[hidden]'));

    const handleKeyDown = (e) => {
      if (e.key !== "Tab") return;
      const focusable = getFocusable();
      if (!focusable.length) { e.preventDefault(); return; }
      const first = focusable[0];
      const last  = focusable[focusable.length - 1];
      if (e.shiftKey) {
        if (document.activeElement === first) { e.preventDefault(); last.focus(); }
      } else {
        if (document.activeElement === last)  { e.preventDefault(); first.focus(); }
      }
    };

    // Auto-focus first focusable element
    const focusable = getFocusable();
    if (focusable.length) focusable[0].focus();

    el.addEventListener("keydown", handleKeyDown);
    return () => {
      el.removeEventListener("keydown", handleKeyDown);
      if (previouslyFocused && typeof previouslyFocused.focus === "function") {
        previouslyFocused.focus();
      }
    };
  }, [active]);

  return ref;
};

// ── Gate prompt (locked feature upgrade modal) ────────────────────────────────
// Usage: reliqGatePrompt.show({ feature: "pdf_export", planRequired: "starter", go })
const _GATE_EV = "reliq-gate-prompt";

const reliqGatePrompt = {
  show({ title, description, planRequired = "starter", go }) {
    window.dispatchEvent(new CustomEvent(_GATE_EV, {
      detail: { title, description, planRequired, go }
    }));
  },
};

const GatePromptContainer = ({ go }) => {
  const [prompt, setPrompt] = React.useState(null);
  const trapRef = useFocusTrap(!!prompt); // focus trap + restore on close

  React.useEffect(() => {
    const handler = (e) => setPrompt(e.detail);
    window.addEventListener(_GATE_EV, handler);
    return () => window.removeEventListener(_GATE_EV, handler);
  }, []);

  // Escape handler
  React.useEffect(() => {
    if (!prompt) return;
    const onKey = (e) => { if (e.key === "Escape") setPrompt(null); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [prompt]);

  // Body scroll lock
  React.useEffect(() => {
    if (!prompt) return;
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => { document.body.style.overflow = prev; };
  }, [prompt]);

  if (!prompt) return null;

  const planName = PLAN_META?.[prompt.planRequired]?.name || "Starter";
  const priceStr = PLAN_META?.[prompt.planRequired]?.priceStr || "$29";
  const navFn = prompt.go || go;

  return (
    <div
      onClick={() => setPrompt(null)}
      style={{
        position: "fixed", inset: 0, zIndex: 9500,
        background: "rgba(0,0,0,0.55)",
        backdropFilter: "blur(5px)", WebkitBackdropFilter: "blur(5px)",
        display: "flex", alignItems: "center", justifyContent: "center",
        padding: 20,
      }}
    >
      <div
        ref={trapRef}
        role="dialog"
        aria-modal="true"
        aria-labelledby="gate-title"
        onClick={e => e.stopPropagation()}
        style={{
          background: "var(--bg-1)", border: "1px solid var(--line-2)",
          borderRadius: 16, maxWidth: 400, width: "100%",
          padding: "26px 26px 22px",
          boxShadow: "0 24px 60px rgba(0,0,0,0.35)",
        }}
      >
        {/* Header */}
        <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", marginBottom: 18 }}>
          <div style={{
            width: 44, height: 44, borderRadius: "var(--r-md)",
            background: "var(--bg-3)", border: "1px solid var(--line-2)",
            display: "flex", alignItems: "center", justifyContent: "center",
            color: "var(--amber)",
          }}>
            <Icon name="lock" size={20} />
          </div>
          <button
            ref={closeBtnRef}
            onClick={() => setPrompt(null)}
            aria-label="Close"
            style={{
              background: "none", border: "1px solid var(--line-2)", borderRadius: 7,
              cursor: "pointer", color: "var(--fg-2)", padding: "4px 6px",
              display: "flex", alignItems: "center", transition: "border-color .12s, color .12s",
            }}
            onMouseEnter={e => { e.currentTarget.style.color = "var(--fg-0)"; e.currentTarget.style.borderColor = "var(--line-3)"; }}
            onMouseLeave={e => { e.currentTarget.style.color = "var(--fg-2)"; e.currentTarget.style.borderColor = "var(--line-2)"; }}
          >
            <Icon name="x" size={14} />
          </button>
        </div>

        <h2 id="gate-title" style={{
          fontFamily: "var(--font-display)", fontSize: 17, fontWeight: 700,
          margin: "0 0 8px", color: "var(--fg-0)", letterSpacing: "-0.01em",
        }}>
          {prompt.title || `${planName} plan required`}
        </h2>
        <p style={{ fontSize: 13.5, color: "var(--fg-2)", lineHeight: 1.65, margin: "0 0 20px" }}>
          {prompt.description || `Upgrade to ${planName} (${priceStr}/mo) to unlock this feature, along with PDF export, re-scan, and more.`}
        </p>

        <div style={{ display: "flex", gap: 8 }}>
          <button
            className="btn btn-primary"
            style={{ flex: 1, justifyContent: "center" }}
            onClick={() => {
              setPrompt(null);
              if (navFn) navFn("signup?plan=" + prompt.planRequired + "&trial=7d&source=pricing");
            }}
          >
            Start {planName} trial <Icon name="arrow-right" size={13} />
          </button>
          <button
            className="btn btn-ghost"
            onClick={() => setPrompt(null)}
            style={{ flexShrink: 0 }}
          >
            Not now
          </button>
        </div>
      </div>
    </div>
  );
};

// ── Confirm dialog ────────────────────────────────────────────────────────────
// Usage: reliqConfirm.show({ title: "Delete workspace?", message: "...", danger: true, onConfirm: () => ... })
// Never use browser alert() or window.confirm() — use this instead.
const _CONFIRM_EV = "reliq-confirm";

const reliqConfirm = {
  show({ title, message, confirmLabel = "Confirm", cancelLabel = "Cancel", danger = false, onConfirm, onCancel }) {
    window.dispatchEvent(new CustomEvent(_CONFIRM_EV, {
      detail: { title, message, confirmLabel, cancelLabel, danger, onConfirm, onCancel }
    }));
  },
};

const ConfirmDialogContainer = () => {
  const [dialog, setDialog] = React.useState(null);
  const trapRef = useFocusTrap(!!dialog);

  React.useEffect(() => {
    const handler = (e) => setDialog(e.detail);
    window.addEventListener(_CONFIRM_EV, handler);
    return () => window.removeEventListener(_CONFIRM_EV, handler);
  }, []);

  React.useEffect(() => {
    if (!dialog) return;
    const onKey = (e) => { if (e.key === "Escape") { dialog.onCancel?.(); setDialog(null); } };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [dialog]);

  React.useEffect(() => {
    if (!dialog) return;
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => { document.body.style.overflow = prev; };
  }, [dialog]);

  if (!dialog) return null;

  const confirm = () => { dialog.onConfirm?.(); setDialog(null); };
  const cancel  = () => { dialog.onCancel?.();  setDialog(null); };

  return (
    <div
      onClick={cancel}
      style={{
        position: "fixed", inset: 0, zIndex: 9800,
        background: "rgba(0,0,0,0.55)",
        backdropFilter: "blur(5px)", WebkitBackdropFilter: "blur(5px)",
        display: "flex", alignItems: "center", justifyContent: "center",
        padding: 20,
      }}
    >
      <div
        ref={trapRef}
        role="alertdialog"
        aria-modal="true"
        aria-labelledby="confirm-title"
        onClick={e => e.stopPropagation()}
        style={{
          background: "var(--bg-1)", border: "1px solid var(--line-2)",
          borderRadius: 14, maxWidth: 380, width: "100%",
          padding: "22px 22px 18px",
          boxShadow: "0 20px 50px rgba(0,0,0,0.35)",
        }}
      >
        <h2 id="confirm-title" style={{
          fontFamily: "var(--font-display)", fontSize: 15, fontWeight: 700,
          margin: "0 0 8px",
          color: dialog.danger ? "var(--red)" : "var(--fg-0)",
        }}>
          {dialog.title}
        </h2>
        <p style={{ fontSize: 13.5, color: "var(--fg-2)", lineHeight: 1.65, margin: "0 0 20px" }}>
          {dialog.message}
        </p>
        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
          <button className="btn btn-ghost btn-sm" onClick={cancel}>
            {dialog.cancelLabel}
          </button>
          <button
            className={`btn btn-sm ${dialog.danger ? "btn-danger" : "btn-primary"}`}
            onClick={confirm}
            autoFocus
          >
            {dialog.confirmLabel}
          </button>
        </div>
      </div>
    </div>
  );
};

// ── FormField ─────────────────────────────────────────────────────────────────
// Wraps a form input with a consistent label, error, and optional hint.
// Usage:
//   <FormField label="Email" error={errors.email} required>
//     <input type="email" ... />
//   </FormField>
const FormField = ({ label, error, required, hint, children, style, htmlFor }) => (
  <div style={{ display: "flex", flexDirection: "column", gap: 6, marginBottom: 16, ...style }}>
    {label && (
      <label
        htmlFor={htmlFor}
        style={{
          fontFamily: "var(--font-mono)", fontSize: 10.5,
          letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)",
        }}
      >
        {label}
        {required && <span style={{ color: "var(--red)", marginLeft: 3 }} aria-hidden="true">*</span>}
      </label>
    )}
    {children}
    {error && (
      <span
        role="alert"
        style={{ fontSize: 12.5, color: "var(--red)", display: "flex", alignItems: "center", gap: 5 }}
      >
        <Icon name="alert" size={11} aria-hidden="true" /> {error}
      </span>
    )}
    {hint && !error && (
      <span style={{ fontSize: 12, color: "var(--fg-3)", lineHeight: 1.5 }}>{hint}</span>
    )}
  </div>
);

// ── Spinner ───────────────────────────────────────────────────────────────────
const Spinner = ({ size = 14, style }) => (
  <svg
    width={size} height={size} viewBox="0 0 24 24"
    aria-hidden="true"
    style={{ animation: "spin 1s linear infinite", flexShrink: 0, ...style }}
  >
    <circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="2.5"
            fill="none" strokeDasharray="40 60" strokeLinecap="round" />
  </svg>
);

// ── EmptyState ────────────────────────────────────────────────────────────────
// Shows a centred icon, title, description, and optional action button.
const EmptyState = ({ icon = "layers", title, description, action, style }) => (
  <div style={{
    display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center",
    padding: "60px 24px", textAlign: "center", ...style,
  }}>
    <div style={{
      width: 52, height: 52, borderRadius: "var(--r-md)",
      background: "var(--bg-3)", border: "1px solid var(--line-2)",
      display: "flex", alignItems: "center", justifyContent: "center",
      color: "var(--fg-3)", marginBottom: 16,
    }}>
      <Icon name={icon} size={22} />
    </div>
    {title && (
      <div style={{
        fontFamily: "var(--font-display)", fontSize: 15, fontWeight: 600,
        color: "var(--fg-0)", marginBottom: 6,
      }}>
        {title}
      </div>
    )}
    {description && (
      <div style={{ fontSize: 13.5, color: "var(--fg-2)", lineHeight: 1.65, maxWidth: 320, marginBottom: action ? 20 : 0 }}>
        {description}
      </div>
    )}
    {action}
  </div>
);

// ── LoadingState ──────────────────────────────────────────────────────────────
// Skeleton loading panel — use while async data is being fetched.
const LoadingState = ({ message = "Loading…", rows = 3 }) => (
  <div style={{ padding: "28px 24px" }} aria-busy="true" aria-label={message}>
    <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 20, color: "var(--fg-3)" }}>
      <Spinner size={13} />
      <span style={{ fontSize: 13, fontFamily: "var(--font-mono)" }}>{message}</span>
    </div>
    {Array.from({ length: rows }).map((_, i) => (
      <div key={i} style={{
        height: 42, borderRadius: "var(--r-sm)",
        background: "var(--bg-2)", marginBottom: 8,
        opacity: 1 - i * 0.2,
        animation: "skeletonPulse 1.6s ease-in-out infinite",
        animationDelay: `${i * 0.1}s`,
      }} />
    ))}
  </div>
);

// ── LockedTabOverlay ──────────────────────────────────────────────────────────
// Replaces gated tab content when the user's plan doesn't include that tab.
// Usage: {!reliqGates.canAccessTab("sdk") && <LockedTabOverlay planRequired="starter" go={go} />}
const LockedTabOverlay = ({ planRequired = "starter", go, featureName }) => {
  const planName  = PLAN_META?.[planRequired]?.name  || "Starter";
  const priceStr  = PLAN_META?.[planRequired]?.priceStr || "$29";

  return (
    <div style={{
      display: "flex", flexDirection: "column", alignItems: "center",
      justifyContent: "center", textAlign: "center",
      padding: "72px 24px", minHeight: 300,
    }}>
      <div style={{
        width: 52, height: 52, borderRadius: "var(--r-md)",
        background: "var(--bg-3)", border: "1px solid var(--line-2)",
        display: "flex", alignItems: "center", justifyContent: "center",
        color: "var(--amber)", marginBottom: 18,
      }}>
        <Icon name="lock" size={22} />
      </div>
      <div style={{
        fontFamily: "var(--font-display)", fontSize: 16, fontWeight: 600,
        color: "var(--fg-0)", marginBottom: 8,
      }}>
        {featureName ? `${featureName} requires ${planName}` : `${planName} plan required`}
      </div>
      <div style={{
        fontSize: 13.5, color: "var(--fg-2)", lineHeight: 1.65,
        maxWidth: 340, marginBottom: 24,
      }}>
        Upgrade to {planName} ({priceStr}/mo) to unlock this analysis, along with PDF export, re-scan, and more. No charge for 7 days.
      </div>
      <div style={{ display: "flex", gap: 10, flexWrap: "wrap", justifyContent: "center" }}>
        <button
          className="btn btn-primary"
          onClick={() => go && go("signup?plan=" + planRequired + "&trial=7d&source=pricing")}
        >
          Start {planName} trial — free <Icon name="arrow-right" size={13} />
        </button>
        <button
          className="btn btn-ghost"
          onClick={() => go && go("billing")}
        >
          View plans
        </button>
      </div>
    </div>
  );
};

// ── CopyButton ────────────────────────────────────────────────────────────────
// Reusable copy-to-clipboard button with toast feedback.
// Usage: <CopyButton text="some string" label="Copy link" />
const CopyButton = ({ text, label = "Copy", successLabel = "Copied!", className = "btn btn-sm", style }) => {
  const [copied, setCopied] = React.useState(false);

  const handleCopy = () => {
    if (navigator.clipboard) {
      navigator.clipboard.writeText(text).catch(() => {});
    } else {
      // Fallback for older browsers
      const ta = document.createElement("textarea");
      ta.value = text; ta.style.cssText = "position:fixed;opacity:0";
      document.body.appendChild(ta); ta.select();
      document.execCommand("copy");
      document.body.removeChild(ta);
    }
    window.reliqToast?.success("Copied to clipboard");
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  };

  return (
    <button className={className} style={style} onClick={handleCopy} aria-label={label}>
      {copied
        ? <><Icon name="check" size={12} /> {successLabel}</>
        : <><Icon name="copy" size={12} /> {label}</>
      }
    </button>
  );
};

// Expose to window
Object.assign(window, {
  reliqToast,
  reliqGatePrompt,
  reliqConfirm,
  ToastContainer,
  GatePromptContainer,
  ConfirmDialogContainer,
  FormField,
  Spinner,
  EmptyState,
  LoadingState,
  LockedTabOverlay,
  CopyButton,
  useFocusTrap,
});
