"use client";

import {
  type Dispatch,
  type ReactNode,
  createContext,
  useContext,
  useMemo,
} from "react";
import { useMachine } from "@xstate/react";

import { privateRoomMachine } from "./private-room-machine";
import type {
  PrivateRoomEvent,
  PrivateRoomState as MachineContext,
} from "./private-room-machine";

export interface PrivateRoomContextState {
  status: string;
  profile: MachineContext["profile"];
  items: MachineContext["items"];
  nextCursor: string | null;
  hasMore: boolean;
  creditBalance: number;
  errorMessage: string | null;
  unlockingMomentId: string | null;
  unlockErrorMessage: string | null;
  pendingConfirmMomentId: string | null;
  unlockPaywallRequest: MachineContext["unlockPaywallRequest"];
  unlockSuccessNonce: number;
  isLoading: boolean;
  isLoadingMore: boolean;
  isUnlocking: boolean;
}

const PrivateRoomStateCtx = createContext<PrivateRoomContextState | null>(null);
const PrivateRoomDispatchCtx = createContext<Dispatch<PrivateRoomEvent> | null>(
  null,
);

export interface PrivateRoomProviderProps {
  children: ReactNode;
}

export function PrivateRoomProvider({ children }: PrivateRoomProviderProps) {
  const [state, send] = useMachine(privateRoomMachine);

  const privateRoomState = useMemo<PrivateRoomContextState>(
    () => ({
      status: String(state.value),
      profile: state.context.profile,
      items: state.context.items,
      nextCursor: state.context.nextCursor,
      hasMore: state.context.hasMore,
      creditBalance: state.context.creditBalance,
      errorMessage: state.context.errorMessage,
      unlockingMomentId: state.context.unlockingMomentId,
      unlockErrorMessage: state.context.unlockErrorMessage,
      pendingConfirmMomentId: state.context.pendingConfirmMomentId,
      unlockPaywallRequest: state.context.unlockPaywallRequest,
      unlockSuccessNonce: state.context.unlockSuccessNonce,
      isLoading: state.matches("loading"),
      isLoadingMore: state.matches("loadingMore"),
      isUnlocking: state.matches("unlocking"),
    }),
    [state],
  );

  return (
    <PrivateRoomStateCtx.Provider value={privateRoomState}>
      <PrivateRoomDispatchCtx.Provider value={send}>
        {children}
      </PrivateRoomDispatchCtx.Provider>
    </PrivateRoomStateCtx.Provider>
  );
}

export function usePrivateRoomState(): PrivateRoomContextState {
  const ctx = useContext(PrivateRoomStateCtx);
  if (!ctx) {
    throw new Error(
      "usePrivateRoomState must be used inside <PrivateRoomProvider>",
    );
  }
  return ctx;
}

export function usePrivateRoomDispatch(): Dispatch<PrivateRoomEvent> {
  const ctx = useContext(PrivateRoomDispatchCtx);
  if (!ctx) {
    throw new Error(
      "usePrivateRoomDispatch must be used inside <PrivateRoomProvider>",
    );
  }
  return ctx;
}
