/* ============================================================================
   DIVONCI WORLD — DATA HOOKS + BACKEND-STATE PRIMITIVES  (dw-hooks.jsx)
   ----------------------------------------------------------------------------
   The ONLY way screens touch backend-fed data. useResource() wires DW.get +
   DW.subscribe and hands back { data, loading, error, refetch }. Every screen
   that reads from the seam renders <LoadingState/>, <EmptyState/>, <ErrorState/>
   for the three non-happy paths — no screen assumes data is present.
   ========================================================================== */
const { useState: useStateH, useEffect: useEffectH, useCallback: useCallbackH, useRef: useRefH } = React;

/* useResource(resource, params, opts)
   - resource : backend table name (DW.RESOURCES)
   - params   : passed to DW.get (id / eq / where / search / sort / limit)
   - opts.channel : realtime channel to subscribe to (defaults to `resource`)
   - opts.live    : re-fetch on realtime events (default true)
*/
function useResource(resource, params, opts = {}) {
  const { channel, live = true } = opts;
  const [data, setData] = useStateH(null);
  const [loading, setLoading] = useStateH(true);
  const [error, setError] = useStateH(null);
  const paramKey = JSON.stringify(params || {});
  const mounted = useRefH(true);

  const load = useCallbackH((soft) => {
    if (!soft) setLoading(true);
    DW.get(resource, params || {})
      .then((rows) => { if (!mounted.current) return; setData(rows); setError(null); setLoading(false); })
      .catch((e) => { if (!mounted.current) return; setError(e); setLoading(false); });
  }, [resource, paramKey]); // eslint-disable-line

  useEffectH(() => {
    mounted.current = true;
    load(false);
    let unsub;
    if (live) unsub = DW.subscribe(channel || resource, () => load(true));
    return () => { mounted.current = false; unsub && unsub(); };
  }, [resource, paramKey]); // eslint-disable-line

  return { data, loading, error, refetch: () => load(false) };
}

/* useAuth — current user/role + a re-render on role change */
function useAuth() {
  const [, force] = useStateH(0);
  useEffectH(() => DW.subscribe("auth", () => force((n) => n + 1)), []);
  return { ...DW.auth, can: (area) => DW.can(DW.auth.user.role, area), signInAs: DW.signInAs };
}

/* ── backend-state primitives ─────────────────────────────────────────────── */
function StateWrap({ children }) {
  return <div style={{ display: "grid", placeItems: "center", minHeight: 200, padding: "var(--s-9)" }}>{children}</div>;
}

function LoadingState({ label = "Loading", lines = 3 }) {
  return (
    <div className="dw-state" role="status" aria-live="polite">
      <div className="dw-skel-head">
        <span className="dw-spin" />
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--ink-3)" }}>{label}…</span>
      </div>
      <div className="dw-skel-rows">
        {Array.from({ length: lines }).map((_, i) => (
          <div key={i} className="dw-skel" style={{ animationDelay: i * 0.12 + "s" }} />
        ))}
      </div>
    </div>
  );
}

function EmptyState({ icon = "foundry", title = "Nothing here yet", hint, action }) {
  return (
    <StateWrap>
      <div style={{ textAlign: "center", maxWidth: 360 }}>
        <div className="dw-empty-ic">{typeof Icon === "function" ? <Icon name={icon} style={{ width: 22, height: 22, color: "var(--ink-4)" }} /> : null}</div>
        <div style={{ fontFamily: "var(--font-display)", fontWeight: 600, fontSize: 16, marginBottom: 6 }}>{title}</div>
        {hint && <div style={{ color: "var(--ink-3)", fontSize: 13, lineHeight: 1.5 }}>{hint}</div>}
        {action && <div style={{ marginTop: 16 }}>{action}</div>}
      </div>
    </StateWrap>
  );
}

function ErrorState({ error, onRetry, label = "Could not reach the seam" }) {
  return (
    <StateWrap>
      <div style={{ textAlign: "center", maxWidth: 380 }}>
        <div className="dw-empty-ic" style={{ boxShadow: "var(--glow-crisis)", borderColor: "transparent" }}>
          {typeof Icon === "function" ? <Icon name="risk" style={{ width: 22, height: 22, color: "var(--state-crisis)" }} /> : null}
        </div>
        <div style={{ fontFamily: "var(--font-display)", fontWeight: 600, fontSize: 16, marginBottom: 6 }}>{label}</div>
        <div style={{ color: "var(--ink-3)", fontSize: 12.5, fontFamily: "var(--font-mono)", marginBottom: 16 }}>
          {(error && error.message) || "Unknown error"} · DW.get failed
        </div>
        {onRetry && <button className="btn" onClick={onRetry}><Icon name="refresh" className="glyph" style={{ width: 13, height: 13 }} /> Retry</button>}
      </div>
    </StateWrap>
  );
}

/* Resource — declarative wrapper that renders the right state for a query.
   <Resource of="clients" params={…}>{(rows) => <List rows={rows}/>}</Resource>
*/
function Resource({ of, params, opts, empty, loadingLines, children }) {
  const { data, loading, error, refetch } = useResource(of, params, opts);
  if (loading) return <LoadingState lines={loadingLines} label={"Loading " + of.replace(/_/g, " ")} />;
  if (error) return <ErrorState error={error} onRetry={refetch} />;
  if (!data || (Array.isArray(data) && data.length === 0)) return empty || <EmptyState />;
  return children(data, refetch);
}

Object.assign(window, { useResource, useAuth, LoadingState, EmptyState, ErrorState, Resource });
