function SignupStep({ onDone, data }) {
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const formRef = React.useRef(null);

  // Per-mount: read ?invite= from the URL and prefill the invite_code input,
  // locking it so the recipient can't accidentally edit a token they were given.
  React.useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const fromUrl = params.get("invite");
    if (!fromUrl || !formRef.current) return;
    const input = formRef.current.querySelector('input[name="invite_code"]');
    if (!input) return;
    input.value = fromUrl;
    input.readOnly = true;
    input.classList.add("bs-formfield-locked");
  }, []);

  const mode = (window.FEATURES && window.FEATURES.signup_mode) || "invite_only";

  if (mode === "closed") {
    return (
      <div className="bs-auth-blocked">
        <p>Account creation is temporarily closed for maintenance. Please check back later.</p>
      </div>
    );
  }

  async function onSubmit(e) {
    e.preventDefault();
    setErr(null); setBusy(true);
    try {
      const form = new FormData(e.currentTarget);
      const inviteCode = (form.get("invite_code") || "").toString().trim();
      const body = {
        email: form.get("email"),
        name: form.get("name"),
        organization: form.get("org"),
        hcaptcha_token: (window.hcaptcha && typeof window.hcaptcha.getResponse === "function")
          ? window.hcaptcha.getResponse()
          : "",
        _hp: form.get("_hp") || "",
        form_token: window.__bs_form_token,
        fingerprint: await window.__bs_fingerprint,
      };
      if (inviteCode) body.invite_code = inviteCode;
      const res = await fetch(`${window.__bs_api}/api/auth/signup/start`, {
        method: "POST",
        credentials: "include",
        headers: { "content-type": "application/json", "x-csrf-token": window.__bs_csrf },
        body: JSON.stringify(body),
      });
      if (!res.ok) {
        // Surface server-side gating errors directly so the user knows whether
        // they need an invite, were closed out, or carried a stale token.
        let detail = `Signup failed (${res.status}).`;
        try {
          const j = await res.json();
          if (j.error === "invite_required") detail = "An invite is required to create an account.";
          else if (j.error === "invite_invalid") detail = "That invite is no longer valid.";
          else if (j.error === "signup_closed") detail = "Signups are temporarily closed.";
          else if (j.error) detail = `Signup failed: ${j.error}.`;
        } catch {/* keep the generic fallback */}
        throw new Error(detail);
      }
      onDone();
    } catch (e) {
      setErr(e.message || String(e));
    } finally {
      setBusy(false);
    }
  }

  // Filter fields based on signup_mode. In open mode the invite_code field is
  // hidden entirely; in invite_only it is shown (and required unless the URL
  // already prefilled it, which the effect above handles by locking the input).
  const fields = (data.fields || []).filter((f) => {
    if (f.name !== "invite_code") return true;
    return mode === "invite_only";
  });

  return (
    <form ref={formRef} className="bs-form bs-auth-form" onSubmit={onSubmit}>
      {fields.map((f) => (
        <label key={f.name} className="bs-formfield">
          <span>{f.label}</span>
          <input
            type={f.type}
            name={f.name}
            required={f.name === "invite_code" ? mode === "invite_only" : f.required}
          />
          {f.hint && <small className="bs-auth-hint">{f.hint}</small>}
        </label>
      ))}
      <input
        type="text" name="_hp" tabIndex="-1" autoComplete="off" aria-hidden="true"
        style={{ position: "absolute", left: "-9999px" }}
      />
      <div className="h-captcha" data-sitekey={window.__bs_hcaptcha_sitekey}></div>
      <button type="submit" className="bs-formsubmit" disabled={busy}>
        {data.primaryCta}
      </button>
      {err && <p className="bs-auth-error">{err}</p>}
      {data.legal && <p className="bs-auth-legal">{data.legal}</p>}
    </form>
  );
}
window.SignupStep = SignupStep;
