"use client";
/**
 * UserContext：基于 XState v5 的 React Context Provider
 *
 * 业务事件通过 `useMachine(userMachine).send()` 派发。
 * XState 自动处理异步副作用（invoke + fromPromise actors）。
 *
 * 兼容性：保持原 `useUserState()` / `useUserDispatch()` API。
 * 内部将 XState 状态机快照映射回原 `UserState` 形状。
 */
import {
  type Dispatch,
  type ReactNode,
  createContext,
  useContext,
  useMemo,
} from "react";
import { useMachine } from "@xstate/react";

import { userMachine } from "./user-machine";
import type { UserState as MachineContext, UserEvent } from "./user-machine";

/**
 * 对外暴露的 State 形状（保持与原 UserState 兼容）
 */
interface UserState {
  currentUser: MachineContext["currentUser"];
  isLoading: boolean;
  avatarUrl: string | null;
  isVip: boolean;
  creditBalance: number;
}

const UserStateCtx = createContext<UserState | null>(null);
const UserDispatchCtx = createContext<Dispatch<UserEvent> | null>(null);

export interface UserProviderProps {
  children: ReactNode;
}

export function UserProvider({ children }: UserProviderProps) {
  const [state, send] = useMachine(userMachine);

  // 映射 XState 状态机快照 → 原 UserState 形状
  const userState = useMemo<UserState>(
    () => ({
      currentUser: state.context.currentUser,
      isLoading:
        state.matches("initializing") ||
        state.matches("fetching") ||
        state.matches("loggingOut") ||
        state.context.isLoading,
      avatarUrl: state.context.avatarUrl,
      isVip: state.context.isVip,
      creditBalance: state.context.creditBalance,
    }),
    [state],
  );

  return (
    <UserStateCtx.Provider value={userState}>
      <UserDispatchCtx.Provider value={send}>{children}</UserDispatchCtx.Provider>
    </UserStateCtx.Provider>
  );
}

export function useUserState(): UserState {
  const ctx = useContext(UserStateCtx);
  if (!ctx) throw new Error("useUserState must be used inside <UserProvider>");
  return ctx;
}

export function useUserDispatch(): Dispatch<UserEvent> {
  const ctx = useContext(UserDispatchCtx);
  if (!ctx)
    throw new Error("useUserDispatch must be used inside <UserProvider>");
  return ctx;
}
