/**
 * Chat 状态机（XState v5）
 *
 * 登录态流转约束：
 *   - 未登录：可以进入游客登录 / 其他登录。
 *   - 游客登录：只可以升级为其他登录，不响应退出。
 *   - 其他登录：可以退出，不响应游客登录 / 重复其他登录。
 *
 * 状态结构（parent state 模式）：
 *   - `idle`：屏没挂 / 登出
 *   - `guestSession`（parent）：游客会话
 *   - `userSession`（parent）：其他登录用户会话
 *
 * init 任务：
 *   - guestSession.initializing：loadHistory
 *   - userSession.initializing：loadHistory
 *   - 每个任务都是独立 actor，不互相等待（除非 `always` barrier）
 *
 * 消息发送路径（业务事实）：
 *   - `ChatSendMessage` 只负责即时追加用户消息 + 入队，不进入 sending 子状态
 *   - guestSession / userSession：队列串行走 HTTP，限制以后端 `lockDetail` 为准
 *   - `pendingReplyCount` 跟踪待回复数量，`isReplyingAI` 由计数派生
 *
 * 发送能力：
 *   - 前端不再处理本地消息额度；游客 / 注册用户均以后端响应为准。
 *   - 后端返回 `cannotSendReason="insufficient_credits"` 时展示充值引导。
 *
 */

import { setup, assign, sendTo } from "xstate";

import { ChatState, initialState } from "./chat-state";
import type { ChatEvent } from "./chat-events";
import {
  applyHttpSendOutput,
  applyHistoryLoadedOutput,
  applyNetworkHistoryLoadedOutput,
  countLockedHistoryMessages,
  shouldAutoUnlockHistory,
  shouldPromptUnlockHistory,
} from "./chat-machine.helpers";
import {
  loadHistoryActor,
  loadMoreHistoryActor,
} from "./chat-history-flow";
import {
  appendGuestUserImageAction,
  appendUserImageAction,
} from "./chat-media-flow";
import {
  appendGuestUserMessageAction,
  appendQueuedSendErrorMessageAction,
  appendUserMessageAction,
  applyQueuedHttpOutputAction,
  clearUpgradePromptAction,
  httpMessageQueueActor,
  markQueuedSendStartedAction,
  sendMessageHttpActor,
} from "./chat-send-flow";
import {
  applyUnlockMessageSucceededAction,
  clearUnlockPaywallRequestAction,
  dismissUnlockHistoryPromptAction,
  markPaymentUnlockPendingAction,
  markUnlockHistoryFailedAction,
  markUnlockHistoryStartedAction,
  markUnlockMessageStartedAction,
  requestUnlockPaymentFromErrorAction,
  requestUnlockPaymentFromOutputAction,
  showUnlockHistoryPromptAction,
  unlockHistoryActor,
  unlockMessageActor,
} from "./chat-unlock-flow";

// 重新导出 State / Event 类型，保持 machine 文件的公共 API 不变
export type { ChatState } from "./chat-state";
export { initialState } from "./chat-state";
export type { ChatEvent } from "./chat-events";

