import {Suspense, useCallback, useContext, useEffect, useRef, useState} from "@wordpress/element";
import {GetChatbot, GetChatbots} from "../../admin/rest/chatbots";
import Chatbots from "../chatbots";
import {ChatbotPreviewContext} from "../../admin/components/contexts/chatbot-preview";
import useMobileChatLock from "../chatbots/hooks/use-mobile-chat-lock";

export default function ChatbotsGroups({id, autoOpen, attributes}) {
    const chatbotPreview = useContext(ChatbotPreviewContext);
    const [chatbotsGroups, setChatbotsGroups] = useState({});
    const [capturedState, setCapturedState] = useState(null);
    const openedChatbots = useRef({});
    const getActiveChatThemeVariant = useCallback(() => {
        if (typeof document === 'undefined') {
            return null;
        }
        const chatElements = document.querySelectorAll('.lbaic-grid .lbaic-chat');
        if (!chatElements.length) {
            return null;
        }
        const activeChat = chatElements[chatElements.length - 1];
        if (activeChat.classList.contains('lbaic-dark')) {
            return 'dark';
        }
        if (activeChat.classList.contains('lbaic-light')) {
            return 'light';
        }
        return null;
    }, []);

    const {setMobileLockState, releaseMobileChatLock} = useMobileChatLock({
        getActiveThemeVariant: getActiveChatThemeVariant,
    });

    const handleChatCloseStart = useCallback((uuid, side) => {
        if (!uuid) {
            return;
        }
        const simulatedOpened = {};
        Object.keys(openedChatbots.current).forEach(key => {
            simulatedOpened[key] = [...(openedChatbots.current[key] || [])];
        });
        if (side) {
            simulatedOpened[side] = simulatedOpened[side]?.filter(item => item !== uuid) || [];
        }
        const willHaveOpened = Object.values(simulatedOpened).some(items => items?.length);
        if (!willHaveOpened) {
            releaseMobileChatLock();
        }
    }, [releaseMobileChatLock, openedChatbots]);

    useEffect(() => {
        return () => {
            releaseMobileChatLock();
        }
    }, [releaseMobileChatLock]);

    // Get chatbots
    useEffect(() => {
        getChatbots();

        const handleLeadCaptured = (lead) => {
            setCapturedState(lead);
        }

        LimbChatbot.Hooks.addAction('limb.chatbot.lead_captured', 'limb/chatbot/lead_captured', handleLeadCaptured);

        return () => {
            LimbChatbot.Hooks.removeAction('limb.chatbot.lead_captured', 'limb/chatbot/lead_captured');
        }
    }, []);

    useEffect(() => {
        if (!chatbotPreview?.uuid) {
            return;
        }

        let chatbot, moveToOtherSide = false;
        for (const side in chatbotsGroups) {
            for (const i in chatbotsGroups[side]) {
                chatbot = chatbotsGroups[side][i];
                if (chatbot.uuid === chatbotPreview?.uuid) {
                    // Check if the current chatbot already has the same _updateTimestamp
                    if (chatbot._updateTimestamp === chatbotPreview._updateTimestamp) {
                        return;
                    }

                    chatbot = {
                        ...chatbot,
                        ...chatbotPreview,
                        utility: {
                            ...chatbot.utility,
                            ...chatbotPreview.utility,
                        },
                    };
                    if (chatbot.utility.show_in_side === side) {
                        setChatbotsGroups(prevState => ({
                            ...prevState,
                            [side]: [
                                ...prevState[side].slice(0, i),
                                {...chatbot},
                                ...prevState[side].slice(i + 1),
                            ],
                        }));
                    } else {
                        moveToOtherSide = true;
                        setChatbotsGroups(prevState => ({
                            ...prevState,
                            [side]: [
                                ...prevState[side].slice(0, i),
                                ...prevState[side].slice(i + 1),
                            ],
                        }));
                    }
                    break;
                }
            }
        }
        if (moveToOtherSide) {
            setChatbotsGroups(prevState => ({
                ...prevState,
                [chatbotPreview.utility.show_in_side]: [...(prevState[chatbotPreview.utility.show_in_side] || []), chatbot],
            }))
        }
    }, [chatbotPreview, chatbotsGroups]);

    /**
     * Add chatbot
     *
     * @param {object} chatbot Chatbot data
     * @param {object} chatbotShowSideGroups Chatbot show side groups
     * @param {object} scheduledChatbots Scheduled chatbots
     */
    const addChatbot = (chatbot, chatbotShowSideGroups, scheduledChatbots) => {
        // Chatbot group
        const showInSide = chatbot.utility.show_in_side || 'right';
        // Appear after
        const appearAfter = chatbot.utility?.appear_after ? parseInt(chatbot.utility?.appear_after) : 0;
        if (!isNaN(appearAfter) && appearAfter > 0) {
            // Schedule chatbot appearing
            if (!(appearAfter in scheduledChatbots)) {
                scheduledChatbots[appearAfter] = {};
            }
            if (!(showInSide in scheduledChatbots[appearAfter])) {
                scheduledChatbots[appearAfter][showInSide] = [];
            }
            scheduledChatbots[appearAfter][showInSide].push(chatbot);
        } else {
            // Show immediately
            if (showInSide in chatbotShowSideGroups) {
                chatbotShowSideGroups[showInSide].push(chatbot);
            } else {
                chatbotShowSideGroups[showInSide] = [chatbot];
            }
        }
    }

    /**
     * Fetches chatbot(s)
     *
     * @async
     * @function
     */
    const getChatbots = async () => {
        if (id) {
            GetChatbot(LimbChatbot.rest.url, LimbChatbot.rest.nonce, id, {
                include: ['utility'],
            }).then(res => {
                const showInSide = res.utility.show_in_side || 'right';
                setChatbotsGroups({[showInSide]: [res]});
            }).catch(e => {
                console.error(e);
            });
        } else {
            const chatbotShowSideGroups = {};
            const scheduledChatbots = {};
            // Published chatbots CPTs, including default one
            try {
                const reqParams = {
                    include: ['utility', 'default'],
                };
                if (attributes?.preview) {
                    reqParams.per_page = 1;
                } else {
                    reqParams.status = 1;
                }
                const res = await GetChatbots(LimbChatbot.rest.url, LimbChatbot.rest.nonce, reqParams);
                // Add published chatbots
                if (res?.total > 0) {
                    // Group chats by their positions
                    for (const chatbot of res.items) {
                        if (!chatbot.uuid && reqParams.status) {
                            console.error("Chatbot doesn't have a UUID.", chatbot);
                            continue;
                        }
                        if (attributes?.preview && chatbot.uuid !== attributes?.uuid) {
                            continue;
                        }
                        addChatbot(chatbot, chatbotShowSideGroups, scheduledChatbots);
                    }
                }
                // Add default chatbot
                if (res?._default?.utility) {
                    const chatbot = res._default;
                    // Set custom UUID for identification logic
                    chatbot.uuid = 'default';
                    if (!attributes?.preview || chatbot.uuid === attributes?.uuid) {
                        addChatbot(chatbot, chatbotShowSideGroups, scheduledChatbots);
                    }
                }
                // Check the captured state
                setCapturedState(res?._captured_state || null)
            } catch (e) {
                console.error(e);
            }
            // Update chatbots state
            setChatbotsGroups(chatbotShowSideGroups);
            // Schedule chatbots appearing
            const appearAfterTimes = Object.keys(scheduledChatbots);
            if (appearAfterTimes.length) {
                for (const appearAfterTime of appearAfterTimes) {
                    setTimeout(() => {
                        setChatbotsGroups(prevState => ({
                            ...prevState,
                            'left': [...(prevState.left || []), ...('left' in scheduledChatbots[appearAfterTime] ? scheduledChatbots[appearAfterTime].left : [])],
                            'right': [...(prevState.right || []), ...('right' in scheduledChatbots[appearAfterTime] ? scheduledChatbots[appearAfterTime].right : [])],
                        }));
                    }, appearAfterTime * 1000);
                }
            }
        }
    }

    /**
     * Chatbots toggled
     *
     * @param {string[]} chatbots Opened chatbots UUIDs
     * @param {string} showInSize Show side
     */
    const chatbotsToggled = (chatbots, showInSize) => {
        openedChatbots.current[showInSize] = [...chatbots];
        const hasOpenedChatbot = Object.values(openedChatbots.current).some(item => item?.length);
        setMobileLockState(hasOpenedChatbot);
    }

    return <Suspense>
        {!!Object.keys(chatbotsGroups).length &&
            Object.keys(chatbotsGroups).map(showInSide =>
                <Chatbots
                    key={showInSide}
                    showInSide={showInSide}
                    chatbots={chatbotsGroups[showInSide]}
                    chatbotsToggled={chatbotsToggled}
                    autoOpen={autoOpen}
                    onChatCloseStart={handleChatCloseStart}
                    capturedState={capturedState}
                    isPreviewMode={chatbotsGroups[showInSide]?.some(c => c.uuid === chatbotPreview?.uuid)}
                />)}
    </Suspense>
}