/* Centralized BRAND for the Pass Studio.
   The vendor's shared identity (name, company, colors, logo, icon, hero) lives in one place on the
   backend (GET/PUT /api/brand). This gate resolves the brand BEFORE the studio mounts: if the
   vendor has none, it blocks with a "create your brand from a URL" onboarding; once a brand exists
   the studio seeds its pass from it (see seedFromBrand in PassStudio). A Brand screen (reopenable
   from the top bar) edits the shared brand; per-surface pass tweaks never touch it. */
// NB: these are top-level in a shared-global Babel script, so names must NOT collide with globals
// declared by sibling scripts (BuilderForm.jsx defines top-level GenerateDesignModal /
// RoleColorPicker) — hence the B-prefixed aliases.
const BR = window.SpoonityWalletPassDesignSystem_de20b8;
const BRolePicker = window.StudioRoleColorPicker;
const BImageUpload = window.StudioImageUpload;
const BIconUpload = window.StudioIconUpload;
const BFieldLabel = window.StudioFieldLabel;
const effColors = window.studioEffectiveColors;
const BGenerateModal = window.StudioGenerateDesignModal;

// GenerateDesignModal emits a pass-shaped patch (backgroundColor, logoSrc, brandColors, ...);
// translate it to the Brand's own field names (colors.background, logo, palette, ...).
function patchToBrand(patch) {
  const eff = effColors({ backgroundColor: patch.backgroundColor });
  return {
    name: patch.name || patch.company || undefined,
    company: patch.company || undefined,
    colors: { background: eff.background, foreground: eff.foreground, label: eff.label },
    logo: patch.logoSrc || undefined,
    icon: patch.iconSrc || undefined,
    hero: patch.stripSrc || undefined,
    sourceUrl: patch.sourceUrl || undefined,
    palette: patch.brandColors || undefined,
  };
}

// ---- shared store: the current brand + a way to reopen the editor from anywhere (top bar) ----
window.SpoonityBrand = {
  current: null,
  get() { return this.current; },
  // Resolve the merchant's display name at CALL TIME — never at script-load time, since that's
  // before login/brand-fetch complete. Priority: Brand.company -> Brand.name -> the Spoonity
  // vendor's name from the session -> a neutral fallback. Never the demo "Breakfast Bonanza".
  // Null-safe: SpoonityBrand.current, window.SpoonityAuth, and the session may each be absent
  // (e.g. this file isn't even loaded on every page that reuses BuilderForm.jsx).
  merchantName() {
    const b = window.SpoonityBrand.current;
    if (b && b.company) return b.company;
    if (b && b.name) return b.name;
    try {
      const session = window.SpoonityAuth && window.SpoonityAuth.getSession();
      if (session && session.vendor && session.vendor.name) return session.vendor.name;
    } catch (e) {}
    return "Your Company";
  },
  _open: null,
  setOpener(fn) { this._open = fn; },
  openEditor() { if (this._open) this._open(); },
  // Best guess at the merchant's website, for the "create your brand from a URL" step. The brand's
  // own sourceUrl (set the last time they ran that step) wins; otherwise fall back to the website
  // on their Spoonity vendor profile, which the backend now returns with the login catalog. Null
  // when we know of neither — the field is then just empty, as before.
  websiteUrl() {
    const b = window.SpoonityBrand.current;
    if (b && b.sourceUrl) return b.sourceUrl;
    try {
      const catalog = window.SpoonityAuth && window.SpoonityAuth.catalog && window.SpoonityAuth.catalog();
      if (catalog && catalog.website) return catalog.website;
    } catch (e) {}
    return null;
  },
  listeners: [],
  onChange(fn) { this.listeners.push(fn); return () => { this.listeners = this.listeners.filter((x) => x !== fn); }; },
  _notify() { this.listeners.forEach((fn) => { try { fn(this.current); } catch (e) {} }); },
};

const brandEndpoint = () => (window.SpoonityAuth ? window.SpoonityAuth.getEndpoint() : "");

