import type { DoneActorEvent, ErrorActorEvent } from "xstate";

import type { LoginStatus } from "@/data/schemas/auth";

import { toAuthErrorMessage } from "../helper/error";
import {
  loadingEmailLoginState,
  loadingEmailRegisterState,
} from "./credentials-flow";
import {
  loadingOAuthState,
  oauthMachineSetup,
  syncingFacebookBackendState,
  syncingGoogleBackendState,
} from "./oauth-flow";
import { createAuthActorActionSetup } from "./setup";

const updatePanelModeAction = oauthMachineSetup.assign(({ event }) => {
  if (event.type !== "AuthPanelModeChanged") return {};
  return {
    authPanelMode: event.mode,
    errorMessage: null,
  };
});

export const authMachineSetup = oauthMachineSetup.extend({
  actions: {
    updatePanelMode: updatePanelModeAction,
  },
});

const sessionDoneSetup =
  createAuthActorActionSetup<DoneActorEvent<LoginStatus>>();
const sessionErrorSetup = createAuthActorActionSetup<ErrorActorEvent>();

const applySessionSuccessAction = sessionDoneSetup.assign(({ event }) => ({
  loginStatus: event.output,
  hasInitialized: true,
  errorMessage: null,
}));

const applySessionErrorAction = sessionErrorSetup.assign(({ event }) => ({
  errorMessage: toAuthErrorMessage(event.error),
  hasInitialized: true,
}));

const applyLogoutErrorAction = sessionErrorSetup.assign(({ event }) => ({
  loginStatus: "guest",
  hasInitialized: true,
  errorMessage: toAuthErrorMessage(event.error),
}));

const idleState = authMachineSetup.createStateConfig({
  on: {
    AuthPanelModeChanged: { actions: "updatePanelMode" },
    AuthLogoutSubmitted: {
      guard: "canLogoutToGuest",
      target: "loggingOut",
    },
    AuthInit: "initializing",
    AuthExternalFacebookIdentityBindRequested: "bindingFacebookIdentity",
    AuthGuestLoginSubmitted: {
      guard: "canSubmitGuestLogin",
      target: "loadingGuestLogin",
    },
    AuthEmailLoginSubmitted: "loadingEmailLogin",
    AuthEmailRegisterSubmitted: "loadingEmailRegister",
    AuthGoogleLoginSubmitted: "loadingOAuth",
    AuthFacebookLoginSubmitted: "loadingOAuth",
  },
});

const initializingState = authMachineSetup.createStateConfig({
  entry: "clearAuthError",
  invoke: {
    src: "checkAuthStatus",
    onDone: {
      target: "idle",
      actions: applySessionSuccessAction,
    },
    onError: {
      target: "idle",
      actions: applySessionErrorAction,
    },
  },
});

const bindingFacebookIdentityState = authMachineSetup.createStateConfig({
  invoke: {
    src: "bindFacebookIdentity",
    input: ({ event }) =>
      event.type === "AuthExternalFacebookIdentityBindRequested"
        ? { asid: event.asid, psid: event.psid }
        : {},
    onDone: { target: "idle" },
    onError: { target: "idle" },
  },
});

const loadingGuestLoginState = authMachineSetup.createStateConfig({
  entry: "clearAuthError",
  invoke: {
    src: "guestLogin",
    onDone: {
      target: "idle",
      actions: applySessionSuccessAction,
    },
    onError: {
      target: "idle",
      actions: applySessionErrorAction,
    },
  },
});

const loggingOutState = authMachineSetup.createStateConfig({
  entry: "clearAuthError",
  invoke: {
    src: "logout",
    onDone: {
      target: "idle",
      actions: applySessionSuccessAction,
    },
    onError: {
      target: "idle",
      actions: applyLogoutErrorAction,
    },
  },
});

export const authRootStateConfig = authMachineSetup.createStateConfig({
  initial: "idle",
  on: {
    AuthGoogleSyncSubmitted: ".syncingGoogleBackend",
    AuthFacebookSyncSubmitted: ".syncingFacebookBackend",
  },
  states: {
    idle: idleState,
    initializing: initializingState,
    bindingFacebookIdentity: bindingFacebookIdentityState,
    loadingGuestLogin: loadingGuestLoginState,
    loadingEmailLogin: loadingEmailLoginState,
    loadingEmailRegister: loadingEmailRegisterState,
    loadingOAuth: loadingOAuthState,
    loggingOut: loggingOutState,
    syncingGoogleBackend: syncingGoogleBackendState,
    syncingFacebookBackend: syncingFacebookBackendState,
  },
});
