/* global Clerk */

const clerkKey = () => String(window.VIRAL_TENSION_CLERK_PUBLISHABLE_KEY || "").trim();
const usablePhoto = (url = "") => !!url && !/default|placeholder|blank/i.test(url);
const clerkReady = (() => {
  let loading = null;
  return () => {
    if (loading) return loading;
    loading = new Promise((resolve, reject) => {
      const load = async () => {
        if (!clerkKey()) {
          resolve(null);
          return;
        }
        if (typeof Clerk === "undefined") {
          window.setTimeout(load, 25);
          return;
        }
        try {
          await Clerk.load({ ui: { ClerkUI: window.__internal_ClerkUICtor } });
          resolve(Clerk);
        } catch (error) {
          reject(error);
        }
      };
      load();
    });
    return loading;
  };
})();

const primaryEmail = (user) => user && user.primaryEmailAddress && user.primaryEmailAddress.emailAddress || "";
const emailVerified = (user) => {
  const verification = user && user.primaryEmailAddress && user.primaryEmailAddress.verification;
  return Boolean(verification && verification.status === "verified");
};
const normalizeClerkUser = (user) => user ? ({
  uid: user.id,
  email: primaryEmail(user),
  emailVerified: emailVerified(user),
  displayName: user.fullName || [user.firstName, user.lastName].filter(Boolean).join(" ") || "VIRAL TENSION Listener",
  photoURL: usablePhoto(user.imageUrl) ? user.imageUrl : "",
  providerIds: (user.externalAccounts || []).map((account) => account.provider).filter(Boolean),
}) : null;

const tokenForRequest = async () => {
  const clerk = await clerkReady();
  return clerk && clerk.session ? clerk.session.getToken() : "";
};

window.AuthClient = {
  configured: () => !!clerkKey(),
  ready: clerkReady,
  watch: (callback) => {
    let remove = () => {};
    let intervalId = null;
    let cancelled = false;
    clerkReady().then((clerk) => {
      if (cancelled || !clerk) {
        callback(null);
        return;
      }
      let currentUserId = "";
      const sendUser = (nextUser = clerk.user) => {
        if (cancelled) return;
        const nextUserId = nextUser && nextUser.id || "";
        if (nextUserId === currentUserId) return;
        currentUserId = nextUserId;
        callback(normalizeClerkUser(nextUser));
        if (nextUser) {
          tokenForRequest()
            .then((token) => token && fetch("/api/auth-session", { method: "POST", headers: { Authorization: `Bearer ${token}` } }))
            .catch(() => {});
        } else {
          fetch("/api/auth-session", { method: "DELETE" }).catch(() => {});
        }
      };
      sendUser();
      if (typeof clerk.addListener === "function") {
        remove = clerk.addListener(({ user } = {}) => sendUser(user));
      } else {
        intervalId = window.setInterval(() => sendUser(), 500);
      }
    }).catch(() => callback(null));
    return () => {
      cancelled = true;
      remove();
      if (intervalId) window.clearInterval(intervalId);
    };
  },
  fetch: async (url, options = {}) => {
    const headers = new Headers(options.headers || {});
    const token = await tokenForRequest();
    if (token) headers.set("Authorization", `Bearer ${token}`);
    return fetch(url, { ...options, headers });
  },
  mountSignIn: async (node, { afterSignInUrl = "", afterSignUpUrl = "" } = {}) => {
    const clerk = await clerkReady();
    if (!clerk || !node) throw new Error("Clerk login is not configured yet.");
    clerk.mountSignIn(node, {
      routing: "hash",
      forceRedirectUrl: afterSignInUrl || undefined,
      signUpForceRedirectUrl: afterSignUpUrl || afterSignInUrl || undefined,
    });
    return () => clerk.unmountSignIn(node);
  },
  openUserProfile: async () => {
    const clerk = await clerkReady();
    if (clerk) clerk.openUserProfile();
  },
  signOut: async () => {
    const clerk = await clerkReady();
    if (clerk) await clerk.signOut();
    fetch("/api/auth-session", { method: "DELETE" }).catch(() => {});
  },
};
