/**
 * 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` 由计数派生
 *
 * 配额：
 *   - 前端不再处理本地消息额度；游客 / 注册用户均以后端响应为准。
 *   - 后端返回 `lockDetail.reason="weekly_limit"` 且需要升级时展示会员引导。
 *
 */

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

import { todayString, Logger } from "@/utils";

import { ChatState, initialState } from "./chat-state";
import type { ChatEvent } from "./chat-events";
import {
  applyHttpSendOutput,
  applyHistoryLoadedOutput,
  beginPendingReply,
  countLockedHistoryMessages,
  finishPendingReply,
  shouldAutoUnlockHistory,
  shouldPromptUnlockHistory,
} from "./chat-machine.helpers";
import {
  loadHistoryActor,
  sendMessageHttpActor,
  loadMoreHistoryActor,
  httpMessageQueueActor,
  unlockHistoryActor,
} from "./chat-machine.actors";

const log = new Logger("StoresChatChatMachine");

// 重新导出 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,
    sendMessageHttp: sendMessageHttpActor,
    loadMoreHistory: loadMoreHistoryActor,
    httpMessageQueue: httpMessageQueueActor,
    unlockHistory: unlockHistoryActor,
  },
  actions: {
    enqueueMessage: sendTo("messageQueue", ({ event }) => event),

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

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

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

    appendGuestUserMessage: assign(({ context, event }) => {
      if (event.type !== "ChatSendMessage") return {};

      const today = todayString();
      log.debug("[chat-machine] appendGuestUserMessage", {
        contentLength: event.content.length,
        contentPreview: event.content.slice(0, 50),
        quotaMode: "server controlled",
        isReplyingAI: context.isReplyingAI,
      });

      return {
        messages: [
          ...context.messages,
          {
            content: event.content,
            isFromAI: false,
            date: today,
          },
        ],
        upgradePromptVisible: false,
        upgradeReason: null,
      };
    }),

    appendUserMessage: assign(({ context, event }) => {
      if (event.type !== "ChatSendMessage") return {};

      const today = todayString();
      log.debug("[chat-machine] appendUserMessage", {
        contentLength: event.content.length,
        contentPreview: event.content.slice(0, 50),
        isReplyingAI: context.isReplyingAI,
      });

      return {
        messages: [
          ...context.messages,
          {
            content: event.content,
            isFromAI: false,
            date: today,
          },
        ],
        upgradePromptVisible: false,
        upgradeReason: null,
      };
    }),

    appendGuestUserImage: assign(({ context, event }) => {
      if (event.type !== "ChatSendImage") return {};

      const today = todayString();
      log.debug("[chat-machine] appendGuestUserImage", {
        oldMessagesCount: context.messages.length,
        quotaMode: "server controlled",
      });
      return {
        messages: [
          ...context.messages,
          {
            content: "[Image]",
            isFromAI: false,
            date: today,
            imageUrl: event.imageBase64,
          },
        ],
        ...beginPendingReply(context),
        upgradePromptVisible: false,
        upgradeReason: null,
      };
    }),

    appendUserImage: assign(({ context, event }) => {
      if (event.type !== "ChatSendImage") return {};

      const today = todayString();
      log.debug("[chat-machine] appendUserImage", {
        oldMessagesCount: context.messages.length,
      });

      return {
        messages: [
          ...context.messages,
          {
            content: "[Image]",
            isFromAI: false,
            date: today,
            imageUrl: event.imageBase64,
          },
        ],
        ...beginPendingReply(context),
        upgradePromptVisible: false,
        upgradeReason: null,
      };
    }),

    appendQueuedSendErrorMessage: assign(({ context }) => {
      const messages = [
        ...context.messages,
        {
          content: "Something went wrong. Try sending again?",
          isFromAI: true,
          date: todayString(),
        },
      ];
      return { messages, ...finishPendingReply(context) };
    }),

    markQueuedSendStarted: assign(({ context }) => beginPendingReply(context)),

    applyQueuedHttpOutput: assign(({ context, event }) => {
      if (event.type !== "ChatQueuedHttpDone") return {};
      return applyHttpSendOutput(context, event.output);
    }),

    clearUpgradePrompt: assign(() => ({
      upgradePromptVisible: false,
      upgradeReason: null,
      canSendMessage: true,
      cannotSendReason: null,
      requiredCredits: 0,
      shortfallCredits: 0,
    })),

    markPaymentUnlockPending: assign(() => ({
      paymentUnlockPending: true,
      unlockHistoryError: null,
    })),

    showUnlockHistoryPrompt: assign(({ context }) => ({
      paymentUnlockPending: false,
      unlockHistoryPromptVisible: true,
      lockedHistoryCount: countLockedHistoryMessages(context.messages),
      unlockHistoryError: null,
    })),

    dismissUnlockHistoryPrompt: assign(() => ({
      paymentUnlockPending: false,
      unlockHistoryPromptVisible: false,
      unlockHistoryError: null,
    })),

    markUnlockHistoryStarted: assign(() => ({
      paymentUnlockPending: false,
      unlockHistoryPromptVisible: false,
      isUnlockingHistory: true,
      unlockHistoryError: null,
    })),

    markUnlockHistoryFailed: assign(() => ({
      isUnlockingHistory: false,
      unlockHistoryPromptVisible: true,
      unlockHistoryError: "Failed to unlock messages. Please try again.",
    })),
  },
}).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",
      },
      on: {
        ChatUserLogin: {
          target: "#chat.userSession",
          actions: "startUserSession",
        },
        ChatQueuedSendStarted: {
          actions: "markQueuedSendStarted",
        },
        ChatQueuedHttpDone: {
          actions: "applyQueuedHttpOutput",
        },
        ChatQueuedSendError: {
          actions: "appendQueuedSendErrorMessage",
        },
      },
      initial: "initializing",
      states: {
        initializing: {
          always: [
            {
              target: "ready",
              guard: ({ context }) => context.historyLoaded,
            },
          ],
          invoke: {
            id: "loadHistory",
            src: "loadHistory",
            onDone: {
              actions: assign(({ event }) =>
                applyHistoryLoadedOutput(event.output),
              ),
            },
            onError: {
              // 失败也标 loaded，不卡 init（让 UI 还是能进 ready，屏幕可能空）
              actions: assign({
                historyLoaded: true,
              }),
            },
          },
        },
        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",
      },
      on: {
        ChatLogout: {
          target: "#chat.idle",
          actions: "clearChatSession",
        },
        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",
        },
      },
      initial: "initializing",
      states: {
        initializing: {
          invoke: {
            src: "loadHistory",
            onDone: [
              {
                guard: ({ context, event }) =>
                  context.paymentUnlockPending &&
                  shouldAutoUnlockHistory(event.output.messages),
                target: "unlockingHistory",
                actions: [
                  assign(({ event }) => ({
                    ...applyHistoryLoadedOutput(event.output),
                    isLoadingMore: false,
                  })),
                  "markUnlockHistoryStarted",
                ],
              },
              {
                guard: ({ context, event }) =>
                  context.paymentUnlockPending &&
                  shouldPromptUnlockHistory(event.output.messages),
                target: "ready",
                actions: assign(({ event }) => ({
                  ...applyHistoryLoadedOutput(event.output),
                  isLoadingMore: false,
                  paymentUnlockPending: false,
                  unlockHistoryPromptVisible: true,
                  lockedHistoryCount: countLockedHistoryMessages(
                    event.output.messages,
                  ),
                  unlockHistoryError: null,
                })),
              },
              {
                target: "ready",
                actions: assign(({ event }) => ({
                  ...applyHistoryLoadedOutput(event.output),
                  isLoadingMore: false,
                  paymentUnlockPending: false,
                })),
              },
            ],
            onError: {
              target: "ready",
              actions: assign({
                isLoadingMore: false,
                historyLoaded: true,
              }),
            },
          },
        },
        ready: {
          on: {
            ChatSendMessage: {
              guard: ({ context, event }) =>
                context.canSendMessage && event.content.trim().length > 0,
              actions: ["appendUserMessage", "enqueueMessage"],
            },
            ChatSendImage: {
              actions: "appendUserImage",
            },
            ChatLoadMoreHistory: {
              target: "loadingMore",
            },
          },
        },
        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",
            },
          },
        },
      },
    },
  },
});

export type ChatMachine = typeof chatMachine;
