import {
  applyOlderHistoryLoadedOutput,
  applyHistoryLoadedOutput,
  applyNetworkHistoryLoadedOutput,
  canLoadMoreHistory,
} from "../helper/history";
import {
  countLockedHistoryMessages,
  shouldPromptUnlockHistory,
} from "../helper/unlock";
import type { ChatState } from "../chat-state";
import { baseChatMachineSetup } from "./setup";
import { getCharacterErrorCode } from "@/data/services/api";

const applyLocalHistoryLoadedAction = baseChatMachineSetup.assign(
  ({ event }) => {
    if (event.type !== "ChatLocalHistoryLoaded") return {};
    return applyHistoryLoadedOutput(event.output);
  },
);

const applyNetworkHistoryLoadedAction = baseChatMachineSetup.assign(
  ({ context, event }) => {
    if (event.type !== "ChatNetworkHistoryLoaded") return {};
    return applyNetworkHistoryLoadedOutput(context, event.output);
  },
);

const applyNetworkHistoryLoadedAndClearPaymentAction =
  baseChatMachineSetup.assign(({ context, event }) => {
    if (event.type !== "ChatNetworkHistoryLoaded") return {};
    return {
      ...applyNetworkHistoryLoadedOutput(context, event.output),
      paymentUnlockPending: false,
    };
  });

const showUnlockHistoryPromptFromNetworkAction = baseChatMachineSetup.assign(
  ({ context, event }) => {
    if (event.type !== "ChatNetworkHistoryLoaded") return {};
    const nextHistory = applyNetworkHistoryLoadedOutput(context, event.output);
    return {
      ...nextHistory,
      paymentUnlockPending: false,
      unlockHistoryPromptVisible: true,
      lockedHistoryCount: countLockedHistoryMessages(nextHistory.messages),
      unlockHistoryError: null,
    };
  },
);

const markHistoryLoadFailedAction = baseChatMachineSetup.assign(
  ({ context, event }) => {
    if (event.type !== "ChatHistoryLoadFailed") return {};
    const characterErrorCode = getCharacterErrorCode(event.error);
    return {
      historyLoaded: true,
      networkHistoryLoaded: true,
      characterErrorCode,
      canSendMessage:
        characterErrorCode === "CHARACTER_DISABLED" ||
        characterErrorCode === "CHARACTER_NOT_FOUND"
          ? false
          : context.canSendMessage,
    };
  },
);

const markLoadMoreHistoryStartedAction = baseChatMachineSetup.assign({
  isLoadingMoreHistory: true,
});

const requestOlderHistoryPageAction = baseChatMachineSetup.sendTo(
  "loadMoreHistory",
  ({ context }) => ({
    type: "LoadMoreHistoryPageRequested",
    offset: context.nextHistoryOffset,
    limit: context.historyLimit,
  }),
);

const applyOlderHistoryLoadedAction = baseChatMachineSetup.assign(
  ({ context, event }) => {
    if (event.type !== "ChatOlderHistoryLoaded") return {};
    return applyOlderHistoryLoadedOutput(context, event.output);
  },
);

const markOlderHistoryLoadFailedAction = baseChatMachineSetup.assign({
  isLoadingMoreHistory: false,
});

export const historyMachineSetup = baseChatMachineSetup.extend({
  actions: {
    applyLocalHistoryLoaded: applyLocalHistoryLoadedAction,
    applyNetworkHistoryLoaded: applyNetworkHistoryLoadedAction,
    applyNetworkHistoryLoadedAndClearPayment:
      applyNetworkHistoryLoadedAndClearPaymentAction,
    showUnlockHistoryPromptFromNetwork:
      showUnlockHistoryPromptFromNetworkAction,
    markHistoryLoadFailed: markHistoryLoadFailedAction,
    markLoadMoreHistoryStarted: markLoadMoreHistoryStartedAction,
    requestOlderHistoryPage: requestOlderHistoryPageAction,
    applyOlderHistoryLoaded: applyOlderHistoryLoadedAction,
    markOlderHistoryLoadFailed: markOlderHistoryLoadFailedAction,
  },
});

export const historyPaginationTransitions = {
  ChatLoadMoreHistoryRequested: {
    guard: ({ context }: { context: ChatState }) =>
      canLoadMoreHistory(context),
    actions: ["markLoadMoreHistoryStarted", "requestOlderHistoryPage"],
  },
  ChatOlderHistoryLoaded: {
    actions: "applyOlderHistoryLoaded",
  },
  ChatOlderHistoryLoadFailed: {
    actions: "markOlderHistoryLoadFailed",
  },
} as const;

export const guestInitializingState = historyMachineSetup.createStateConfig({
  on: {
    ChatLocalHistoryLoaded: {
      target: "ready",
      actions: "applyLocalHistoryLoaded",
    },
    ChatNetworkHistoryLoaded: {
      target: "ready",
      actions: "applyNetworkHistoryLoaded",
    },
    ChatHistoryLoadFailed: {
      target: "ready",
      actions: "markHistoryLoadFailed",
    },
  },
});

export const userInitializingState = historyMachineSetup.createStateConfig({
  on: {
    ChatLocalHistoryLoaded: {
      target: "ready",
      actions: "applyLocalHistoryLoaded",
    },
    ChatNetworkHistoryLoaded: [
      {
        guard: ({ context, event }) =>
          event.type === "ChatNetworkHistoryLoaded" &&
          context.paymentUnlockPending &&
          shouldPromptUnlockHistory(event.output.messages),
        target: "ready",
        actions: "showUnlockHistoryPromptFromNetwork",
      },
      {
        target: "ready",
        actions: "applyNetworkHistoryLoadedAndClearPayment",
      },
    ],
    ChatHistoryLoadFailed: {
      target: "ready",
      actions: "markHistoryLoadFailed",
    },
  },
});
