import {forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState} from "@wordpress/element";
import {__} from "@wordpress/i18n";
import {
    discardChanges,
    getInitialData,
    getUtilityKeyPrefix,
    setSettingsDataToUpdateFromMultiple,
    setupSetting
} from "../../../../../../../helpers";
import {handleError} from "../../../../../../../helpers/notifications";
import {UTILITIES_HEADER_KEYS} from "../../open-ai/utilities/_data";
import {GetSettings} from "../../../../../../../rest/settings";
import Checkbox from "../../../../../../fields/checkbox";
import TableAccordionContentLoading from "../../../../containers/table-accordion-content-loading";

const Utility = forwardRef(({title, slug, active, toggle, aiProviderId, settings, settingsDefault, dataFetched, isDataReady, setLoading, setHasUnsavedChanges, notifications, children}, ref) => {
    const keyPrefix = getUtilityKeyPrefix(aiProviderId, slug);
    // Actions states
    const [fetchingData, setFetchingData] = useState(true);
    // Initial data
    const initialData = useRef(getInitialData(settings));
    const initialDataDefault = useRef(getInitialData(settingsDefault));

    useImperativeHandle(ref, () => ({
        saved: () => {
            // Make the state as initial
            initialData.current = getInitialData(settings);
            initialDataDefault.current = getInitialData(settingsDefault);
            // Reset session storage
            sessionStorage.removeItem(keyPrefix.localStorage.aiGrouped);
            sessionStorage.removeItem(keyPrefix.localStorage.default);
        },
        discard: () => {
            discardChanges(settings, initialData.current);
            discardChanges(settingsDefault, initialDataDefault.current);
        }
    }));

    // Create serialized versions of settings for stable comparison
    const settingsValues = useMemo(() => {
        return JSON.stringify(getInitialData(settings));
    }, [Object.keys(settings).map(key => settings[key][0]).join('|')]);

    const settingsDefaultValues = useMemo(() => {
        return JSON.stringify(getInitialData(settingsDefault));
    }, [Object.keys(settingsDefault).map(key => settingsDefault[key][0]).join('|')]);

    useEffect(() => {
        setFetchingData(true);
        if (active === slug) {
            fetchData();
        }
    }, [active, slug]);

    useEffect(() => {
        if (isDataReady) {
            // Local storage
            sessionStorage.setItem(keyPrefix.localStorage.aiGrouped, settingsValues);
            sessionStorage.setItem(keyPrefix.localStorage.default, settingsDefaultValues);
            // Set settings data
            const dataToSave = setSettingsDataToUpdateFromMultiple(
                [settings, settingsDefault],
                [initialData.current, initialDataDefault.current],
                [`${keyPrefix.aiGrouped}.`, `${keyPrefix.default}.`],
            );
            // If it has changes
            setHasUnsavedChanges(dataToSave?.length > 0);
        }
    }, [isDataReady, settingsValues, settingsDefaultValues]);

    /**
     * Get saved settings
     */
    const fetchData = async () => {
        setLoading(prev => prev + 1);
        try {
            const res = await GetSettings(LimbChatbot.rest.url, LimbChatbot.rest.nonce, {
                key: [...Object.keys(settings).map(key => `${keyPrefix.aiGrouped}.${key}`), ...Object.keys(settingsDefault).map(key => `${keyPrefix.default}.${key}`)],
            });
            if (res?.length) {
                for (const setting of res) {
                    const result = setupSetting(keyPrefix.aiGrouped, setting, settings, initialData);
                    if (result !== -1) {
                        continue;
                    }
                    // Defaults
                    setupSetting(keyPrefix.default, setting, settingsDefault, initialDataDefault);
                }
            }
        } catch (e) {
            handleError(e, notifications.set, {
                title: __("Failed to retrieve data.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Please check your connection and try again.", 'limb-chatbot'),
            });
        }
        dataFetched();
        setFetchingData(false);
        setLoading(prev => prev - 1);
    }

    return <>
        <tr className={`lbaic-settings-table-accordion-body-in lbaic-settings-table-accordion-summary lbaic-settings-e-oaiu-table-summary${active === slug ? ' active' : ''}`}
            onClick={() => toggle(slug)}>
            <td className='lbaic-settings-table-accordion-body-item'>
                <div className='lbaic-settings-e-oaiu-table-item'>
                    <span className='lbaic-settings-table-accordion-body-label'>{title}</span>
                </div>
            </td>
            <td className='lbaic-settings-table-accordion-body-item lbaic-settings-table-accordion-body-arrow'>
                <svg className='lbaic-settings-table-accordion-body-arrow-i' xmlns='http://www.w3.org/2000/svg' fill='none'
                     viewBox='0 0 24 24'>
                    <use href='#lbaic-settings-arrow'/>
                </svg>
            </td>
        </tr>
        <tr className={`lbaic-settings-table-accordion-body-in lbaic-settings-table-accordion-details${active === slug ? ' opened' : ''}`}>
            <td className='lbaic-settings-table-accordion-body-item lbaic-settings-table-accordion-details-in'
                colSpan={UTILITIES_HEADER_KEYS.length}>
                <div className='lbaic-settings-table-accordion-content lbaic-settings-e-oaiu-table-content'>
                    {(fetchingData || !isDataReady) && <TableAccordionContentLoading/>}
                    {children}
                    <div className="lbaic-settings-column">
                        <div className="lbaic-settings-column-in">
                            <Checkbox label={__("Make default", 'limb-chatbot')}
                                      isChecked={settingsDefault['ai_provider_id'][0] === aiProviderId}
                                      toggleValue={() => settingsDefault['ai_provider_id'][1](settingsDefault['ai_provider_id'][0] === aiProviderId ? initialDataDefault.current.ai_provider_id : aiProviderId)}
                                      desc={__("Check this to make the AI provider the default provider for this utility.", 'limb-chatbot')}/>
                        </div>
                    </div>
                </div>
            </td>
        </tr>
    </>
});

export default Utility;