"use client";

import type { Dispatch, ReactNode } from "react";
import { createActorContext, shallowEqual } from "@xstate/react";
import type { SnapshotFrom } from "xstate";

import { privateZoneMachine } from "./private-zone-machine";
import type {
  PrivateZoneEvent,
  PrivateZoneState as MachineContext,
} from "./private-zone-machine";

/** Route UI reads this projection instead of the Private Zone snapshot. */
export interface PrivateZoneContextState {
  characterId: string;
  status: string;
  items: MachineContext["items"];
  creditBalance: number;
  pendingImageCount: number;
  hasIncompleteContent: boolean;
  errorMessage: string | null;
  unlockingAlbumId: string | null;
  unlockErrorMessage: string | null;
  pendingConfirmAlbumId: string | null;
  unlockPaywallRequest: MachineContext["unlockPaywallRequest"];
  unlockSuccessNonce: number;
  isLoading: boolean;
  isUnlocking: boolean;
}

type PrivateZoneSnapshot = SnapshotFrom<typeof privateZoneMachine>;
type PrivateZoneSelector<T> = (snapshot: PrivateZoneSnapshot) => T;

const PrivateZoneActorContext = createActorContext(privateZoneMachine);

export interface PrivateZoneProviderProps {
  children: ReactNode;
  characterId: string;
}

export function PrivateZoneProvider({
  children,
  characterId,
}: PrivateZoneProviderProps) {
  return (
    <PrivateZoneActorContext.Provider options={{ input: { characterId } }}>
      {children}
    </PrivateZoneActorContext.Provider>
  );
}

export function usePrivateZoneState(): PrivateZoneContextState {
  return usePrivateZoneSelector(selectPrivateZoneState, shallowEqual);
}

export function usePrivateZoneDispatch(): Dispatch<PrivateZoneEvent> {
  return PrivateZoneActorContext.useActorRef().send;
}

export function usePrivateZoneSelector<T>(
  selector: PrivateZoneSelector<T>,
  compare?: (previous: T, next: T) => boolean,
): T {
  return PrivateZoneActorContext.useSelector(selector, compare);
}

function selectPrivateZoneState(
  state: PrivateZoneSnapshot,
): PrivateZoneContextState {
  return {
    characterId: state.context.characterId,
    status: String(state.value),
    items: state.context.items,
    creditBalance: state.context.creditBalance,
    pendingImageCount: state.context.pendingImageCount,
    hasIncompleteContent: state.context.hasIncompleteContent,
    errorMessage: state.context.errorMessage,
    unlockingAlbumId: state.context.unlockingAlbumId,
    unlockErrorMessage: state.context.unlockErrorMessage,
    pendingConfirmAlbumId: state.context.pendingConfirmAlbumId,
    unlockPaywallRequest: state.context.unlockPaywallRequest,
    unlockSuccessNonce: state.context.unlockSuccessNonce,
    isLoading: state.matches("loading"),
    isUnlocking: state.matches("unlocking"),
  };
}
