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

import {
  CreatePaymentOrderResponse,
  CreatePaymentOrderResponseSchema,
  GiftProductsResponse,
  GiftProductsResponseSchema,
  type PayChannel,
  type PaymentOrderStatus,
  PaymentOrderStatusResponseSchema,
  PaymentPlansResponse,
  PaymentPlansResponseSchema,
  TipMessageResponse,
  TipMessageResponseSchema,
} from "@/data/schemas/payment";
import { paymentMachine } from "@/stores/payment/payment-machine";
import type { PaymentPlanCatalog } from "@/stores/payment/payment-state";

export interface PaymentPlansActorInput {
  catalog: PaymentPlanCatalog;
  commercialOfferId?: string | null;
}

export interface CreateOrderInput {
  planId: string;
  payChannel: PayChannel;
  autoRenew: boolean;
  recipientCharacterId?: string;
  commercialOfferId?: string;
  chatActionId?: string;
}

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 giftCatalog = GiftProductsResponseSchema.parse({
  characterId: "elio",
  categories: [
    {
      category: "coffee",
      name: "Coffee",
      productCount: 2,
      imageUrl: null,
    },
    {
      category: "flowers",
      name: "Flowers",
      productCount: 1,
      imageUrl: null,
    },
  ],
  plans: [
    {
      planId: "tip_coffee_usd_4_99",
      planName: "Velvet Espresso",
      orderType: "tip",
      tipType: "coffee_small",
      category: "coffee",
      characterId: "elio",
      description: "A small coffee",
      imageUrl: null,
      amountCents: 499,
      currency: "USD",
      autoRenew: false,
      isFirstRechargeOffer: false,
      firstRechargeDiscountPercent: 0,
      promotionType: null,
    },
    {
      planId: "tip_coffee_usd_9_99",
      planName: "Golden Reserve",
      orderType: "tip",
      tipType: "coffee_medium",
      category: "coffee",
      characterId: "elio",
      description: "A medium coffee",
      imageUrl: null,
      amountCents: 999,
      currency: "USD",
      autoRenew: false,
      isFirstRechargeOffer: false,
      firstRechargeDiscountPercent: 0,
      promotionType: null,
    },
    {
      planId: "tip_flowers_usd_12_99",
      planName: "Rose Bouquet",
      orderType: "tip",
      tipType: "flowers",
      category: "flowers",
      characterId: "elio",
      description: "A bouquet",
      imageUrl: null,
      amountCents: 1299,
      currency: "USD",
      autoRenew: false,
      isFirstRechargeOffer: false,
      firstRechargeDiscountPercent: 0,
      promotionType: null,
    },
  ],
});

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

const defaultTipMessage = TipMessageResponseSchema.parse({
  orderId: "pay_test_001",
  characterId: "elio",
  planId: "tip_coffee_usd_4_99",
  productName: "Velvet Espresso",
  tipCount: 1,
  poolIndex: 37,
  message: "Thank you for the thoughtful gift.",
});

export function createTestPaymentMachine(
  overrides: Partial<{
    cachedPlans: PaymentPlansResponse | null;
    refreshedPlans: PaymentPlansResponse;
    refreshPlans: () => Promise<PaymentPlansResponse>;
    giftProducts: GiftProductsResponse;
    giftProductsError: Error;
    onLoadCatalog: (catalog: PaymentPlanCatalog) => void;
    onRefreshCatalog: (catalog: PaymentPlanCatalog) => void;
    onLoadGiftProducts: (characterId: string) => void;
    createOrderSpy: CreateOrderSpy;
    createOrderError: Error;
    orderStatus: PaymentOrderStatus;
    orderStatuses: PaymentOrderStatus[];
    orderType: string;
    orderPlanId: string | null;
    tipMessage: TipMessageResponse;
    tipMessageError: Error;
    onLoadTipMessage: (orderId: string) => void;
  }> = {},
) {
  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 ??
            PaymentPlansResponseSchema.parse({
              plans: [monthlyPlan, lifetimePlan, creditPlan],
            })
          );
        },
      ),
      loadGiftProducts: fromPromise<
        GiftProductsResponse,
        { characterId: string }
      >(async ({ input }) => {
        overrides.onLoadGiftProducts?.(input.characterId);
        if (overrides.giftProductsError) throw overrides.giftProductsError;
        return overrides.giftProducts ?? giftCatalog;
      }),
      createOrder: fromPromise<CreatePaymentOrderResponse, CreateOrderInput>(
        async ({ input }) => {
          createOrderSpy(input);
          if (overrides.createOrderError) throw overrides.createOrderError;
          return CreatePaymentOrderResponseSchema.parse({
            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 PaymentOrderStatusResponseSchema.parse({
          orderId: "pay_test_001",
          status,
          orderType: overrides.orderType ?? "vip_monthly",
          planId: overrides.orderPlanId ?? "vip_monthly",
          creditsAdded: 0,
        });
      }),
      loadTipMessage: fromPromise<TipMessageResponse, { orderId: string }>(
        async ({ input }) => {
          overrides.onLoadTipMessage?.(input.orderId);
          if (overrides.tipMessageError) throw overrides.tipMessageError;
          return overrides.tipMessage ?? defaultTipMessage;
        },
      ),
    },
  });
}
