import { setup, type ActionFunction, type EventObject } from "xstate";

import type { ChatEvent } from "../chat-events";
import { loadHistoryActor } from "./actors/history";
import {
  httpMessageQueueActor,
  sendMessageHttpActor,
} from "./actors/send";
import {
  unlockHistoryActor,
  unlockMessageActor,
} from "./actors/unlock";
import type { ChatState } from "../chat-state";

export const baseChatMachineSetup = setup({
  types: {
    context: {} as ChatState,
    events: {} as ChatEvent,
  },
  actors: {
    loadHistory: loadHistoryActor,
    sendMessageHttp: sendMessageHttpActor,
    httpMessageQueue: httpMessageQueueActor,
    unlockHistory: unlockHistoryActor,
    unlockMessage: unlockMessageActor,
  },
});

type ChatActorAction<TEvent extends EventObject> = ActionFunction<
  ChatState,
  TEvent,
  ChatEvent,
  undefined,
  never,
  never,
  never,
  never,
  never
>;

export function createChatActorActionSetup<TEvent extends EventObject>() {
  const actorActionSetup = setup({
    types: {
      context: {} as ChatState,
      events: {} as TEvent,
    },
  });
  return {
    assign(
      assignment: Parameters<typeof actorActionSetup.assign>[0],
    ): ChatActorAction<TEvent> {
      // Actor lifecycle events are expression events, not public machine events.
      return actorActionSetup.assign(assignment) as unknown as ChatActorAction<TEvent>;
    },
  };
}
