// Cross-cutting infra: toast bus, error boundary, online detector.

// ─── Toast bus (vanilla, no React deps) ──────────────────────
const _toastListeners = new Set();
let _toastSeq = 0;
const toast = {
  show(msg, opts = {}) {
    const t = { id: ++_toastSeq, msg, type: opts.type || "info", action: opts.action || null, timeout: opts.timeout ?? 4000 };
    _toastListeners.forEach(fn => fn({ kind: "add", toast: t }));
    if (t.timeout > 0) setTimeout(() => toast.dismiss(t.id), t.timeout);
    return t.id;
  },
  dismiss(id) { _toastListeners.forEach(fn => fn({ kind: "remove", id })); },
  error(msg, opts) { return toast.show(msg, { ...opts, type: "error", timeout: opts?.timeout ?? 6000 }); },
  success(msg, opts) { return toast.show(msg, { ...opts, type: "success" }); },
  subscribe(fn) { _toastListeners.add(fn); return () => _toastListeners.delete(fn); },
};

function Toaster() {
  const [items, setItems] = React.useState([]);
  React.useEffect(() => toast.subscribe(ev => {
    if (ev.kind === "add") setItems(prev => [...prev, ev.toast]);
    if (ev.kind === "remove") setItems(prev => prev.filter(t => t.id !== ev.id));
  }), []);
  if (!items.length) return null;
  return (
    <div style={{
      position: "fixed", bottom: 20, left: "50%", transform: "translateX(-50%)",
      display: "flex", flexDirection: "column", gap: 8, zIndex: 9999,
      pointerEvents: "none", maxWidth: "92vw",
    }}>
      {items.map(t => {
        const bg = t.type === "error" ? "#9b1c1c" : t.type === "success" ? "#1a5e3a" : "var(--bx-ink-1)";
        return (
          <div key={t.id} style={{
            background: bg, color: "#fff",
            padding: "12px 18px", borderRadius: 10,
            fontSize: 13, fontWeight: 500, fontFamily: "Inter, sans-serif",
            boxShadow: "0 12px 32px -8px rgba(0,0,0,0.35)",
            display: "flex", alignItems: "center", gap: 12,
            pointerEvents: "auto", animation: "finanzasSlideUp 220ms cubic-bezier(0.16,1,0.3,1)",
          }}>
            <span>{t.msg}</span>
            {t.action && (
              <button onClick={() => { t.action.onClick(); toast.dismiss(t.id); }} style={{
                background: "rgba(255,255,255,0.15)", color: "#fff",
                border: "none", borderRadius: 6, padding: "6px 12px",
                fontSize: 12, fontWeight: 600, cursor: "pointer",
                fontFamily: "Inter, sans-serif", textTransform: "uppercase", letterSpacing: "0.04em",
              }}>{t.action.label}</button>
            )}
            <button onClick={() => toast.dismiss(t.id)} style={{
              background: "transparent", color: "rgba(255,255,255,0.7)",
              border: "none", cursor: "pointer", padding: 0, fontSize: 18, lineHeight: 1,
            }}>×</button>
          </div>
        );
      })}
    </div>
  );
}

// ─── Error boundary ──────────────────────────────────────────
class ErrorBoundary extends React.Component {
  constructor(props) { super(props); this.state = { error: null }; }
  static getDerivedStateFromError(error) { return { error }; }
  componentDidCatch(error, info) { console.error("[finanzas] React error", error, info); }
  reset = () => this.setState({ error: null });
  render() {
    if (!this.state.error) return this.props.children;
    return (
      <div style={{
        minHeight: "100vh", display: "flex", alignItems: "center", justifyContent: "center",
        background: "var(--bx-bg)", color: "var(--bx-ink-1)", padding: 24,
      }}>
        <div style={{
          maxWidth: 420, textAlign: "center",
          background: "var(--bx-paper)", border: "1px solid var(--bx-line)",
          borderRadius: 14, padding: 28,
        }}>
          <div style={{
            fontFamily: "Manrope, Inter, sans-serif",
            fontSize: 20, fontWeight: 800, color: "var(--bx-ink-1)",
          }}>Algo salió mal</div>
          <div style={{ fontSize: 13, color: "var(--bx-ink-3)", marginTop: 8, lineHeight: 1.5 }}>
            {String(this.state.error?.message || this.state.error || "Error desconocido")}
          </div>
          <div style={{ display: "flex", gap: 8, justifyContent: "center", marginTop: 20 }}>
            <button onClick={this.reset} style={{
              background: "var(--bx-navy-700)", color: "#fff",
              border: "none", borderRadius: 8, padding: "10px 18px",
              fontSize: 13, fontWeight: 600, cursor: "pointer",
            }}>Reintentar</button>
            <button onClick={() => location.reload()} style={{
              background: "transparent", color: "var(--bx-ink-2)",
              border: "1px solid var(--bx-line)", borderRadius: 8, padding: "10px 18px",
              fontSize: 13, fontWeight: 600, cursor: "pointer",
            }}>Recargar app</button>
          </div>
        </div>
      </div>
    );
  }
}

// ─── Online/offline hook + banner ────────────────────────────
function useOnline() {
  const [online, setOnline] = React.useState(typeof navigator !== "undefined" ? navigator.onLine : true);
  React.useEffect(() => {
    const on = () => setOnline(true);
    const off = () => setOnline(false);
    window.addEventListener("online", on);
    window.addEventListener("offline", off);
    return () => { window.removeEventListener("online", on); window.removeEventListener("offline", off); };
  }, []);
  return online;
}

function OfflineBanner() {
  const online = useOnline();
  if (online) return null;
  return (
    <div style={{
      position: "fixed", top: 0, left: 0, right: 0, zIndex: 9998,
      background: "#9b1c1c", color: "#fff",
      padding: "6px 14px", textAlign: "center",
      fontSize: 12, fontWeight: 600, fontFamily: "Inter, sans-serif",
      letterSpacing: "0.04em",
    }}>
      Sin conexión · los cambios se guardan localmente y se sincronizarán al volver
    </div>
  );
}

// ─── Splash ──────────────────────────────────────────────────
function FinanzasSplash() {
  return (
    <div style={{
      minHeight: "100vh", display: "flex", alignItems: "center", justifyContent: "center",
      background: "var(--bx-bg)", flexDirection: "column", gap: 14,
    }}>
      <div style={{
        fontFamily: "Bebas Neue, sans-serif",
        fontSize: 48, letterSpacing: "0.08em",
        color: "var(--bx-ink-1)",
      }}>FINANZAS</div>
      <div style={{
        width: 24, height: 24, borderRadius: 12,
        border: "2px solid var(--bx-line)",
        borderTopColor: "var(--bx-navy-700)",
        animation: "finanzasSpin 700ms linear infinite",
      }} />
    </div>
  );
}

Object.assign(window, { toast, Toaster, ErrorBoundary, useOnline, OfflineBanner, FinanzasSplash });
