import { fromPromise } from "xstate";

import type { LoginStatus } from "@/data/schemas/auth";
import { getAuthRepository } from "@/data/repositories/auth_repository";
import { AuthStorage } from "@/data/storage/auth/auth_storage";
import { UserStorage } from "@/data/storage/user/user_storage";
import { hasCompleteBusinessAuthSession } from "@/lib/auth/auth_session";
import { deviceIdentifier } from "@/utils/device_identifier";
import { Logger } from "@/utils/logger";
import { Result } from "@/utils/result";

const log = new Logger("AuthActors");

export const logoutActor = fromPromise<LoginStatus>(async () => {
  const result = await getAuthRepository().logout();
  if (Result.isErr(result)) throw result.error;
  return "guest" as LoginStatus;
});

export const guestLoginActor = fromPromise<LoginStatus, void>(async () => {
  log.debug("[auth-machine] guestLoginActor ENTRY");

  const hasTokenR = await AuthStorage.getInstance().hasGuestToken();
  log.debug("[auth-machine] guestLoginActor hasGuestToken", {
    success: hasTokenR.success,
    hasData: hasTokenR.success ? !!hasTokenR.data : null,
  });
  if (hasTokenR.success && hasTokenR.data) {
    log.debug("[auth-machine] guestLoginActor SHORT-CIRCUIT (has local guestToken) → return guest");
    return "guest" as LoginStatus;
  }

  const deviceId = await deviceIdentifier.getDeviceId();
  log.debug("[auth-machine] guestLoginActor deviceId", {
    length: deviceId.length,
    prefix: deviceId.slice(0, 8),
  });

  log.debug("[auth-machine] guestLoginActor calling authRepo.guestLogin");
  const result = await getAuthRepository().guestLogin(deviceId);
  log.debug("[auth-machine] guestLoginActor authRepo.guestLogin DONE", {
    success: result.success,
    hasData: result.success ? !!result.data : null,
    errorName: result.success ? null : result.error?.name,
    errorMessage: result.success ? null : result.error?.message,
  });
  if (Result.isErr(result)) throw result.error;
  return "guest" as LoginStatus;
});

export const checkAuthStatusActor = fromPromise<LoginStatus, void>(async () => {
  const storage = AuthStorage.getInstance();
  const asidR = await storage.getAsid();
  const psidR = await storage.getPsid();
  const asid = asidR.success ? asidR.data : null;
  const psid = psidR.success ? psidR.data : null;
  const authRepo = getAuthRepository();

  if (await hasCompleteBusinessAuthSession(storage)) {
    const providerR = await storage.getLoginProvider();
    return providerR.success && isBusinessLoginProvider(providerR.data)
      ? providerR.data
      : ("email" as LoginStatus);
  }

  if (asid) {
    const avatarUrlR = await UserStorage.getInstance().getAvatarUrl();
    const result = await authRepo.facebookAsidLogin({
      asid,
      avatarUrl: avatarUrlR.success ? avatarUrlR.data ?? undefined : undefined,
      psid: psid ?? undefined,
    });
    if (Result.isErr(result)) {
      log.warn(
        { err: result.error.message },
        "[auth-machine] checkAuthStatusActor: facebookAsidLogin failed",
      );
      return "notLoggedIn" as LoginStatus;
    }
    return "facebook" as LoginStatus;
  }

  const guestTokenR = await storage.getGuestToken();
  if (guestTokenR.success && guestTokenR.data) return "guest" as LoginStatus;
  return "notLoggedIn" as LoginStatus;
});

function isBusinessLoginProvider(
  provider: LoginStatus | null,
): provider is LoginStatus {
  return (
    provider === "email" ||
    provider === "facebook" ||
    provider === "facebookMessenger" ||
    provider === "google"
  );
}
