import styles from './index.module.less';
import { useEffect, useState, useRef, useMemo, useContext } from 'react';
import { Input, message, Tooltip } from 'antd';
import ShowRightIcon from './assets/think-progress-icon.svg';
import { MindsearchContext } from './provider/context';
import ChatRight from './components/chat-right';
import { useNavigate, useParams } from 'react-router-dom';
import { fetchEventSource } from '@microsoft/fetch-event-source';
import SessionItem from './components/session-item';
import classNames from 'classnames';
import Notice from './components/notice';

interface INodeInfo {
    isEnd?: boolean; // 该节点是否结束
    current_node?: string;
    thinkingData?: string; // step1 思考
    queries?: [];
    readingData?: string; // step2 思考
    searchList?: [];
    conclusion?: string; // 节点的结论
    selectedIds?: number[];
    subQuestion?: string; // 节点的标题
    conclusionRef: any[];
    outputing?: boolean;
};

interface IFormattedData {
    question?: string;
    nodes?: any;
    adjacency_list?: object;
    response?: string;
    responseRefList?: any[];
    chatIsOver?: boolean;
};

interface INodeItem {
    id: string;
    name: string;
    state: number;
};

class FatalError extends Error { };
class RetriableError extends Error { };

const MindSearchCon = () => {
    const navigate = useNavigate();
    const params = useParams<{ id: string; robotId: string }>();
    const [qaList, setQaList] = useState<IFormattedData[]>([]);
    const [formatted, setFormatted] = useState<IFormattedData>({});
    const [question, setQuestion] = useState('');
    const [stashedQuestion, setStashedQuestion] = useState<string>('');
    const [newChatTip, setNewChatTip] = useState<Boolean>(false);
    const [singleObj, setSingleObj] = useState<any>(null);
    const [isEnd, setIsEnd] = useState(false);
    const [inputFocused, setFocused] = useState(false);
    // 一轮完整对话结束
    const [chatIsOver, setChatIsOver] = useState(true);

    const [currentNodeInfo, setCurrentNode] = useState<any>(null);
    const [currentNodeName, setCurrentNodeName] = useState<string>('');
    const [activeNode, setActiveNode] = useState<string>('');
    // 是否展示右侧内容
    const [showRight, setShowRight] = useState(false);
    const [adjList, setAdjList] = useState<any>({});
    const [historyNode, setHistoryNode] = useState<any>(null);

    const [hasNewChat, setHasNewChat] = useState(false);

    // 新开会话
    const openNewChat = () => {
        location.reload();
    };

    const toggleRight = () => {
        setShowRight(!showRight);
    };

    // 渲染过程中保持渲染文字可见
    const keepScrollTop = () => {
        const divA = document.getElementById('chatArea') as HTMLDivElement;
        const divB = document.getElementById('messageWindowId') as HTMLDivElement;
        // 获取 divB 的当前高度
        const bHeight = divB.offsetHeight;

        // 检查 divA 是否需要滚动(即 divB 的高度是否大于 divA 的可视高度)
        if (bHeight > divA.offsetHeight) {
            // 滚动到 divB 的底部在 divA 的可视区域内  
            divA.scrollTop = bHeight - divA.offsetHeight + 30;
        }
    };

    const initPageState = () => {
        setSingleObj(null);
        setCurrentNodeName('');
        setCurrentNode(null);
        setFormatted({});
        setAdjList({});
        setShowRight(false);
        setIsEnd(false);
    };

    const responseTimer: any = useRef(null);

    useEffect(() => {
        // console.log('[ms]---', formatted, chatIsOver, responseTimer.current);
        if (chatIsOver && formatted?.response) {
            // 一轮对话结束
            setQaList((pre) => {
                return pre.concat(formatted);
            });
            initPageState();
            setCurrentNodeName('customer-0');
        }
        if (!chatIsOver && !responseTimer.current) {
            responseTimer.current = setInterval(() => {
                keepScrollTop();
            }, 50);
        }
        if (responseTimer.current && chatIsOver) {
            // 如果 isEnd 变为 false,清除定时器  
            clearInterval(responseTimer.current);
            responseTimer.current = null;
        }
    }, [formatted?.response, chatIsOver, responseTimer.current, newChatTip]);

    useEffect(() => {
        if (formatted?.question) {
            setHistoryNode(null);
            setChatIsOver(false);
        }
    }, [formatted?.question]);

    // 存储节点信息
    const stashNodeInfo = (fullInfo: any, nodeName: string) => {
        // console.log('stash node info------', fullInfo, fullInfo?.response?.stream_state);
        const content = JSON.parse(fullInfo?.response?.content || '{}') || {};
        const searchListStashed: any = Object.keys(content).map((item) => {
            return { id: item, ...content[item] };
        });
        const stashedList = JSON.parse(localStorage?.stashedNodes || '{}');
        const nodeInfo = stashedList[nodeName] || {};

        if (fullInfo?.content) {
            nodeInfo.subQuestion = fullInfo.content;
        }
        if (fullInfo?.response?.formatted?.thought) {
            // step1 思考
            if (!nodeInfo?.readingData && !nodeInfo?.queries?.length) {
                nodeInfo.thinkingData = fullInfo?.response?.formatted?.thought;
            }

            // step2 思考
            if (nodeInfo?.thinkingData && nodeInfo?.queries?.length && nodeInfo?.searchList?.length && !nodeInfo?.selectedIds?.length && !nodeInfo?.conclusion) {
                nodeInfo.readingData = fullInfo?.response?.formatted?.thought;
            }

            // conclusion
            if (nodeInfo?.startConclusion && fullInfo?.response?.stream_state === 1) {
                nodeInfo.conclusion = fullInfo?.response?.formatted?.thought;
            }
        }
        if (fullInfo?.response?.formatted?.action?.parameters?.query?.length && !nodeInfo.queries?.length) {
            nodeInfo.queries = fullInfo?.response?.formatted.action.parameters.query;
        }

        if (searchListStashed?.length && !nodeInfo.conclusionRef) {
            nodeInfo.searchList = searchListStashed;
            nodeInfo.conclusionRef = content;
        }

        if (Array.isArray(fullInfo?.response?.formatted?.action?.parameters?.select_ids) && !nodeInfo?.selectedIds?.length) {
            nodeInfo.selectedIds = fullInfo?.response?.formatted.action.parameters.select_ids;
            nodeInfo.startConclusion = true;
        }

        if (fullInfo?.response?.stream_state) {
            nodeInfo.outputing = true;
        } else {
            nodeInfo.outputing = false;
        }

        const nodesList: any = {};
        nodesList[nodeName] = {
            current_node: nodeName,
            ...nodeInfo,
        };
        window.localStorage.stashedNodes = JSON.stringify({ ...stashedList, ...nodesList });
    };

    const formatData = (obj: any) => {
        // 嫦娥6号上有哪些国际科学载荷?它们的作用分别是什么?
        try {
            // 更新邻接表
            if (obj?.response?.formatted?.adjacency_list) {
                setAdjList(obj.response?.formatted?.adjacency_list);
            }

            if (!obj?.current_node && obj?.response?.formatted?.thought && obj?.response?.stream_state === 1) {
                // 有thought,没有node, planner思考过程
                setFormatted((pre: IFormattedData) => {
                    return {
                        ...pre,
                        response: obj.response.formatted.thought,
                    };
                });
            }
            if (obj?.response?.formatted?.ref2url && !formatted?.responseRefList) {
                setFormatted((pre: IFormattedData) => {
                    return {
                        ...pre,
                        responseRefList: obj?.response?.formatted?.ref2url,
                    };
                });
            }
            if (obj?.current_node || obj?.response?.formatted?.node) {
                // 有node, 临时存储node信息
                stashNodeInfo(obj?.response?.formatted?.node?.[obj.current_node], obj.current_node);
            }
        } catch (err) {
            console.log(err);
        }
    };

    const handleError = (errCode: number, msg: string) => {
        message.warning(msg || '请求出错了,请稍后再试');
        if (errCode === -20032 || errCode === -20033 || errCode === -20039) {
            // 敏感词校验失败, 新开会话
            openNewChat();
            return;
        }
        console.log('handle error------', msg);
        setChatIsOver(true);
        initPageState();
    };

    const startEventSource = () => {
        console.log('start event--------');
        if (qaList?.length > 4) {
            setNewChatTip(true);
            message.warning('对话数已达上限,请在新对话中聊天');
            keepScrollTop();
            return;
        }
        setFormatted({ ...formatted, question });
        setQuestion('');
        setChatIsOver(false);
        const ctrl = new AbortController();
        const url = '/solve';
        // const queryData = {
        //     cancel: true,
        //     prompt: question,
        // };
        const postData = {
            inputs: question
        }
        fetchEventSource(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(postData),
            openWhenHidden: true,
            signal: ctrl.signal,
            onmessage(ev) {
                try {
                    const res = (ev?.data && JSON.parse(ev.data)) || null;
                    if (res?.response?.stream_state === 0) {
                        setChatIsOver(true);
                        setFormatted((pre: IFormattedData) => {
                            return {
                                ...pre,
                                chatIsOver: true,
                            };
                        });
                    } else {
                        formatData(res);
                        setSingleObj(res);
                    }
                } catch (err) {
                    console.log('error on sse---', err);
                    handleError(0, '请求出错了,请稍后再试!');
                }
            },
            onerror(err) {
                console.log('error on sse---', err);
                handleError(0, '');
                ctrl.abort();
                if (err instanceof FatalError) {
                    throw err;
                }
            },
            onclose() {
                // params?.id && handleUpdateHistoryItem(params?.id);
            }
        });
    };

    // 点击节点
    const handleNodeClick = (node: string, idx: number) => {
        if (isEnd && !chatIsOver) return; // 当节点输出完成,最终response进行中,不允许点击按钮,点击无效
        const isFromHistory = qaList?.[idx]?.nodes?.[node];
        setShowRight(true);
        setActiveNode(node);

        if (isFromHistory) {
            const info = qaList?.[idx]?.nodes?.[node];

            if (!info) {
                message.error('没有读取到节点信息');
            }
            setHistoryNode(info);
        } else {
            setCurrentNodeName(node);
        }
    };

    // 解析历史记录或者搜索返回的数据
    const formatHistoryNode = (originNodeInfo: any) => {
        // console.log('format history node--------', originNodeInfo);
        const searchContent = JSON.parse(originNodeInfo?.memory?.[1]?.content || '{}') || {};
        const searchListStashed: any = Object.keys(searchContent).map((item) => {
            return { id: item, ...searchContent[item] };
        });

        const nodeInfo: INodeInfo = {
            current_node: originNodeInfo?.current_node || String(Date.now()),
            thinkingData: originNodeInfo?.memory?.[0]?.formatted?.thought || '', // step1 思考
            queries: originNodeInfo?.memory?.[0]?.formatted?.action?.parameters?.query || [],
            readingData: originNodeInfo?.memory?.[2]?.formatted?.thought || '', // step2 思考
            searchList: searchListStashed,
            conclusionRef: searchContent,
            conclusion: originNodeInfo?.memory?.[4]?.formatted?.thought || '', // 节点的结论
            selectedIds: originNodeInfo?.memory?.[2]?.formatted?.action?.parameters?.select_ids || [],
            subQuestion: originNodeInfo?.content, // 节点的标题
            isEnd: true,
            outputing: false
        };
        return nodeInfo;
    };

    const createSseChat = () => {
        if (submitDisabled) {
            return;
        }
        setQuestion(stashedQuestion);
        setStashedQuestion('');
        setCurrentNodeName('customer-0');
    };

    const checkNodesOutputFinish = () => {
        const adjListStr = JSON.stringify(adjList);
        // 服务端没有能准确描述所有节点输出完成的状态,前端从邻接表信息中寻找response信息,不保证完全准确,因为也可能不返回
        if (adjListStr.includes('"name":"response"')) {
            setIsEnd(true);
        }
    };

    useEffect(() => {
        if (!adjList) return;
        if (isEnd) {
            // 所有节点输出完成时收起右侧
            setShowRight(false);
        } else {
            checkNodesOutputFinish();
        }
        setFormatted((pre: IFormattedData) => {
            return {
                ...pre,
                adjacency_list: adjList,
            };
        });
    }, [adjList, isEnd]);

    useEffect(() => {
        const findStashNode = localStorage?.stashedNodes && JSON.parse(localStorage?.stashedNodes || '{}');
        if (!findStashNode || !currentNodeName) return;
        currentNodeName === 'customer-0' ? setCurrentNode(null) : setCurrentNode(findStashNode?.[currentNodeName]);
        currentNodeName !== 'customer-0' && setShowRight(true);
    }, [currentNodeName, localStorage?.stashedNodes]);

    useEffect(() => {
        if (!singleObj) return;
        if ((!currentNodeName || currentNodeName === 'customer-0') && singleObj?.current_node) {
            setCurrentNodeName(singleObj?.current_node);
        }
    }, [singleObj, currentNodeName]);

    useEffect(() => {
        if (question) {
            startEventSource();
        }
    }, [question]);

    useEffect(() => {
        if (!showRight) {
            setActiveNode('');
        }
    }, [showRight]);

    useEffect(() => {
        localStorage.stashedNodes = '';
        localStorage.reformatStashedNodes = '';

        return () => {
            // 返回清理函数,确保组件卸载时清除定时器  
            if (responseTimer.current) {
                clearInterval(responseTimer.current);
                responseTimer.current = null;
            }
        };
    }, []);

    const submitDisabled = useMemo(() => {
        return newChatTip || !stashedQuestion || !chatIsOver;
    }, [newChatTip, stashedQuestion, chatIsOver]);

    return (
        <MindsearchContext.Provider value={{
            isEnd,
            chatIsOver,
            activeNode: activeNode
        }}>
            <div className={styles.mainPage} style={!showRight ? { maxWidth: '840px' } : {}}>
                <div className={styles.chatContent}>
                    <div className={classNames(
                        styles.top,
                        (isEnd && !chatIsOver) ? styles.mb12 : ''
                    )} id="chatArea">
                        <div id="messageWindowId">
                            {qaList.length > 0 &&
                                qaList.map((item: IFormattedData, idx) => {
                                    return (
                                        <div key={`qa-item-${idx}`} className={styles.qaItem}>
                                            {
                                                item.question && <SessionItem
                                                    item={item}
                                                    handleNodeClick={handleNodeClick}
                                                    idx={idx}
                                                    key={`session-item-${idx}`}
                                                />
                                            }
                                        </div>
                                    );
                                })
                            }
                            {
                                formatted?.question &&
                                <SessionItem
                                    item={{ ...formatted, chatIsOver, isEnd, adjacency_list: adjList }}
                                    handleNodeClick={handleNodeClick}
                                    idx={qaList.length}
                                />
                            }
                        </div>
                        {newChatTip && (
                            <div className={styles.newChatTip}>
                                <span>
                                    对话数已达上限,请在 <a onClick={openNewChat}>新对话</a> 中聊天
                                </span>
                            </div>
                        )}
                    </div>
                    <div className={classNames(
                        styles.input,
                        inputFocused ? styles.focus : ''
                    )}>
                        <div className={styles.inputMain}>
                            <div className={styles.inputMainBox}>
                                <Input
                                    className={styles.textarea}
                                    variant="borderless"
                                    value={stashedQuestion}
                                    placeholder={'开始提问吧'}
                                    onChange={(e) => {
                                        setStashedQuestion(e.target.value);
                                    }}
                                    onPressEnter={createSseChat}
                                    onFocus={() => { setFocused(true) }}
                                    onBlur={() => { setFocused(false) }}
                                />
                                <div className={classNames(styles.send, submitDisabled && styles.disabled)} onClick={createSseChat}>
                                    <i className="iconfont icon-Frame1" />
                                </div>
                            </div>
                        </div>
                    </div>
                    <Notice />
                </div>
                {showRight ? (
                    <ChatRight
                        nodeInfo={currentNodeInfo}
                        historyNode={historyNode}
                        toggleRight={toggleRight}
                        key={currentNodeName}
                        chatIsOver={chatIsOver}
                    />
                ) : (
                    <div className={styles.showRight}>
                        <div className={classNames(
                            styles.actionIcon,
                            isEnd && !chatIsOver ? styles.forbidden : ''
                        )} onClick={toggleRight}>
                            <Tooltip placement="leftTop" title="思考过程">
                                <img src={ShowRightIcon} />
                            </Tooltip>
                        </div>
                    </div>
                )}
            </div>
        </MindsearchContext.Provider>
    );
};

export default MindSearchCon;