// SQSEO app shell infrastructure: a tiny API client, a global toast system, and
// reusable Popover / Modal / MenuItem primitives. Everything registers on
// window.LTQ so the no-build screens can share it. Loaded before Sidebar/Topbar.
(function init(){
if(!window.LongtailIQDesignSystem_ae8f12){return setTimeout(init,30);}
const React = window.React;
const DS = window.LongtailIQDesignSystem_ae8f12;
const { Icon } = DS;
window.LTQ = window.LTQ || {};

// ----------------------------------------------------------------- API client
// Returns { ok, status, data, error }. A 401 means the session lapsed (expiry,
// or a password change elsewhere) -> bounce to sign in. Never throws.
async function call(method, path, body){
  const opts = { method, credentials: "same-origin", headers: {} };
  if (body !== undefined) { opts.headers["Content-Type"] = "application/json"; opts.body = JSON.stringify(body); }
  let res;
  try { res = await fetch(path, opts); }
  catch (e) { return { ok: false, status: 0, data: {}, error: window.LTQ.t ? window.LTQ.t("chrome.offline") : "Could not reach the server." }; }
  if (res.status === 401) { window.location.href = "/app/login.html"; return { ok: false, status: 401, data: {}, error: "unauthorized" }; }
  let data = {};
  try { data = await res.json(); } catch (e) {}
  return { ok: res.ok, status: res.status, data, error: res.ok ? null : (data.message || data.error || (window.LTQ.t ? window.LTQ.t("chrome.generic_error") : "Something went wrong.")) };
}
window.LTQ.api = {
  get: (p) => call("GET", p),
  post: (p, b) => call("POST", p, b),
  patch: (p, b) => call("PATCH", p, b),
  del: (p) => call("DELETE", p),
};

// ------------------------------------------------ live boot (no full reloads)
// Components subscribe; reloadBoot() re-fetches /api/bootstrap, updates
// window.LTQ.boot and notifies, so the shell re-renders in place after a switch
// or edit instead of a jarring page reload.
let bootListeners = [];
window.LTQ.subscribeBoot = (fn) => { bootListeners.push(fn); return () => { bootListeners = bootListeners.filter((f) => f !== fn); }; };
window.LTQ.reloadBoot = async () => {
  const r = await call("GET", "/api/bootstrap");
  if (r.ok) { window.LTQ.boot = r.data; bootListeners.forEach((fn) => { try { fn(); } catch (e) {} }); }
  return r;
};

// ----------------------------------------------------- data-loading hook
// useApi(path, deps) GETs a JSON endpoint and re-fetches when the path, the
// active project, or any extra dep changes. Returns { loading, data, error, reload }.
window.LTQ.useApi = function (path, deps) {
  deps = deps || [];
  const url = typeof path === "function" ? path() : path;
  const projectId = (window.LTQ.boot && window.LTQ.boot.project && window.LTQ.boot.project.id) || "";
  const [state, setState] = React.useState({ loading: true, data: null, error: null });
  const apply = (r) => setState({ loading: false, data: r.ok ? r.data : null, error: r.ok ? null : r.error });
  const reload = React.useCallback(async () => { setState((s) => ({ ...s, loading: true })); apply(await window.LTQ.api.get(url)); }, [url, projectId, ...deps]);
  React.useEffect(() => {
    let alive = true;
    setState({ loading: true, data: null, error: null });
    window.LTQ.api.get(url).then((r) => { if (alive) apply(r); });
    return () => { alive = false; };
  }, [url, projectId, ...deps]);
  return { loading: state.loading, data: state.data, error: state.error, reload };
};

// -------------------------------------------------------------------- toasts
// window.LTQ.toast("Saved", { tone: "success" }) — tone: default|success|error|warning.
const TONE_DOT = { default: "var(--text-faint)", success: "var(--viz-green)", error: "var(--viz-red)", warning: "var(--viz-amber)" };
function toast(message, opts){
  opts = opts || {};
  window.dispatchEvent(new CustomEvent("ltq:toast", { detail: { message, tone: opts.tone || "default", id: Math.random().toString(36).slice(2) } }));
}
window.LTQ.toast = toast;

function ToastHost(){
  const [items, setItems] = React.useState([]);
  React.useEffect(() => {
    const on = (e) => {
      const t = e.detail;
      setItems((x) => [...x, t]);
      // Gestalt-style exit: fade+slide out for 240ms before removal instead of popping away.
      setTimeout(() => setItems((x) => x.map((i) => (i.id === t.id ? { ...i, leaving: true } : i))), 3400);
      setTimeout(() => setItems((x) => x.filter((i) => i.id !== t.id)), 3660);
    };
    window.addEventListener("ltq:toast", on);
    return () => window.removeEventListener("ltq:toast", on);
  }, []);
  return (
    <div style={{ position: "fixed", bottom: 22, left: "50%", transform: "translateX(-50%)", zIndex: 300,
      display: "flex", flexDirection: "column", alignItems: "center", gap: 8, pointerEvents: "none" }}>
      {items.map((t) => (
        <div key={t.id} className={t.leaving ? "lt-toast-out" : "lt-toast-in"} style={{ display: "inline-flex", alignItems: "center", gap: 9,
          padding: "11px 16px", borderRadius: 999, background: "var(--ink-900)", color: "#fff",
          boxShadow: "var(--shadow-lg)", fontSize: 13.5, fontWeight: 600, pointerEvents: "auto" }}>
          {t.tone === "success"
            ? <span className="lt-tick-pop" style={{ width: 17, height: 17, borderRadius: 999, background: "var(--viz-green)", display: "grid", placeItems: "center", flex: "none" }}>
                <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="3.6" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5" /></svg>
              </span>
            : <span style={{ width: 7, height: 7, borderRadius: 999, background: TONE_DOT[t.tone] || TONE_DOT.default, flex: "none" }} />}
          {t.message}
        </div>
      ))}
    </div>
  );
}
window.LTQ.ToastHost = ToastHost;

// ------------------------------------------------------------------- Popover
// Controlled-internally dropdown with click-away + Escape. `trigger(open, toggle)`
// renders the button; `children` is a node or (close) => node. align: left|right.
function Popover({ trigger, children, align = "left", width = 260, panelStyle }){
  const [open, setOpen] = React.useState(false);
  React.useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === "Escape") setOpen(false); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open]);
  const close = () => setOpen(false);
  return (
    <div style={{ position: "relative" }}>
      {trigger(open, () => setOpen((o) => !o))}
      {open && (
        <>
          <div onClick={close} style={{ position: "fixed", inset: 0, zIndex: 40 }} />
          <div className="lt-pop" style={{ position: "absolute", top: "calc(100% + 6px)", [align]: 0, zIndex: 41,
            minWidth: width, padding: 6, background: "var(--paper)", border: "1px solid var(--border-subtle)",
            borderRadius: 12, boxShadow: "var(--shadow-lg)", transformOrigin: align === "right" ? "top right" : "top left", ...(panelStyle || {}) }}>
            {typeof children === "function" ? children(close) : children}
          </div>
        </>
      )}
    </div>
  );
}
window.LTQ.Popover = Popover;

