import { setup, type ActionFunction, type EventObject } from "xstate";

import type { PaymentEvent } from "../payment-events";
import type { PaymentState } from "../payment-state";
import {
  createPaymentOrderActor,
  pollPaymentOrderStatusActor,
} from "./actors/order";
import { loadGiftProductsActor, loadTipMessageActor } from "./actors/gifts";
import {
  loadCachedPaymentPlansActor,
  refreshPaymentPlansActor,
} from "./actors/plans";

export const basePaymentMachineSetup = setup({
  types: {
    context: {} as PaymentState,
    events: {} as PaymentEvent,
  },
  actors: {
    loadCachedPlans: loadCachedPaymentPlansActor,
    refreshPlans: refreshPaymentPlansActor,
    loadGiftProducts: loadGiftProductsActor,
    loadTipMessage: loadTipMessageActor,
    createOrder: createPaymentOrderActor,
    pollOrderStatus: pollPaymentOrderStatusActor,
  },
  guards: {
    canCreateOrder: ({ context }) =>
      context.agreed && context.selectedPlanId.length > 0,
  },
});

type PaymentActorAction<TEvent extends EventObject> = ActionFunction<
  PaymentState,
  TEvent,
  PaymentEvent,
  undefined,
  never,
  never,
  never,
  never,
  never
>;

export function createPaymentActorActionSetup<TEvent extends EventObject>() {
  const actorActionSetup = setup({
    types: {
      context: {} as PaymentState,
      events: {} as TEvent,
    },
  });
  return {
    assign(
      assignment: Parameters<typeof actorActionSetup.assign>[0],
    ): PaymentActorAction<TEvent> {
      return actorActionSetup.assign(assignment) as unknown as PaymentActorAction<TEvent>;
    },
    createAction(
      action: Parameters<typeof actorActionSetup.createAction>[0],
    ): PaymentActorAction<TEvent> {
      return actorActionSetup.createAction(action) as unknown as PaymentActorAction<TEvent>;
    },
  };
}
