import { useState as b, useCallback as u, useMemo as P, useEffect as j } from "react";
import { FrankUser as J } from "@frank-auth/sdk";
import { useAuth as M } from "./use-auth.js";
import { useConfig as V } from "../provider/config-provider.js";
function N() {
  return typeof window < "u" && "navigator" in window && "credentials" in navigator && "create" in navigator.credentials && "get" in navigator.credentials;
}
async function Y() {
  if (!N()) return !1;
  try {
    return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
  } catch {
    return !1;
  }
}
function E(r) {
  const t = r.replace(/-/g, "+").replace(/_/g, "/"), n = t.padEnd(t.length + (4 - t.length % 4) % 4, "="), l = atob(n), f = new ArrayBuffer(l.length), p = new Uint8Array(f);
  for (let a = 0; a < l.length; a++)
    p[a] = l.charCodeAt(a);
  return f;
}
function k(r) {
  const t = new Uint8Array(r);
  let n = "";
  for (let l = 0; l < t.byteLength; l++)
    n += String.fromCharCode(t[l]);
  return btoa(n).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
}
function G(r) {
  return {
    ...r,
    challenge: E(r.challenge),
    user: {
      ...r.user,
      id: E(r.user.id)
    },
    excludeCredentials: r.excludeCredentials?.map((t) => ({
      ...t,
      id: E(t.id)
    }))
  };
}
function Q(r) {
  return {
    ...r,
    challenge: E(r.challenge),
    allowCredentials: r.allowCredentials?.map((t) => ({
      ...t,
      id: E(t.id)
    }))
  };
}
function T(r) {
  const t = r.response, n = {
    id: r.id,
    rawId: k(r.rawId),
    type: r.type,
    response: {
      clientDataJSON: k(t.clientDataJSON)
    }
  };
  return t instanceof AuthenticatorAttestationResponse ? n.response.attestationObject = k(t.attestationObject) : t instanceof AuthenticatorAssertionResponse && (n.response.authenticatorData = k(t.authenticatorData), n.response.signature = k(t.signature), t.userHandle && (n.response.userHandle = k(t.userHandle))), n;
}
function F() {
  const { user: r, session: t, userType: n } = M(), { apiUrl: l, publishableKey: f, features: p } = V(), [a, C] = b([]), [w, c] = b(!1), [K, y] = b(null), [W, L] = b(!1), i = P(() => t?.accessToken ? new J({
    publishableKey: f,
    apiUrl: l,
    userType: n ?? "end_user"
  }, t.accessToken) : null, [f, l, t?.accessToken]), g = P(() => N(), []), A = P(() => p.passkeys, [p.passkeys]), d = u((e) => {
    const s = {
      code: e.code || "UNKNOWN_ERROR",
      message: e.message || "An unknown error occurred",
      details: e.details,
      field: e.field
    };
    throw y(s), s;
  }, []), S = u(async () => {
    if (!g) return !1;
    try {
      const e = await Y();
      return L(e), e;
    } catch {
      return L(!1), !1;
    }
  }, [g]), h = u(async () => {
    if (!(!i || !r || !A))
      try {
        c(!0), y(null);
        const e = await i.listPasskeys();
        C(e.data || []);
      } catch (e) {
        console.error("Failed to load passkeys:", e), y({
          code: "PASSKEYS_LOAD_FAILED",
          message: "Failed to load passkeys"
        });
      } finally {
        c(!1);
      }
  }, [i, r, A]);
  j(() => {
    S(), h();
  }, [S, h]);
  const v = u(async (e) => {
    if (!i) throw new Error("User not authenticated");
    if (!g) throw new Error("WebAuthn not supported");
    if (!A) throw new Error("Passkeys not enabled");
    try {
      c(!0), y(null);
      const s = await i.beginPasskeyRegistration({
        name: e || `Passkey ${a.length + 1}`
      }), o = G(s.options);
      return {
        challenge: s.challenge,
        options: o,
        sessionId: s.sessionId
      };
    } catch (s) {
      return d(s);
    } finally {
      c(!1);
    }
  }, [i, g, A, a.length, d]), U = u(async (e, s) => {
    if (!i) throw new Error("User not authenticated");
    try {
      c(!0), y(null);
      const o = T(s), D = {
        sessionId: e.sessionId,
        credential: o
      }, m = await i.finishPasskeyRegistration(D);
      return await h(), m.passkey;
    } catch (o) {
      return d(o);
    } finally {
      c(!1);
    }
  }, [i, h, d]), _ = u(async (e) => {
    const s = await v(e);
    try {
      const o = await navigator.credentials.create({
        publicKey: s.options
      });
      if (!o)
        throw new Error("Failed to create credential");
      return await U(s, o);
    } catch (o) {
      throw o.name === "NotAllowedError" ? new Error("User cancelled the registration process") : o.name === "InvalidStateError" ? new Error("This authenticator is already registered") : new Error(`Registration failed: ${o.message}`);
    }
  }, [v, U]), I = u(async () => {
    if (!i) throw new Error("User not authenticated");
    if (!g) throw new Error("WebAuthn not supported");
    try {
      c(!0), y(null);
      const e = await i.beginPasskeyAuthentication(), s = Q(e.options);
      return {
        challenge: e.challenge,
        options: s,
        sessionId: e.sessionId
      };
    } catch (e) {
      return d(e);
    } finally {
      c(!1);
    }
  }, [i, g, d]), R = u(async (e, s) => {
    if (!i) throw new Error("User not authenticated");
    try {
      c(!0), y(null);
      const o = T(s), D = {
        sessionId: e.sessionId,
        credential: o
      }, m = await i.finishPasskeyAuthentication(D);
      return {
        success: !0,
        session: m.session,
        user: m.user
      };
    } catch (o) {
      return {
        success: !1,
        error: o.message
      };
    } finally {
      c(!1);
    }
  }, [i, d]), z = u(async () => {
    const e = await I();
    try {
      const s = await navigator.credentials.get({
        publicKey: e.options
      });
      if (!s)
        throw new Error("Failed to get credential");
      return await R(e, s);
    } catch (s) {
      return s.name === "NotAllowedError" ? {
        success: !1,
        error: "User cancelled the authentication process"
      } : {
        success: !1,
        error: `Authentication failed: ${s.message}`
      };
    }
  }, [I, R]), O = u(async (e, s) => {
    if (!i) throw new Error("User not authenticated");
    try {
      c(!0), y(null);
      const o = await i.updatePasskey(e, s);
      return await h(), o.passkey;
    } catch (o) {
      return d(o);
    } finally {
      c(!1);
    }
  }, [i, h, d]), B = u(async (e) => {
    if (!i) throw new Error("User not authenticated");
    try {
      c(!0), y(null), await i.deletePasskey(e), await h();
    } catch (s) {
      d(s);
    } finally {
      c(!1);
    }
  }, [i, h, d]), q = u(async (e, s) => O(e, { name: s }), [O]), x = u(async () => {
    await h();
  }, [h]), H = P(() => a.find((e) => e.isPrimary) || a[0] || null, [a]), $ = P(() => a.length, [a]);
  return {
    // Passkey state
    passkeys: a,
    isSupported: g,
    isAvailable: W,
    isLoaded: !!r && A,
    isLoading: w,
    error: K,
    // Passkey registration
    beginRegistration: v,
    finishRegistration: U,
    registerPasskey: _,
    // Passkey authentication
    beginAuthentication: I,
    finishAuthentication: R,
    authenticateWithPasskey: z,
    // Passkey management
    updatePasskey: O,
    deletePasskey: B,
    renamePasskey: q,
    // Passkey information
    primaryPasskey: H,
    passkeyCount: $,
    // Utility methods
    refreshPasskeys: x,
    checkSupport: S
  };
}
function se() {
  const {
    registerPasskey: r,
    isSupported: t,
    isAvailable: n,
    isLoading: l,
    error: f
  } = F(), [p, a] = b("idle");
  return {
    register: u(async (w) => {
      if (!t || !n)
        throw a("error"), new Error("Passkeys not supported or available");
      try {
        a("registering");
        const c = await r(w);
        return a("success"), c;
      } catch (c) {
        throw a("error"), c;
      }
    }, [r, t, n]),
    state: p,
    isSupported: t,
    isAvailable: n,
    isLoading: l,
    error: f,
    canRegister: t && n && !l
  };
}
function re() {
  const {
    authenticateWithPasskey: r,
    isSupported: t,
    isAvailable: n,
    isLoading: l,
    error: f
  } = F(), [p, a] = b("idle");
  return {
    authenticate: u(async () => {
      if (!t || !n)
        throw a("error"), new Error("Passkeys not supported or available");
      try {
        a("authenticating");
        const w = await r();
        return w.success ? a("success") : a("error"), w;
      } catch (w) {
        throw a("error"), w;
      }
    }, [r, t, n]),
    state: p,
    isSupported: t,
    isAvailable: n,
    isLoading: l,
    error: f,
    canAuthenticate: t && n && !l
  };
}
export {
  re as usePasskeyAuthentication,
  se as usePasskeyRegistration,
  F as usePasskeys
};
//# sourceMappingURL=use-passkeys.js.map
