import { vi } from "vitest";
import { fromPromise } from "xstate";

import {
  CreatePaymentOrderResponse,
  type PayChannel,
  PaymentOrderStatusResponse,
  PaymentPlansResponse,
} from "@/data/dto/payment";
import { paymentMachine } from "@/stores/payment/payment-machine";
import type { PaymentPlanCatalog } from "@/stores/payment/payment-state";

export interface PaymentPlansActorInput {
  catalog: PaymentPlanCatalog;
}

export interface CreateOrderInput {
  planId: string;
  payChannel: PayChannel;
  autoRenew: boolean;
}

export type CreateOrderSpy = (input: CreateOrderInput) => void;

export const monthlyPlan = {
  planId: "vip_monthly",
  planName: "VIP Monthly",
  orderType: "vip_monthly",
  vipDays: 30,
  dolAmount: null,
  creditBalance: 3000,
  amountCents: 999,
  originalAmountCents: null,
  dailyPriceCents: 33,
  currency: "usd",
};

export const lifetimePlan = {
  planId: "vip_lifetime",
  planName: "VIP Lifetime",
  orderType: "vip_lifetime",
  vipDays: 3650,
  dolAmount: null,
  creditBalance: 0,
  amountCents: 4999,
  originalAmountCents: null,
  dailyPriceCents: null,
  currency: "usd",
};

export const creditPlan = {
  planId: "dol_1000",
  planName: "1000 Credits",
  orderType: "dol",
  vipDays: null,
  dolAmount: 1000,
  creditBalance: 1000,
  amountCents: 990,
  originalAmountCents: null,
  dailyPriceCents: null,
  currency: "usd",
};

export const quarterlyPlan = {
  planId: "vip_quarterly",
  planName: "VIP Quarterly",
  orderType: "vip_quarterly",
  vipDays: 90,
  dolAmount: null,
  creditBalance: 9000,
  amountCents: 2499,
  originalAmountCents: null,
  dailyPriceCents: 28,
  currency: "usd",
};

export const tipPlan = {
  planId: "tip_coffee_usd_4_99",
  planName: "Small Coffee",
  orderType: "tip",
  vipDays: null,
  dolAmount: null,
  creditBalance: 0,
  amountCents: 499,
  originalAmountCents: null,
  dailyPriceCents: null,
  currency: "USD",
};

export function createTestPaymentMachine(
  overrides: Partial<{
    cachedPlans: PaymentPlansResponse | null;
    refreshedPlans: PaymentPlansResponse;
    refreshPlans: () => Promise<PaymentPlansResponse>;
    onLoadCatalog: (catalog: PaymentPlanCatalog) => void;
    onRefreshCatalog: (catalog: PaymentPlanCatalog) => void;
    createOrderSpy: CreateOrderSpy;
    createOrderError: Error;
    orderStatus: "pending" | "paid" | "failed";
    orderStatuses: ("pending" | "paid" | "failed")[];
  }> = {},
) {
  const createOrderSpy = overrides.createOrderSpy ?? vi.fn<CreateOrderSpy>();
  const orderStatus = overrides.orderStatus ?? "paid";
  const orderStatuses = overrides.orderStatuses ?? [];
  let pollCount = 0;

  return paymentMachine.provide({
    actors: {
      loadCachedPlans: fromPromise<
        PaymentPlansResponse | null,
        PaymentPlansActorInput
      >(async ({ input }) => {
        overrides.onLoadCatalog?.(input.catalog);
        return overrides.cachedPlans ?? null;
      }),
      refreshPlans: fromPromise<
        PaymentPlansResponse,
        PaymentPlansActorInput
      >(async ({ input }) => {
        overrides.onRefreshCatalog?.(input.catalog);
        if (overrides.refreshPlans) return overrides.refreshPlans();
        return (
          overrides.refreshedPlans ??
          PaymentPlansResponse.from({
            plans: [monthlyPlan, lifetimePlan, creditPlan],
          })
        );
      }),
      createOrder: fromPromise<
        CreatePaymentOrderResponse,
        CreateOrderInput
      >(async ({ input }) => {
        createOrderSpy(input);
        if (overrides.createOrderError) throw overrides.createOrderError;
        return CreatePaymentOrderResponse.from({
          orderId: "pay_test_001",
          payParams: {
            provider: "stripe",
            clientSecret: "pi_test_secret_test",
          },
        });
      }),
      pollOrderStatus: fromPromise(async () => {
        const status =
          orderStatuses[Math.min(pollCount, orderStatuses.length - 1)] ??
          orderStatus;
        pollCount += 1;
        return PaymentOrderStatusResponse.from({
          orderId: "pay_test_001",
          status,
          orderType: "vip_monthly",
          planId: "vip_monthly",
        });
      }),
    },
  });
}