// ============================================================
// Machine
// ============================================================
export const chatMachine = setup({
  types: {
    context: {} as ChatState,
    events: {} as ChatEvent,
  },
  actors: {
    loadHistory: loadHistoryActor,
    loadMoreHistory: loadMoreHistoryActor,
    sendMessageHttp: sendMessageHttpActor,
    httpMessageQueue: httpMessageQueueActor,
    unlockHistory: unlockHistoryActor,
    unlockMessage: unlockMessageActor,
  },
  actions: {
    appendGuestUserMessage: appendGuestUserMessageAction,
    appendUserMessage: appendUserMessageAction,
    appendQueuedSendErrorMessage: appendQueuedSendErrorMessageAction,
    markQueuedSendStarted: markQueuedSendStartedAction,
    applyQueuedHttpOutput: applyQueuedHttpOutputAction,
    clearUpgradePrompt: clearUpgradePromptAction,
    appendGuestUserImage: appendGuestUserImageAction,
    appendUserImage: appendUserImageAction,
    markPaymentUnlockPending: markPaymentUnlockPendingAction,
    showUnlockHistoryPrompt: showUnlockHistoryPromptAction,
    dismissUnlockHistoryPrompt: dismissUnlockHistoryPromptAction,
    markUnlockHistoryStarted: markUnlockHistoryStartedAction,
    markUnlockHistoryFailed: markUnlockHistoryFailedAction,
    markUnlockMessageStarted: markUnlockMessageStartedAction,
    applyUnlockMessageSucceeded: applyUnlockMessageSucceededAction,
    requestUnlockPaymentFromOutput: requestUnlockPaymentFromOutputAction,
    requestUnlockPaymentFromError: requestUnlockPaymentFromErrorAction,
    clearUnlockPaywallRequest: clearUnlockPaywallRequestAction,
    enqueueMessage: sendTo("messageQueue", ({ event }) => event),

    startGuestSession: assign(() => ({
      ...initialState,
    })),

    startUserSession: assign(() => ({
      ...initialState,
    })),

    clearChatSession: assign(() => ({
      ...initialState,
    })),

    applyLocalHistoryLoaded: assign(({ event }) => {
      if (event.type !== "ChatLocalHistoryLoaded") return {};
      return applyHistoryLoadedOutput(event.output);
    }),

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

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

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

    markHistoryLoadFailed: assign({
      isLoadingMore: false,
      historyLoaded: true,
    }),
  },
}).createMachine({
  id: "chat",
  initial: "idle",
  context: initialState,
  states: {
    idle: {
      on: {
        ChatGuestLogin: {
          target: "#chat.guestSession",
          actions: "startGuestSession",
        },
        ChatUserLogin: {
          target: "#chat.userSession",
          actions: "startUserSession",
        },
      },
    },

    guestSession: {
      invoke: [
        {
          id: "messageQueue",
          src: "httpMessageQueue",
        },
        {
          id: "loadHistory",
          src: "loadHistory",
        },
      ],
      on: {
        ChatUserLogin: {
          target: "#chat.userSession",
          actions: "startUserSession",
        },
        ChatNetworkHistoryLoaded: {
          actions: "applyNetworkHistoryLoaded",
        },
        ChatHistoryLoadFailed: {
          actions: "markHistoryLoadFailed",
        },
        ChatQueuedSendStarted: {
          actions: "markQueuedSendStarted",
        },
        ChatQueuedHttpDone: {
          actions: "applyQueuedHttpOutput",
        },
        ChatQueuedSendError: {
          actions: "appendQueuedSendErrorMessage",
        },
      },
      initial: "initializing",
      states: {
        initializing: {
          on: {
            ChatLocalHistoryLoaded: {
              target: "ready",
              actions: "applyLocalHistoryLoaded",
            },
            ChatNetworkHistoryLoaded: {
              target: "ready",
              actions: "applyNetworkHistoryLoaded",
            },
            ChatHistoryLoadFailed: {
              target: "ready",
              actions: "markHistoryLoadFailed",
            },
          },
        },
        ready: {
          on: {
            ChatSendMessage: {
              actions: ["appendGuestUserMessage", "enqueueMessage"],
              guard: ({ context, event }) =>
                context.canSendMessage && event.content.trim().length > 0,
            },
            ChatSendImage: {
              actions: "appendGuestUserImage",
              target: "sending",
            },
            // 游客不支持翻页历史，发送消息统一走 HTTP 队列。
          },
        },
        sending: {
          invoke: {
            src: "sendMessageHttp",
            input: ({ event }) => ({
              content: event.type === "ChatSendMessage" ? event.content : "",
            }),
            onDone: {
              target: "ready",
              actions: assign(({ context, event }) =>
                applyHttpSendOutput(context, event.output),
              ),
            },
            onError: {
              target: "ready",
              actions: assign({ isReplyingAI: false }),
            },
          },
        },
      },
    },

    userSession: {
      invoke: [
        {
          id: "messageQueue",
          src: "httpMessageQueue",
        },
        {
          id: "loadHistory",
          src: "loadHistory",
        },
      ],
      on: {
        ChatGuestLogin: {
          target: "#chat.guestSession",
          actions: "startGuestSession",
        },
        ChatLogout: {
          target: "#chat.idle",
          actions: "clearChatSession",
        },
        ChatNetworkHistoryLoaded: [
          {
            guard: ({ context, event }) =>
              event.type === "ChatNetworkHistoryLoaded" &&
              context.paymentUnlockPending &&
              shouldAutoUnlockHistory(event.output.messages),
            target: ".unlockingHistory",
            actions: [
              "applyNetworkHistoryLoadedAndClearPayment",
              "markUnlockHistoryStarted",
            ],
          },
          {
            guard: ({ context, event }) =>
              event.type === "ChatNetworkHistoryLoaded" &&
              context.paymentUnlockPending &&
              shouldPromptUnlockHistory(event.output.messages),
            target: ".ready",
            actions: "showUnlockHistoryPromptFromNetwork",
          },
          {
            guard: ({ context }) =>
              !context.isUnlockingHistory && !context.isUnlockingMessage,
            actions: "applyNetworkHistoryLoaded",
          },
        ],
        ChatHistoryLoadFailed: {
          actions: "markHistoryLoadFailed",
        },
        ChatQueuedSendStarted: {
          actions: "markQueuedSendStarted",
        },
        ChatQueuedHttpDone: {
          actions: "applyQueuedHttpOutput",
        },
        ChatQueuedSendError: {
          actions: "appendQueuedSendErrorMessage",
        },
        ChatPaymentSucceeded: [
          {
            guard: ({ context }) =>
              context.historyLoaded && shouldAutoUnlockHistory(context.messages),
            target: ".unlockingHistory",
            actions: ["clearUpgradePrompt", "markUnlockHistoryStarted"],
          },
          {
            guard: ({ context }) =>
              context.historyLoaded &&
              shouldPromptUnlockHistory(context.messages),
            actions: ["clearUpgradePrompt", "showUnlockHistoryPrompt"],
          },
          {
            guard: ({ context }) => !context.historyLoaded,
            actions: ["clearUpgradePrompt", "markPaymentUnlockPending"],
          },
          {
            guard: ({ context }) => context.historyLoaded,
            actions: ["clearUpgradePrompt", "dismissUnlockHistoryPrompt"],
          },
        ],
        ChatUnlockHistoryConfirmed: {
          target: ".unlockingHistory",
          actions: "markUnlockHistoryStarted",
        },
        ChatUnlockHistoryDismissed: {
          actions: "dismissUnlockHistoryPrompt",
        },
        ChatUnlockPaywallNavigationConsumed: {
          actions: "clearUnlockPaywallRequest",
        },
      },
      initial: "initializing",
      states: {
        initializing: {
          on: {
            ChatLocalHistoryLoaded: {
              target: "ready",
              actions: "applyLocalHistoryLoaded",
            },
            ChatNetworkHistoryLoaded: [
              {
                guard: ({ context, event }) =>
                  event.type === "ChatNetworkHistoryLoaded" &&
                  context.paymentUnlockPending &&
                  shouldAutoUnlockHistory(event.output.messages),
                target: "unlockingHistory",
                actions: [
                  "applyNetworkHistoryLoadedAndClearPayment",
                  "markUnlockHistoryStarted",
                ],
              },
              {
                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",
            },
          },
        },
        ready: {
          on: {
            ChatSendMessage: {
              guard: ({ context, event }) =>
                context.canSendMessage && event.content.trim().length > 0,
              actions: ["appendUserMessage", "enqueueMessage"],
            },
            ChatSendImage: {
              actions: "appendUserImage",
            },
            ChatLoadMoreHistory: {
              target: "loadingMore",
            },
            ChatUnlockMessageRequested: {
              guard: ({ event }) => event.messageId.trim().length > 0,
              target: "unlockingMessage",
              actions: "markUnlockMessageStarted",
            },
          },
        },
        sendingViaHttp: {
          invoke: {
            src: "sendMessageHttp",
            input: ({ event }) => ({
              content: event.type === "ChatSendMessage" ? event.content : "",
            }),
            onDone: {
              target: "ready",
              actions: assign(({ context, event }) =>
                applyHttpSendOutput(context, event.output),
              ),
            },
            onError: {
              target: "ready",
              actions: assign({ isReplyingAI: false }),
            },
          },
        },
        loadingMore: {
          invoke: {
            src: "loadMoreHistory",
            input: ({ context }) => ({ offset: context.historyOffset }),
            onDone: {
              target: "ready",
              actions: assign(({ context, event }) => ({
                messages: [...event.output.messages, ...context.messages],
                isLoadingMore: false,
                hasMore: event.output.hasMore,
                historyOffset: event.output.newOffset,
              })),
            },
            onError: {
              target: "ready",
              actions: assign({ isLoadingMore: false }),
            },
          },
        },
        unlockingHistory: {
          invoke: {
            id: "unlockHistory",
            src: "unlockHistory",
            onDone: {
              target: "ready",
              actions: assign(({ event }) => {
                const lockedHistoryCount = countLockedHistoryMessages(
                  event.output.messages,
                );
                const insufficientBalance =
                  !event.output.unlocked &&
                  event.output.reason === "insufficient_balance";
                return {
                  messages: event.output.messages,
                  hasMore: event.output.hasMore,
                  historyOffset: event.output.newOffset,
                  historyLoaded: true,
                  paymentUnlockPending: false,
                  unlockHistoryPromptVisible: insufficientBalance,
                  lockedHistoryCount,
                  isUnlockingHistory: false,
                  unlockHistoryError: insufficientBalance
                    ? `Insufficient credits. You still need ${event.output.shortfallCredits} credits.`
                    : null,
                };
              }),
            },
            onError: {
              target: "ready",
              actions: "markUnlockHistoryFailed",
            },
          },
        },
        unlockingMessage: {
          invoke: {
            id: "unlockMessage",
            src: "unlockMessage",
            input: ({ context }) => ({
              messageId: context.unlockingMessageId ?? "",
            }),
            onDone: [
              {
                guard: ({ event }) => event.output.response.unlocked,
                target: "ready",
                actions: "applyUnlockMessageSucceeded",
              },
              {
                target: "ready",
                actions: "requestUnlockPaymentFromOutput",
              },
            ],
            onError: {
              target: "ready",
              actions: "requestUnlockPaymentFromError",
            },
          },
        },
      },
    },
  },
});

export type ChatMachine = typeof chatMachine;