async function fetchBrand() {
  const r = await fetch(brandEndpoint() + "/api/brand", { credentials: "include" });
  if (r.status === 404) return { none: true };
  if (!r.ok) throw new Error("brand fetch " + r.status);
  return { brand: await r.json() };
}
async function saveBrand(body) {
  const r = await fetch(brandEndpoint() + "/api/brand", {
    method: "PUT", credentials: "include",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(body),
  });
  if (!r.ok) throw new Error((await r.json().catch(() => ({}))).error || ("brand save " + r.status));
  return r.json();
}

/* The editable Brand screen (also the onboarding target). `mode` = "onboard" | "edit". */
function BrandScreen({ initial, mode, accent, onSaved, onClose }) {
  const [b, setB] = React.useState(initial || {});
  const [saving, setSaving] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const [genOpen, setGenOpen] = React.useState(mode === "onboard");

  // RoleColorPicker speaks the pass color vocabulary; adapt to/from the brand shape.
  const pseudoPass = {
    backgroundColor: (b.colors && b.colors.background) || undefined,
    foregroundColor: (b.colors && b.colors.foreground) || undefined,
    labelColor: (b.colors && b.colors.label) || undefined,
    logoSrc: b.logo, iconSrc: b.icon, stripSrc: b.hero,
    brandColors: b.palette || undefined,
  };
  const setColors = (patch) => setB((p) => {
    const colors = { ...(p.colors || {}) };
    if ("backgroundColor" in patch) colors.background = patch.backgroundColor;
    if ("foregroundColor" in patch) colors.foreground = patch.foregroundColor;
    if ("labelColor" in patch) colors.label = patch.labelColor;
    return { ...p, colors };
  });

  const save = async () => {
    setSaving(true); setErr(null);
    try {
      const saved = await saveBrand({
        name: b.name || "", company: b.company || "",
        colors: b.colors || null, logo: b.logo || null, icon: b.icon || null, hero: b.hero || null,
        sourceUrl: b.sourceUrl || undefined,
        palette: b.palette || undefined,
      });
      window.SpoonityBrand.current = saved;
      onSaved(saved);
    } catch (e) { setErr(e.message); setSaving(false); }
  };

  const field = { display: "flex", flexDirection: "column", gap: 6, marginBottom: 14 };
  return ReactDOM.createPortal(
    <div style={{ position: "fixed", inset: 0, zIndex: 4000, background: "rgba(17,24,39,.55)", display: "flex", alignItems: "center", justifyContent: "center", padding: 20 }}
      onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div style={{ background: "var(--surface-base)", borderRadius: 18, width: 460, maxWidth: "94vw", maxHeight: "88vh", overflow: "hidden", boxShadow: "0 24px 60px -12px rgba(0,0,0,.4)", display: "flex", flexDirection: "column" }}>
        <div style={{ overflowY: "auto", padding: 24, flex: 1 }}>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 6 }}>
          <span style={{ fontSize: 17, fontWeight: 700, color: "var(--typography-primary)" }}>{mode === "onboard" ? "Create your brand" : "Brand"}</span>
          {/* Always allow closing without saving (onboarding included) — the hub handles "no brand yet". */}
          <button onClick={onClose} aria-label="Close" style={{ border: "none", background: "none", cursor: "pointer", fontSize: 18, color: "var(--typography-tertiary)", padding: 4, lineHeight: 1 }}>✕</button>
        </div>
        <p style={{ fontSize: 12.5, color: "var(--typography-secondary)", lineHeight: 1.5, marginTop: 0, marginBottom: 18 }}>
          Your brand is shared by your wallet passes and your enrollment site. Set it once here; each design can still be customized on top of it.
        </p>

        <button type="button" onClick={() => setGenOpen(true)}
          style={{ width: "100%", padding: "10px", borderRadius: 10, border: `1.5px solid ${accent}`, background: "transparent", cursor: "pointer", fontFamily: "var(--font-sans)", fontSize: 13, fontWeight: 600, color: accent, marginBottom: 18 }}>
          ✨ {mode === "onboard" ? "Create from your website URL" : "Regenerate from a website URL"}
        </button>

        <div style={field}>
          <BFieldLabel>Company</BFieldLabel>
          {/* This IS the brand editor, so brand-derived sources are usually empty here — the
              placeholder falls through to the Spoonity vendor's name. Never prefills the VALUE. */}
          <BR.Input value={b.company || ""} placeholder={window.SpoonityBrand.merchantName()} onChange={(e) => setB((p) => ({ ...p, company: e.target.value }))} />
        </div>
        {/* No "Program name" field here on purpose — a company can run several differently-named
            reward programs, so program name is edited per-pass, not centralized in the Brand. */}

        <BFieldLabel>Brand colors</BFieldLabel>
        <div style={{ margin: "8px 0 16px" }}>
          <BRolePicker pass={pseudoPass} set={setColors} accent={accent} />
        </div>

        <BFieldLabel>Logo</BFieldLabel>
        <div style={{ margin: "6px 0 14px" }}>
          <BImageUpload src={b.logo} previewH={56} onUpload={(d) => setB((p) => ({ ...p, logo: d }))} onClear={() => setB((p) => ({ ...p, logo: null }))} />
        </div>
        <BFieldLabel>Icon</BFieldLabel>
        <div style={{ margin: "6px 0 14px" }}>
          <BIconUpload src={b.icon} onUpload={(d) => setB((p) => ({ ...p, icon: d }))} onClear={() => setB((p) => ({ ...p, icon: null }))} />
        </div>
        <BFieldLabel>Hero image</BFieldLabel>
        <div style={{ margin: "6px 0 16px" }}>
          <BImageUpload src={b.hero} previewH={56} cropTo={{ w: 1125, h: 432 }} onUpload={(d) => setB((p) => ({ ...p, hero: d }))} onClear={() => setB((p) => ({ ...p, hero: null }))} />
        </div>

        {err && <div style={{ color: "var(--critical,#c3223f)", fontSize: 12, marginBottom: 10 }}>{err}</div>}
        <BR.Button style={{ width: "100%", background: accent, color: "#fff" }} onClick={save} disabled={saving}>
          {saving ? "Saving…" : mode === "onboard" ? "Create brand" : "Save brand"}
        </BR.Button>

        </div>
      </div>
      {genOpen && BGenerateModal && (
        <BGenerateModal accent={accent}
          initialUrl={b.sourceUrl || window.SpoonityBrand.websiteUrl() || ""}
          onApply={(patch) => {
            const mapped = patchToBrand(patch);
            setB((p) => ({ ...p, ...mapped, colors: { ...(p.colors || {}), ...mapped.colors } }));
            setGenOpen(false);
          }}
          onClose={() => setGenOpen(false)} />
      )}
    </div>,
    document.body
  );
}

