import {useEffect, useMemo, useRef, useState} from "@wordpress/element";
import {isRTL} from "@wordpress/i18n";
import Trigger from './containers/trigger';
import Groups from './containers/groups';
import ChatbotIconWidgets from './components/trigger/chatbot-icon-widgets';
import {PARAMETERS, UNITS} from './includes/constants';
import {hexToRgb, isNumber} from './includes/helpers';
import {ChatBotsContext} from "../contexts/chatbots";

export default function Chatbots({
                                     showInSide,
                                     chatbots,
                                     chatbotsToggled,
                                     autoOpen,
                                     onChatCloseStart,
                                     capturedState,
                                     isPreviewMode
                                 }) {
    const localStorageKey = useRef(`lbaic.chatbots.opened.${showInSide}`);
    const leadCaptureActionRef = useRef({blockOpen: false, isVisible: false, shake: () => {}, showAgain: () => {}});
    const [leadCaptureBlocking, setLeadCaptureBlocking] = useState(false);

    const [openedChatbotsUUIDs, setOpenedChatbotsUUIDs] = useState([]);
    const [activeChatbotIndex, setActiveChatbotIndex] = useState(0);
    const [moveTriggerUp, setMoveTriggerUp] = useState(0);
    const [moveTriggerDown, setMoveTriggerDown] = useState(0);

    useEffect(() => {
        if (document.querySelector('#chatbot-meta-box #lbaic-single-chatbot')) {
            // In the chatbot CPT
            setMoveTriggerUp(10);
        } else if (document.querySelector('#lbaic-admin-page-settings')) {
            // In the settings
            setMoveTriggerDown(8);
        }
    }, []);

    useEffect(() => {
        // Get chatbots opened last state
        let openedChatbotsState = JSON.parse(localStorage.getItem(localStorageKey.current) || '[]');
        // Auto open
        if (autoOpen && openedChatbotsState.indexOf(autoOpen) === -1) {
            openedChatbotsState.push(autoOpen);
        }
        // Fix chatbots' UUIDs
        openedChatbotsState = Array.isArray(openedChatbotsState) ? openedChatbotsState.filter(item => chatbots.findIndex(item2 => item2.uuid === item) !== -1) : [];
        // Update storage with corrected state
        localStorage.setItem(localStorageKey.current, JSON.stringify(openedChatbotsState));
        chatbotsToggled(openedChatbotsState, showInSide);
        // Update states
        setOpenedChatbotsUUIDs(openedChatbotsState);
        // Get and set active chatbot index
        if (openedChatbotsState.length) {
            updateActiveChatbotIndex(openedChatbotsState[openedChatbotsState.length - 1]);
        } else {
            updateActiveChatbotIndex();
        }
    }, [chatbots]);

    /**
     * Update active chatbot index state
     *
     * @param {string|false|any} chatbotUUID Chatbot UUID
     */
    const updateActiveChatbotIndex = (chatbotUUID = false) => {
        if (chatbotUUID) {
            const i = chatbots.findIndex(chatbot => chatbot.uuid === chatbotUUID);
            setActiveChatbotIndex(i !== -1 ? i : 0);
        } else {
            setActiveChatbotIndex(0);
        }
    }

    /**
     * Handle chatbot toggle
     *
     * @param {string[]} uuids
     */
    const toggleChatbots = (uuids) => {
        if (!uuids?.length) {
            return;
        }
        const openNow = uuids.every(item => openedChatbotsUUIDs.indexOf(item) === -1);
        // Update nested chatbots opened state
        const newOpenedState = openNow ? (showInSide === 'right' ? [...openedChatbotsUUIDs, ...uuids] : [...uuids, ...openedChatbotsUUIDs]) : openedChatbotsUUIDs.filter(item => uuids.every(item2 => item !== item2));
        setOpenedChatbotsUUIDs(prevState => [...newOpenedState]);
        // Keep it in local storage
        localStorage.setItem(localStorageKey.current, JSON.stringify(newOpenedState));
        chatbotsToggled(newOpenedState, showInSide);
        // Active chatbot(s) state
        updateActiveChatbotIndex(newOpenedState.length ? newOpenedState[newOpenedState.length - 1] : false);
    }

    // Trigger WordPress hook when chatbots are opened/closed to recalculate positions
    useEffect(() => {
        // Use requestAnimationFrame to ensure DOM has updated
        window.requestAnimationFrame(() => {
            setTimeout(() => {
                LimbChatbot.Hooks.doAction('lbaic.settings.chatbots.init');
            }, 400);
        });
    }, [openedChatbotsUUIDs]);

    const chatbotContextValue = useMemo(() => ({
        chatbots,
        showInSide,
        activeChatbotIndex,
        openedChatbotsUUIDs
    }), [chatbots, showInSide, activeChatbotIndex, openedChatbotsUUIDs]);

    /**
     * Open chatbot (respects lead capture required: block and shake or show form)
     *
     * @param {string} chatbotUuid Chatbot UUID. If not provided, will use active chatbot UUID.
     * @return {Promise<void>}
     */
    const openChatbot = (chatbotUuid) => {
        const currentChatbotUuid = chatbotUuid || chatbots[activeChatbotIndex].uuid;
        if (openedChatbotsUUIDs.indexOf(currentChatbotUuid) !== -1) return;
        const ref = leadCaptureActionRef.current;
        if (ref?.blockOpen) {
            if (ref.isVisible) {
                ref.shake();
            } else {
                ref.showAgain();
            }
            return;
        }
        toggleChatbots([currentChatbotUuid]);
    }

    /**
     * Toggle chatbots; when opening, intercept if lead capture is required and not completed
     */
    const handleToggleChatbots = (uuids) => {
        if (!uuids?.length) return;
        const isOpening = openedChatbotsUUIDs.indexOf(uuids[0]) === -1;
        if (isOpening && leadCaptureActionRef.current?.blockOpen) {
            if (leadCaptureActionRef.current.isVisible) {
                leadCaptureActionRef.current.shake();
            } else {
                leadCaptureActionRef.current.showAgain();
            }
            return;
        }
        toggleChatbots(uuids);
    }

    /**
     * Open chatbot and send message
     *
     * @param {any} result Result
     * @param {string} message Message
     * @param {string} chatbotUuid Chatbot UUID
     * @return {Promise<*>}
     */
    const openChatbotAndSendMessage = async (result, message, chatbotUuid = null) => {
        if (typeof message === 'string' && message.trim().length > 0) {
            openChatbot(chatbotUuid);
        }

        return result;
    }

    useEffect(() => {
        // Trigger WordPress hook to notify settings component to recalculate positions
        // Use requestAnimationFrame to ensure DOM has updated with new size
        window.requestAnimationFrame(() => {
            LimbChatbot.Hooks.doAction('lbaic.settings.chatbots.init');
        });

        LimbChatbot.Hooks.addFilter('lbaic.chatbot.sendMessage', 'lbaic/chatbot/open/send-message', openChatbotAndSendMessage);
        LimbChatbot.Hooks.addAction('lbaic.chatbot.open', 'lbaic/chatbots/open', openChatbot);

        return () => {
            LimbChatbot.Hooks.removeFilter('lbaic.chatbot.sendMessage', 'lbaic/chatbot/open/send-message');
            LimbChatbot.Hooks.removeAction('lbaic.chatbot.open', 'lbaic/chatbots/open');
        }
    }, []);

    return (!!chatbots.length &&
        <div id="lbaic" className={`lbaic lbaic-${showInSide} lbaic-${isRTL() ? 'rtl' : 'ltr'}`}
             style={{
                 '--lbaic-t': isNumber(PARAMETERS.position[showInSide].top) ? `${PARAMETERS.position[showInSide].top}px` : 'unset',
                 '--lbaic-r': isNumber(PARAMETERS.position[showInSide].right) ? `${PARAMETERS.position[showInSide].right - moveTriggerDown}px` : 'unset',
                 '--lbaic-b': isNumber(PARAMETERS.position[showInSide].bottom) ? `${PARAMETERS.position[showInSide].bottom + moveTriggerUp - moveTriggerDown}px` : 'unset',
                 '--lbaic-l': isNumber(PARAMETERS.position[showInSide].left) ? `${PARAMETERS.position[showInSide].left}px` : 'unset',
                 '--lbaic-trigger-size': `${PARAMETERS.trigger.size}px`,
                 '--lbaic-trigger-gap': `${PARAMETERS.trigger.gap}px`,
                 '--lbaic-main-color': `${chatbots[activeChatbotIndex]?.utility.color || PARAMETERS.trigger.color}`,
                 '--lbaic-main-color-rgb': `${chatbots[activeChatbotIndex]?.utility.color || PARAMETERS.trigger.color}`,
                 '--lbaic-trigger-color': `${chatbots[activeChatbotIndex]?.utility.color || PARAMETERS.trigger.color}`,
                 '--lbaic-trigger-color-rgb': `${hexToRgb(chatbots[activeChatbotIndex]?.utility.color) || PARAMETERS.trigger.colorRGB}`,
                 '--lbaic-reverse-multiplier': UNITS.reverseMultiplier,
             }}>
            {!openedChatbotsUUIDs.length && (
                <ChatBotsContext.Provider value={chatbotContextValue}>
                    <ChatbotIconWidgets
                        leadCaptureActionRef={leadCaptureActionRef}
                        capturedState={capturedState}
                        isInPreviewMode={isPreviewMode}
                        onLeadCaptureBlockChange={setLeadCaptureBlocking}
                    />
                    <Trigger toggleChatbots={handleToggleChatbots} leadCaptureBlocking={leadCaptureBlocking}/>
                </ChatBotsContext.Provider>
            )}
            <Groups
                chatbots={chatbots}
                showInSide={showInSide}
                openedChatbotsUUIDs={openedChatbotsUUIDs}
                closeChatbots={toggleChatbots}
                onChatCloseStart={onChatCloseStart}
                capturedState={capturedState}
            />
        </div>
    )
}
