"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.useChatRuntime = useChatRuntime;
const react_1 = __importDefault(require("react"));
const constants_1 = require("../types/constants");
const use_chat_polling_1 = require("./use-chat-polling");
/**
 * 聊天运行时 Hook
 *
 * 协调整个会话状态机：submit → polling → done / error / cancel
 * 支持受控与非受控两种消息管理模式。
 * 当 `autoInit=true` 时，mount 后自动调用 adapter.init 初始化会话。
 */
function useChatRuntime(options) {
    const { adapter, context, initialConversationId, pollingConfig, onEvent, controlledMessages, onMessagesChange, autoInit, initWhen, enableHistory, historyPageSize = constants_1.DEFAULT_HISTORY_PAGE_SIZE, } = options;
    const [internalMessages, setInternalMessages] = react_1.default.useState([]);
    const [isPolling, setIsPolling] = react_1.default.useState(false);
    const [generatingMessageId, setGeneratingMessageId] = react_1.default.useState(null);
    const [initStatus, _setInitStatus] = react_1.default.useState(autoInit ? 'pending' : 'idle');
    const [retryCount, setRetryCount] = react_1.default.useState(0);
    const initStatusRef = react_1.default.useRef(autoInit ? 'pending' : 'idle');
    const setInitStatus = react_1.default.useCallback((status) => {
        initStatusRef.current = status;
        _setInitStatus(status);
    }, []);
    const conversationIdRef = react_1.default.useRef(initialConversationId !== null && initialConversationId !== void 0 ? initialConversationId : null);
    const requestTokenRef = react_1.default.useRef(0);
    const isControlled = controlledMessages !== undefined;
    const messages = isControlled ? controlledMessages : internalMessages;
    const messagesRef = react_1.default.useRef(messages);
    react_1.default.useEffect(() => {
        messagesRef.current = messages;
    }, [messages]);
    const setMessages = react_1.default.useCallback((action) => {
        if (isControlled) {
            // 使用 ref 获取最新 messages，避免轮询回调中的闭包拿到过期的 controlledMessages
            const prev = messagesRef.current;
            const next = typeof action === 'function' ? action(prev) : action;
            messagesRef.current = next;
            onMessagesChange === null || onMessagesChange === void 0 ? void 0 : onMessagesChange(next);
        }
        else {
            setInternalMessages((prev) => {
                const next = typeof action === 'function' ? action(prev) : action;
                onMessagesChange === null || onMessagesChange === void 0 ? void 0 : onMessagesChange(next);
                return next;
            });
        }
    }, [isControlled, onMessagesChange]);
    // ---- 历史加载状态 ----
    const [isHistoryLoading, setIsHistoryLoading] = react_1.default.useState(false);
    const [historyHasMore, setHistoryHasMore] = react_1.default.useState(!!enableHistory);
    const historyCursorRef = react_1.default.useRef(undefined);
    const historyTokenRef = react_1.default.useRef(0);
    /** 在该消息之前展示「新会话」分割线（prepend 历史前的首条消息 id，仅设一次） */
    const [historySessionDividerBeforeMessageId, setHistorySessionDividerBeforeMessageId] = react_1.default.useState(null);
    react_1.default.useEffect(() => {
        if (!enableHistory) {
            setHistorySessionDividerBeforeMessageId(null);
        }
    }, [enableHistory]);
    react_1.default.useEffect(() => {
        if (historySessionDividerBeforeMessageId &&
            !messages.some((m) => m.id === historySessionDividerBeforeMessageId)) {
            setHistorySessionDividerBeforeMessageId(null);
        }
    }, [messages, historySessionDividerBeforeMessageId]);
    const loadHistory = react_1.default.useCallback(async () => {
        var _a, _b;
        if (!enableHistory || !adapter.queryHistory || !historyHasMore || isHistoryLoading) {
            return;
        }
        setIsHistoryLoading(true);
        const token = ++historyTokenRef.current;
        onEvent === null || onEvent === void 0 ? void 0 : onEvent({ name: 'history_load_start' });
        try {
            const result = await adapter.queryHistory({
                conversationId: (_a = conversationIdRef.current) !== null && _a !== void 0 ? _a : '',
                cursor: historyCursorRef.current,
                pageSize: historyPageSize,
                context,
            });
            if (historyTokenRef.current !== token)
                return;
            const existingIds = new Set(messagesRef.current.map((m) => m.id));
            const deduped = result.messages.filter((m) => !existingIds.has(m.id));
            if (deduped.length > 0) {
                const firstIdBeforePrepend = (_b = messagesRef.current[0]) === null || _b === void 0 ? void 0 : _b.id;
                setMessages((prev) => [...deduped, ...prev]);
                if (firstIdBeforePrepend) {
                    setHistorySessionDividerBeforeMessageId((cur) => cur !== null && cur !== void 0 ? cur : firstIdBeforePrepend);
                }
            }
            historyCursorRef.current = result.nextCursor;
            setHistoryHasMore(result.hasMore);
            onEvent === null || onEvent === void 0 ? void 0 : onEvent({
                name: 'history_load_success',
                payload: {
                    count: deduped.length,
                    hasMore: result.hasMore,
                    nextCursor: result.nextCursor,
                },
            });
        }
        catch (err) {
            if (historyTokenRef.current !== token)
                return;
            onEvent === null || onEvent === void 0 ? void 0 : onEvent({
                name: 'history_load_error',
                payload: { error: err instanceof Error ? err.message : String(err) },
            });
        }
        finally {
            if (historyTokenRef.current === token) {
                setIsHistoryLoading(false);
            }
        }
    }, [
        enableHistory,
        adapter,
        historyHasMore,
        isHistoryLoading,
        historyPageSize,
        context,
        onEvent,
        setMessages,
    ]);
    const { startPolling, stopPolling, activeTokenRef } = (0, use_chat_polling_1.useChatPolling)({
        adapter,
        pollingConfig,
        onEvent,
    });
    // ---- autoInit 流程 ----
    react_1.default.useEffect(() => {
        if (!autoInit)
            return;
        // Gap 1: adapter 没有 init 方法时退化为 idle，不锁住输入区
        if (!adapter.init) {
            setInitStatus('idle');
            return;
        }
        // Gap 2: 前置条件未满足时保持 pending，等上下文就绪后再触发
        if (initWhen !== undefined && !initWhen)
            return;
        let cancelled = false;
        setInitStatus('pending');
        const doInit = async () => {
            onEvent === null || onEvent === void 0 ? void 0 : onEvent({ name: 'init_start' });
            try {
                const result = await adapter.init(context);
                if (cancelled)
                    return;
                if (!result || !result.conversationId || !result.respMessageId) {
                    setInitStatus('failed');
                    onEvent === null || onEvent === void 0 ? void 0 : onEvent({ name: 'init_error', payload: { reason: 'empty_result' } });
                    return;
                }
                conversationIdRef.current = result.conversationId;
                setInitStatus('success');
                onEvent === null || onEvent === void 0 ? void 0 : onEvent({
                    name: 'init_success',
                    payload: {
                        conversationId: result.conversationId,
                        respMessageId: result.respMessageId,
                    },
                });
                const placeholderId = `assistant-init-${Date.now()}`;
                const placeholderMessage = {
                    id: placeholderId,
                    role: 'assistant',
                    content: constants_1.PLACEHOLDER_GENERATING_TEXT,
                    status: 'pending',
                    time: Date.now(),
                };
                setMessages((prev) => [...prev, placeholderMessage]);
                setIsPolling(true);
                setGeneratingMessageId(placeholderId);
                const token = ++requestTokenRef.current;
                startPolling({
                    conversationId: result.conversationId,
                    messageId: result.respMessageId,
                    placeholderMessageId: placeholderId,
                    setMessages,
                    requestToken: token,
                    onDone: () => {
                        setIsPolling(false);
                        setGeneratingMessageId(null);
                    },
                });
            }
            catch {
                if (cancelled)
                    return;
                setInitStatus('failed');
                onEvent === null || onEvent === void 0 ? void 0 : onEvent({ name: 'init_error' });
            }
        };
        doInit();
        return () => {
            cancelled = true;
        };
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [autoInit, initWhen, retryCount]);
    // Gap 3: 初始化失败后的可恢复入口
    const retryInit = react_1.default.useCallback(() => {
        if (initStatusRef.current !== 'failed')
            return;
        setRetryCount((c) => c + 1);
    }, []);
    const handleSubmit = react_1.default.useCallback(async (value) => {
        if (!(value === null || value === void 0 ? void 0 : value.trim()))
            return;
        if (autoInit && initStatus === 'pending')
            return;
        onEvent === null || onEvent === void 0 ? void 0 : onEvent({ name: 'submit_start', payload: { prompt: value } });
        const userMessage = {
            id: `user-${Date.now()}`,
            role: 'user',
            content: value,
            status: 'done',
            time: Date.now(),
        };
        const placeholderId = `assistant-${Date.now()}`;
        const placeholderMessage = {
            id: placeholderId,
            role: 'assistant',
            content: constants_1.PLACEHOLDER_GENERATING_TEXT,
            status: 'pending',
            time: Date.now(),
        };
        setMessages((prev) => [...prev, userMessage, placeholderMessage]);
        setIsPolling(true);
        setGeneratingMessageId(placeholderId);
        stopPolling();
        const token = ++requestTokenRef.current;
        try {
            const result = await adapter.submit({
                userPrompt: value,
                conversationId: conversationIdRef.current,
                context,
            });
            if (activeTokenRef.current !== 0 && activeTokenRef.current !== token)
                return;
            conversationIdRef.current = result.conversationId;
            onEvent === null || onEvent === void 0 ? void 0 : onEvent({
                name: 'submit_success',
                payload: {
                    conversationId: result.conversationId,
                    respMessageId: result.respMessageId,
                },
            });
            startPolling({
                conversationId: result.conversationId,
                messageId: result.respMessageId,
                placeholderMessageId: placeholderId,
                setMessages,
                requestToken: token,
                onDone: () => {
                    setIsPolling(false);
                    setGeneratingMessageId(null);
                },
            });
        }
        catch {
            if (requestTokenRef.current !== token)
                return;
            setMessages((prev) => {
                const idx = prev.findIndex((m) => m.id === placeholderId);
                if (idx < 0)
                    return prev;
                const updated = [...prev];
                updated[idx] = {
                    ...updated[idx],
                    content: constants_1.ERROR_SUBMIT_TEXT,
                    status: 'error',
                };
                return updated;
            });
            setIsPolling(false);
            setGeneratingMessageId(null);
            onEvent === null || onEvent === void 0 ? void 0 : onEvent({ name: 'submit_error', payload: { prompt: value } });
        }
    }, [
        adapter,
        context,
        onEvent,
        setMessages,
        startPolling,
        stopPolling,
        activeTokenRef,
        autoInit,
        initStatus,
    ]);
    const handleCancel = react_1.default.useCallback(() => {
        stopPolling();
        setIsPolling(false);
        setGeneratingMessageId(null);
        setMessages((prev) => prev.filter((msg) => !(msg.role === 'assistant' && msg.status === 'pending')));
        onEvent === null || onEvent === void 0 ? void 0 : onEvent({ name: 'cancel' });
    }, [stopPolling, setMessages, onEvent]);
    return {
        messages,
        isPolling,
        generatingMessageId,
        conversationIdRef,
        handleSubmit,
        handleCancel,
        setMessages,
        initStatus,
        retryInit,
        isHistoryLoading,
        historyHasMore,
        loadHistory,
        historySessionDividerBeforeMessageId,
    };
}