/* Gate: load the vendor's brand (non-blocking) so the hub/studio can seed from it, and expose a
   reopenable Brand screen. The hub surfaces the "create your brand" CTA when none exists, so we
   don't hard-block here. */
function SpoonityBrandGate({ children, accent = "#ff7e3d" }) {
  const [status, setStatus] = React.useState("loading"); // loading | ready
  const [editing, setEditing] = React.useState(false);

  React.useEffect(() => {
    let alive = true;
    fetchBrand()
      .then((r) => {
        if (!alive) return;
        if (!r.none) window.SpoonityBrand.current = r.brand;
        setStatus("ready");
      })
      .catch(() => { if (alive) setStatus("ready"); }); // never hard-block on a fetch hiccup
    window.SpoonityBrand.setOpener(() => setEditing(true));
    return () => { alive = false; };
  }, []);

  if (status === "loading") {
    return React.createElement("div", { style: { position: "fixed", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", background: "var(--surface-base)", color: "var(--typography-tertiary)", fontFamily: "var(--font-sans)", fontSize: 13 } }, "Loading…");
  }
  // "onboard" mode (auto-opens the URL extractor) when the vendor has no brand yet; else "edit".
  const mode = window.SpoonityBrand.current ? "edit" : "onboard";
  return (
    <React.Fragment>
      {children}
      {editing && (
        <BrandScreen mode={mode} accent={accent} initial={window.SpoonityBrand.current || {}}
          onSaved={(b) => { window.SpoonityBrand.current = b; window.SpoonityBrand._notify(); setEditing(false); }}
          onClose={() => setEditing(false)} />
      )}
    </React.Fragment>
  );
}

window.SpoonityBrandGate = SpoonityBrandGate;
