import { fromPromise } from "xstate";

import type { LoginStatus } from "@/data/schemas/auth";
import { getAuthRepository } from "@/data/repositories/auth_repository";
import { fetchFacebookUserData } from "@/data/services";
import { AuthStorage } from "@/data/storage/auth/auth_storage";
import { UserStorage } from "@/data/storage/user/user_storage";
import { AuthPlatform, type AuthProvider } from "@/lib/auth/auth_platform";
import { Logger } from "@/utils/logger";
import { Result } from "@/utils/result";

import { readGuestId, readPsid } from "./storage";

const log = new Logger("AuthActors");

export const oauthSignInActor = fromPromise<void, AuthProvider>(async ({ input }) => {
  if (input === "google") {
    await AuthPlatform.googleSignIn();
  } else {
    await AuthPlatform.facebookSignIn();
  }
});

export const syncGoogleBackendActor = fromPromise<
  LoginStatus,
  { idToken: string }
>(async ({ input }) => {
  const authRepo = getAuthRepository();
  const guestId = await readGuestId();
  const psid = await readPsid();
  const result = await authRepo.googleLogin({
    idToken: input.idToken,
    guestId,
    psid,
  });
  if (Result.isErr(result)) throw result.error;
  return "google" as LoginStatus;
});

export const syncFacebookBackendActor = fromPromise<
  LoginStatus,
  { accessToken: string }
>(async ({ input }) => {
  const authRepo = getAuthRepository();
  const guestId = await readGuestId();
  const psid = await readPsid();
  const result = await authRepo.facebookLogin({
    accessToken: input.accessToken,
    guestId,
    psid,
  });
  if (Result.isErr(result)) throw result.error;

  await persistFacebookProfile(input.accessToken);
  return "facebook" as LoginStatus;
});

async function persistFacebookProfile(accessToken: string): Promise<void> {
  const fbR = await fetchFacebookUserData(accessToken);
  if (Result.isErr(fbR)) {
    log.warn(
      { err: fbR.error.message },
      "[auth-machine] syncFacebookBackendActor: fetchFacebookUserData failed (continuing anyway)",
    );
    return;
  }
  const fbUser = fbR.data;
  log.info(
    {
      hasId: !!fbUser.id,
      hasPicture: !!fbUser.pictureUrl,
    },
    "[auth-machine] syncFacebookBackendActor: Facebook profile fetched",
  );

  const authStorage = AuthStorage.getInstance();
  if (fbUser.id) {
    const result = await authStorage.setAsid(fbUser.id);
    if (!result.success) {
      log.warn(
        { err: result.error.message },
        "[auth-machine] syncFacebookBackendActor: setAsid failed",
      );
    }
  }

  if (fbUser.pictureUrl) {
    const result = await UserStorage.getInstance().setAvatarUrl(
      fbUser.pictureUrl,
    );
    if (!result.success) {
      log.warn(
        { err: result.error.message },
        "[auth-machine] syncFacebookBackendActor: setAvatarUrl failed",
      );
    }
  }
}
