/**
 * Get Started Machine — XState Definition
 *
 * State machine managing the get-started flow:
 * idle -> email -> verification -> account-status -> (complete-account | migrate-account) -> success
 *
 * Replaces the implicit state machine in the Zustand store with enforced
 * transitions, guards, and typed events.
 */

import { setup, assign } from "xstate";
import { getErrorMessage } from "@/shared/utils";
import type {
  GetStartedAddress,
  GetStartedContext,
  GetStartedEvent,
  GetStartedFormData,
  GetStartedMachineInput,
} from "./get-started.types";
import {
  sendCodeActor,
  verifyCodeActor,
  completeAccountActor,
  migrateAccountActor,
} from "./get-started.actors";

// ============================================================================
// Initial form data (matches store defaults)
// ============================================================================

const ACCOUNT_STATUS_TARGET = "#getStarted.accountStatus";

const initialFormData: GetStartedFormData = {
  email: "",
  firstName: "",
  lastName: "",
  phone: "",
  address: {},
  dateOfBirth: "",
  gender: "",
  password: "",
  confirmPassword: "",
  acceptTerms: false,
  marketingConsent: false,
};

// ============================================================================
// Machine Definition
// ============================================================================

export const getStartedMachine = setup({
  types: {
    context: {} as GetStartedContext,
    events: {} as GetStartedEvent,
    input: {} as GetStartedMachineInput,
  },
  actors: {
    sendCode: sendCodeActor,
    verifyCode: verifyCodeActor,
    completeAccount: completeAccountActor,
    migrateAccount: migrateAccountActor,
  },
  guards: {
    hasSessionToken: ({ context }) => context.sessionToken !== null,
    isNewOrSfUnmapped: ({ context }) =>
      context.accountStatus === "new_customer" || context.accountStatus === "sf_unmapped",
    isWhmcsUnmapped: ({ context }) => context.accountStatus === "whmcs_unmapped",
    isPortalExists: ({ context }) => context.accountStatus === "portal_exists",
  },
  actions: {
    clearError: assign({ error: null }),
    resetMachine: assign(({ context }) => ({
      email: null,
      sessionToken: null,
      accountStatus: null,
      formData: initialFormData,
      prefill: null,
      handoffToken: null,
      serviceContext: context.serviceContext,
      redirectTo: context.redirectTo,
      inline: context.inline,
      error: null,
      errorId: 0,
      codeSent: false,
      codeExpiresAt: null,
      attemptsRemaining: null,
      authResponse: null,
    })),
  },
}).createMachine({
  id: "getStarted",
  context: ({ input }) => ({
    email: null,
    sessionToken: null,
    accountStatus: null,
    formData: initialFormData,
    prefill: null,
    handoffToken: null,
    serviceContext: input?.serviceContext ?? null,
    redirectTo: null,
    inline: input?.inline ?? false,
    error: null,
    errorId: 0,
    codeSent: false,
    codeExpiresAt: null,
    attemptsRemaining: null,
    authResponse: null,
  }),
  initial: "idle",
  on: {
    RESET: {
      target: ".idle",
      actions: "resetMachine",
    },
    UPDATE_FORM_DATA: {
      actions: assign({
        formData: ({ context, event }) => ({
          ...context.formData,
          ...event.data,
        }),
      }),
    },
    SET_SERVICE_CONTEXT: {
      actions: assign({
        serviceContext: ({ event }) => event.context,
      }),
    },
    SET_REDIRECT: {
      actions: assign({
        redirectTo: ({ event }) => event.redirectTo,
      }),
    },
  },
  states: {
    idle: {
      on: {
        START: { target: "email" },
        SET_EMAIL: {
          target: "email",
          actions: assign({
            email: ({ event }) => event.email,
            formData: ({ context, event }) => ({
              ...context.formData,
              email: event.email,
            }),
            handoffToken: ({ event }) => event.handoffToken ?? null,
          }),
        },
        RESTORE_VERIFIED_SESSION: {
          target: "accountStatus",
          actions: assign({
            sessionToken: ({ event }) => event.sessionToken,
            accountStatus: ({ event }) => event.accountStatus,
            prefill: ({ event }) => event.prefill ?? null,
            formData: ({ context, event }) => {
              const prefill = event.prefill;
              if (!prefill) return context.formData;
              return {
                ...context.formData,
                firstName: prefill.firstName ?? context.formData.firstName,
                lastName: prefill.lastName ?? context.formData.lastName,
                phone: prefill.phone ?? context.formData.phone,
                address: (prefill.address as GetStartedAddress) ?? context.formData.address,
              };
            },
          }),
        },
      },
    },

    email: {
      initial: "idle",
      states: {
        idle: {
          on: {
            SEND_CODE: {
              target: "loading",
              actions: assign({
                email: ({ event }) => event.email,
                formData: ({ context, event }) => ({
                  ...context.formData,
                  email: event.email,
                }),
              }),
            },
          },
        },
        loading: {
          invoke: {
            src: "sendCode",
            input: ({ context }) => ({
              email: context.formData.email || context.email || "",
            }),
            onDone: [
              {
                guard: ({ event }) => event.output.sent === true,
                target: "#getStarted.verification",
                actions: assign({
                  codeSent: true,
                  error: null,
                  codeExpiresAt: () => new Date(Date.now() + 10 * 60 * 1000).toISOString(),
                }),
              },
              {
                target: "error",
                actions: assign({
                  error: ({ event }) => event.output.message,
                  errorId: ({ context }) => context.errorId + 1,
                }),
              },
            ],
            onError: {
              target: "error",
              actions: assign({
                error: ({ event }) => getErrorMessage(event.error),
                errorId: ({ context }) => context.errorId + 1,
              }),
            },
          },
        },
        error: {
          on: {
            SEND_CODE: {
              target: "loading",
              actions: assign({
                email: ({ event }) => event.email,
                formData: ({ context, event }) => ({
                  ...context.formData,
                  email: event.email,
                }),
              }),
            },
          },
        },
      },
    },

    verification: {
      initial: "idle",
      states: {
        idle: {
          on: {
            VERIFY_CODE: { target: "loading" },
          },
        },
        loading: {
          invoke: {
            src: "verifyCode",
            input: ({ context, event }) => ({
              email: context.formData.email || context.email || "",
              code: event.type === "VERIFY_CODE" ? event.code : "",
              ...(context.handoffToken && { handoffToken: context.handoffToken }),
            }),
            onDone: [
              {
                guard: ({ event }) =>
                  event.output.verified === true &&
                  event.output.sessionToken !== undefined &&
                  event.output.accountStatus !== undefined,
                target: ACCOUNT_STATUS_TARGET,
                actions: assign({
                  sessionToken: ({ event }) => event.output.sessionToken ?? null,
                  accountStatus: ({ event }) => event.output.accountStatus ?? null,
                  prefill: ({ event }) => event.output.prefill ?? null,
                  error: null,
                  formData: ({ context, event }) => {
                    const prefill = event.output.prefill;
                    if (!prefill) return context.formData;
                    return {
                      ...context.formData,
                      firstName: prefill.firstName ?? context.formData.firstName,
                      lastName: prefill.lastName ?? context.formData.lastName,
                      phone: prefill.phone ?? context.formData.phone,
                      address: (prefill.address as GetStartedAddress) ?? context.formData.address,
                    };
                  },
                }),
              },
              {
                target: "error",
                actions: assign({
                  error: ({ event }) => event.output.error ?? "Verification failed",
                  errorId: ({ context }) => context.errorId + 1,
                  attemptsRemaining: ({ event }) => event.output.attemptsRemaining ?? null,
                }),
              },
            ],
            onError: {
              target: "error",
              actions: assign({
                error: ({ event }) => getErrorMessage(event.error),
                errorId: ({ context }) => context.errorId + 1,
              }),
            },
          },
        },
        error: {
          on: {
            VERIFY_CODE: { target: "loading" },
            SEND_CODE: {
              target: "#getStarted.email.loading",
              actions: assign({
                email: ({ event }) => event.email,
                formData: ({ context, event }) => ({
                  ...context.formData,
                  email: event.email,
                }),
              }),
            },
          },
        },
      },
    },

    accountStatus: {
      always: [
        {
          guard: "isPortalExists",
          target: "loginRedirect",
        },
        {
          guard: "isNewOrSfUnmapped",
          target: "completeAccount",
        },
        {
          guard: "isWhmcsUnmapped",
          target: "migrateAccount",
        },
      ],
    },

    loginRedirect: {
      type: "final",
    },

    completeAccount: {
      initial: "idle",
      states: {
        idle: {
          on: {
            COMPLETE: {
              target: "loading",
              guard: "hasSessionToken",
              actions: assign({
                formData: ({ context, event }) => ({
                  ...context.formData,
                  ...event.formData,
                }),
              }),
            },
            GO_BACK: { target: ACCOUNT_STATUS_TARGET },
          },
        },
        loading: {
          invoke: {
            src: "completeAccount",
            input: ({ context }) => ({
              sessionToken: context.sessionToken!,
              formData: context.formData,
              accountStatus: context.accountStatus,
            }),
            onDone: {
              target: "#getStarted.success",
              actions: assign({
                authResponse: ({ event }) => event.output,
                sessionToken: null,
                error: null,
              }),
            },
            onError: {
              target: "error",
              actions: assign({
                error: ({ event }) => getErrorMessage(event.error),
              }),
            },
          },
        },
        error: {
          on: {
            COMPLETE: {
              target: "loading",
              guard: "hasSessionToken",
              actions: assign({
                formData: ({ context, event }) => ({
                  ...context.formData,
                  ...event.formData,
                }),
              }),
            },
            GO_BACK: { target: ACCOUNT_STATUS_TARGET },
          },
        },
      },
    },

    migrateAccount: {
      initial: "idle",
      states: {
        idle: {
          on: {
            MIGRATE: {
              target: "loading",
              guard: "hasSessionToken",
            },
            GO_BACK: { target: ACCOUNT_STATUS_TARGET },
          },
        },
        loading: {
          invoke: {
            src: "migrateAccount",
            input: ({ context, event }) => ({
              sessionToken: context.sessionToken!,
              password:
                event.type === "MIGRATE" && event.password
                  ? event.password
                  : context.formData.password,
              acceptTerms: context.formData.acceptTerms,
              marketingConsent: context.formData.marketingConsent,
            }),
            onDone: {
              target: "#getStarted.success",
              actions: assign({
                authResponse: ({ event }) => event.output,
                sessionToken: null,
                error: null,
              }),
            },
            onError: {
              target: "error",
              actions: assign({
                error: ({ event }) => getErrorMessage(event.error),
              }),
            },
          },
        },
        error: {
          on: {
            MIGRATE: {
              target: "loading",
              guard: "hasSessionToken",
            },
            GO_BACK: { target: ACCOUNT_STATUS_TARGET },
          },
        },
      },
    },

    success: {
      type: "final",
    },
  },
});

export type GetStartedMachine = typeof getStartedMachine;