// Row inside a Popover menu.
function MenuItem({ icon, label, sub, trailing, onClick, danger, active }){
  const [hover, setHover] = React.useState(false);
  return (
    <button onClick={onClick} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{ display: "flex", alignItems: "center", gap: 10, width: "100%", padding: "8px 9px", border: "none",
        borderRadius: 8, cursor: "pointer", textAlign: "left", background: hover || active ? "var(--ink-50)" : "transparent",
        color: danger ? "var(--viz-red)" : "var(--text-body)", fontFamily: "var(--font-sans)", fontSize: 13, fontWeight: 500 }}>
      {icon && <Icon name={icon} size={15} style={{ color: danger ? "var(--viz-red)" : "var(--text-faint)", flex: "none" }} />}
      <span style={{ flex: 1, minWidth: 0 }}>
        <span style={{ display: "block", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", fontWeight: active ? 600 : 500, color: danger ? "var(--viz-red)" : "var(--text-strong)" }}>{label}</span>
        {sub && <span style={{ display: "block", fontSize: 11, color: "var(--text-faint)" }}>{sub}</span>}
      </span>
      {trailing}
    </button>
  );
}
window.LTQ.MenuItem = MenuItem;

// --------------------------------------------------------------------- Modal
// Centered dialog with backdrop + Escape-to-close. children may use the form.
function Modal({ title, sub, onClose, children, width = 460 }){
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose && onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);
  return (
    <div onMouseDown={(e) => { if (e.target === e.currentTarget) onClose && onClose(); }} className="lt-backdrop-in"
      style={{ position: "fixed", inset: 0, zIndex: 120, display: "grid", placeItems: "center", padding: 20,
        background: "rgba(12,16,14,0.42)", backdropFilter: "blur(2px)" }}>
      <div className="lt-overlay-in" style={{ width: "100%", maxWidth: width, background: "var(--paper)", border: "1px solid var(--border-subtle)",
        borderRadius: "var(--r-xl)", boxShadow: "var(--shadow-lg)", padding: 22, transformOrigin: "center" }}>
        <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 12, marginBottom: 16 }}>
          <div>
            <h3 style={{ fontSize: 18, fontWeight: 700, letterSpacing: "-0.01em", color: "var(--text-strong)" }}>{title}</h3>
            {sub && <p style={{ fontSize: 13, color: "var(--text-muted)", marginTop: 4 }}>{sub}</p>}
          </div>
          <button onClick={onClose} aria-label={window.LTQ.t ? window.LTQ.t("chrome.close") : "Close"} style={{ flex: "none", width: 30, height: 30, display: "grid", placeItems: "center",
            border: "none", background: "transparent", cursor: "pointer", color: "var(--text-faint)", borderRadius: 8 }}>
            <Icon name="x" size={18} />
          </button>
        </div>
        {children}
      </div>
    </div>
  );
}
window.LTQ.Modal = Modal;
})();
