import {useEffect, useRef, useState} from "@wordpress/element";
import {UTILITIES_HEADER_KEYS} from "../../../../../../_data/chatbot/costs-limits";
import {
    getValidatedCostsLimits,
    getSettingsLocalKey,
    getUtilityLinkTo,
    validateCostTokenLimits,
    convertChatbotLimits
} from "../../../../../../../helpers";
import UserUtility from "./utilities/user";
import GuestUtility from "./utilities/guest";
import SingleMessageInputUtility from "./utilities/single-message-input";
import SingleMessageOutputUtility from "./utilities/single-message-output";
import Container from "../../../../containers/content/container";
import TabSettings from "../../../../../components/tab-settings";

// Constants
const TAB_NAME = 'settings.chatbot.costs-limits';
const SETTINGS_KEYS_PREFIX = 'lbaic.utilities.chatbot';

const removeUnusedLimits = (data, tab) => {
    if (tab === TAB_NAME) {
        if (data?.length) {
            const i = data.findIndex((item) => getSettingsLocalKey(item.key, SETTINGS_KEYS_PREFIX) === 'limits');
            if (i !== -1) {
                return getValidatedCostsLimits(data, i);
            }
        }
    }
    return data;
}

// Filter data to remove limits which has no limit
LimbChatbot.Hooks.addFilter('lbaic.admin.page.settings.dataToUpdate', 'lbaic/admin/page/settings/data-to-update', removeUnusedLimits);
LimbChatbot.Hooks.addFilter('lbaic.admin.page.settings.preview.dataToUpdate', 'lbaic/admin/page/settings/preview/data-to-update', removeUnusedLimits);

const prepareLimitsData = (settings) => {
    if (settings && 'limits' in settings && settings['limits'][0]) {
        const newData = JSON.parse(JSON.stringify(settings));
        newData['limits'][0] = validateCostTokenLimits(newData['limits'][0]);

        return newData;
    }
    return settings;
}

LimbChatbot.Hooks.addFilter('lbaic.admin.page.settings.prepareDataToUpdate', 'lbaic/admin/page/settings/prepare-data-to-update', prepareLimitsData);
LimbChatbot.Hooks.addFilter('lbaic.admin.page.settings.preview.prepareDataToUpdate', 'lbaic/admin/page/settings/preview/prepare-data-to-update', prepareLimitsData);
LimbChatbot.Hooks.addFilter('lbaic.admin.page.settings.saved', 'lbaic/admin/page/settings/saved', prepareLimitsData);

LimbChatbot.Hooks.addFilter('lbaic.admin.settings.formatValue', 'lbaic/admin/settings/format-value', (value, key) => {
    if (key === 'limits') {
        const keys = typeof value === 'object' && Object.keys(value);
        if (keys?.length) {
            return convertChatbotLimits(value);
        }
    }

    return value;
});

export default function CostsLimits({notifications}) {
    // Actions states
    const [loading, setLoading] = useState(0);
    const [isDataFetched, setIsDataFetched] = useState(false);
    const [showContent, setShowContent] = useState(false);
    // Utilities
    const [activeUtilityKey, setActiveUtilityKey] = useState('');
    const [utilities, setUtilities] = useState(LimbChatbot.Hooks.applyFilters('lbaic.admin.page.settings.general.chatbot.costs-limits.utilities', {
        'user': UserUtility,
        'guest': GuestUtility,
        'input': SingleMessageInputUtility,
        'output': SingleMessageOutputUtility,
    }));
    // Utilities refs
    const utilitiesRefs = useRef([]);
    // Settings
    const settings = {
        'limits': useState({}),
    };

    useEffect(() => {
        if (!showContent) {
            if (!loading || isDataFetched) {
                setTimeout(() => setShowContent(true), 400);
            }
        }
    }, [loading, isDataFetched]);

    useEffect(() => {
        const searchParams = new URLSearchParams(window.location.search);
        const utilityKey = searchParams.get('utility');
        if (utilityKey && utilityKey in utilities) {
            setActiveUtilityKey(utilityKey);
        }
    }, []);

    /**
     * Toggle accordion
     *
     * @param {string} key Utility key
     */
    const toggleAccordion = (key) => {
        const utilityKey = activeUtilityKey === key ? '' : key;

        if (utilityKey) {
            const searchParams = new URLSearchParams(window.location.search);
            if (searchParams.get('utility') !== utilityKey) {
                history.pushState({}, '', getUtilityLinkTo(searchParams.get('menu'), searchParams.get('tab'), utilityKey));
            }
        }

        setActiveUtilityKey(utilityKey);
    }

    /**
     * Render utility accordion
     *
     * @param {string} key Utility key
     * @return {JSX.Element}
     */
    const renderUtility = (key) => {
        const UtilityComponent = utilities[key];
        return <UtilityComponent key={key} ref={(el) => (utilitiesRefs.current[key] = el)} slug={key}
                                 active={activeUtilityKey} toggle={toggleAccordion}
                                 limits={settings['limits'][0]} setLimits={settings['limits'][1]}
                                 isDataFetched={isDataFetched} notifications={notifications}/>
    }

    return <>
        <TabSettings name={TAB_NAME}
                     settings={settings}
                     keysPrefix={SETTINGS_KEYS_PREFIX}
                     tabLoading={loading}
                     contentLoading={!showContent}
                     shouldUpdatePreviewData
                     dataFetched={value => setIsDataFetched(value)}
                     notifications={notifications}>
            <Container className="lbaic-settings-cb-cl">
                <div className='lbaic-settings-cb-cl'>
                    <div
                        className={`lbaic-settings-table-accordion-wrapper lbaic-settings-scroll-style lbaic-settings-scroll-x${activeUtilityKey && ' lbaic-settings-cb-cl-table-overflow'}`}>
                        <table className='lbaic-settings-table-accordion lbaic-settings-cb-cl-table'>
                            <thead className='lbaic-settings-table-accordion-header'>
                            <tr className='lbaic-settings-table-accordion-header-in'>
                                {UTILITIES_HEADER_KEYS.map((column, i) =>
                                    <th key={i} className='lbaic-settings-table-accordion-header-item'>
                                        <span className='lbaic-settings-table-accordion-header-label costs'>{column}</span>
                                    </th>
                                )}
                            </tr>
                            </thead>
                            <tbody className='lbaic-settings-table-accordion-body'>
                            {Object.keys(utilities).map(renderUtility)}
                            </tbody>
                        </table>
                    </div>
                </div>
            </Container>
        </TabSettings>
    </>
}