function LoginStep({ data }) {
  const [stage, setStage] = React.useState("collect");
  const [mfaTicket, setMfaTicket] = React.useState(null);
  const [err, setErr] = React.useState(null);
  const [busy, setBusy] = React.useState(false);

  async function tryPasswordFlow(email, password) {
    setErr(null); setBusy(true);
    try {
      const Mod = window.OpaqueModule;
      if (!Mod) throw new Error("OPAQUE client not loaded.");
      const cfg = Mod.getOpaqueConfig
        ? Mod.getOpaqueConfig(Mod.OpaqueID.OPAQUE_P256)
        : new Mod.OpaqueConfig(Mod.OpaqueID.OPAQUE_P256);
      const client = new Mod.OpaqueClient(cfg);
      const ke1 = await client.authInit(password);
      if (ke1 instanceof Error) throw ke1;
      const r1 = await fetch(`${window.__bs_api}/api/auth/login/ke1`, {
        method: "POST", credentials: "include",
        headers: { "content-type": "application/json", "x-csrf-token": window.__bs_csrf },
        body: JSON.stringify({
          email,
          ke1: btoa(String.fromCharCode.apply(null, ke1.serialize())),
        }),
      });
      const { ke2, login_session_id } = await r1.json();
      const ke2Bytes = Uint8Array.from(atob(ke2), c => c.charCodeAt(0));
      const ke2Obj = Mod.KE2.deserialize(cfg, Array.from(ke2Bytes));
      const finish = await client.authFinish(ke2Obj, "blockscanner", email);
      if (finish instanceof Error) throw new Error("Wrong email or password.");
      const r2 = await fetch(`${window.__bs_api}/api/auth/login/ke3`, {
        method: "POST", credentials: "include",
        headers: { "content-type": "application/json", "x-csrf-token": window.__bs_csrf },
        body: JSON.stringify({
          login_session_id,
          ke3: btoa(String.fromCharCode.apply(null, finish.ke3.serialize())),
        }),
      });
      if (!r2.ok) { setErr("Wrong email or password."); return; }
      const { mfa_ticket } = await r2.json();
      setMfaTicket(mfa_ticket); setStage("mfa");
    } catch (e) {
      setErr(e.message || String(e));
    } finally {
      setBusy(false);
    }
  }

  async function tryPasskeyFlow() {
    setErr(null); setBusy(true);
    try {
      const optsRes = await fetch(`${window.__bs_api}/api/auth/login/passkey/options`, {
        method: "POST", credentials: "include",
        headers: { "content-type": "application/json", "x-csrf-token": window.__bs_csrf },
        body: "{}",
      });
      if (!optsRes.ok) throw new Error("Could not fetch passkey options.");
      const { options, challenge_key } = await optsRes.json();
      const assertion = await navigator.credentials.get({ publicKey: options });
      const r = await fetch(`${window.__bs_api}/api/auth/login/passkey/verify`, {
        method: "POST", credentials: "include",
        headers: { "content-type": "application/json", "x-csrf-token": window.__bs_csrf },
        body: JSON.stringify({ challenge_key, response: assertion }),
      });
      if (!r.ok) { setErr("Passkey login failed."); return; }
      location.assign("/");
    } catch (e) {
      setErr(e.message || String(e));
    } finally {
      setBusy(false);
    }
  }

  if (stage === "mfa") return <MfaVerifyStep mfaTicket={mfaTicket} />;
  return (
    <form className="bs-form bs-auth-form" onSubmit={(e) => {
      e.preventDefault();
      const f = new FormData(e.currentTarget);
      tryPasswordFlow(f.get("email"), f.get("password"));
    }}>
      <label className="bs-formfield">
        <span>Email</span>
        <input type="email" name="email" required autoComplete="username webauthn" />
      </label>
      <label className="bs-formfield">
        <span>Password</span>
        <input type="password" name="password" required autoComplete="current-password webauthn" />
      </label>
      <button type="submit" className="bs-formsubmit" disabled={busy}>Sign in</button>
      <button type="button" className="bs-formsubmit bs-formsubmit-alt" disabled={busy}
              onClick={tryPasskeyFlow}>Sign in with passkey</button>
      {err && <p className="bs-auth-error">{err}</p>}
    </form>
  );
}
window.LoginStep = LoginStep;
