"use client";

/**
 * PaymentContext：基于 XState v5 的 React Context Provider
 */
import {
  type Dispatch,
  type ReactNode,
  createContext,
  useContext,
  useMemo,
} from "react";
import { useMachine } from "@xstate/react";

import { paymentMachine } from "./payment-machine";
import type {
  PaymentEvent,
  PaymentState as MachineContext,
} from "./payment-machine";

export interface PaymentContextState {
  status: string;
  plans: MachineContext["plans"];
  selectedPlanId: string;
  payChannel: MachineContext["payChannel"];
  autoRenew: boolean;
  agreed: boolean;
  currentOrderId: string | null;
  payParams: Record<string, unknown> | null;
  orderStatus: MachineContext["orderStatus"];
  errorMessage: string | null;
  launchNonce: number;
  isLoadingPlans: boolean;
  isCreatingOrder: boolean;
  isPollingOrder: boolean;
  isPaid: boolean;
}

const PaymentStateCtx = createContext<PaymentContextState | null>(null);
const PaymentDispatchCtx = createContext<Dispatch<PaymentEvent> | null>(null);

export interface PaymentProviderProps {
  children: ReactNode;
}

export function PaymentProvider({ children }: PaymentProviderProps) {
  const [state, send] = useMachine(paymentMachine);

  const paymentState = useMemo<PaymentContextState>(
    () => ({
      status: String(state.value),
      plans: state.context.plans,
      selectedPlanId: state.context.selectedPlanId,
      payChannel: state.context.payChannel,
      autoRenew: state.context.autoRenew,
      agreed: state.context.agreed,
      currentOrderId: state.context.currentOrderId,
      payParams: state.context.payParams,
      orderStatus: state.context.orderStatus,
      errorMessage: state.context.errorMessage,
      launchNonce: state.context.launchNonce,
      isLoadingPlans:
        state.matches("loadingCachedPlans") ||
        state.matches("loadingPlans") ||
        state.matches("refreshingPlans"),
      isCreatingOrder: state.matches("creatingOrder"),
      isPollingOrder:
        state.matches("pollingOrder") || state.matches("waitingForPayment"),
      isPaid: state.matches("paid"),
    }),
    [state],
  );

  return (
    <PaymentStateCtx.Provider value={paymentState}>
      <PaymentDispatchCtx.Provider value={send}>
        {children}
      </PaymentDispatchCtx.Provider>
    </PaymentStateCtx.Provider>
  );
}

export function usePaymentState(): PaymentContextState {
  const ctx = useContext(PaymentStateCtx);
  if (!ctx)
    throw new Error("usePaymentState must be used inside <PaymentProvider>");
  return ctx;
}

export function usePaymentDispatch(): Dispatch<PaymentEvent> {
  const ctx = useContext(PaymentDispatchCtx);
  if (!ctx)
    throw new Error("usePaymentDispatch must be used inside <PaymentProvider>");
  return ctx;
}
