import {useEffect, useRef, useState} from "@wordpress/element";
import {__} from "@wordpress/i18n";
import {useNavigate} from "react-router-dom";
import ContentFooter from "../../../../containers/content/footer";
import {UTILITIES_HEADER_KEYS} from "./_data";
import {
    ALL_SETTINGS_DATA_KEY,
    getAllSettingsChanges,
    getUtilityLinkTo,
    isAllSettingsHasError
} from "../../../../../../../helpers";
import EmbeddingUtility from "./embedding";
import Copilot from "./copilot";
import ContentBodyInner from "../../../../containers/content/body-inner";
import Container from "../../../../containers/content/container";
import Notice from "../../../../../../sections/notice";
import useUnsavedChangesWarning from "../../../../../components/unsaved-changes-warning";
import confirm from "../../../../../../../helpers/confirm";
import {handleError, handleSuccess, handleWarning} from "../../../../../../../helpers/notifications";
import {UpdateSettings} from "../../../../../../../rest/settings";

export default function Utilities({notifications}) {
    // Navigation
    const navigate = useNavigate();
    // Actions states
    const [loading, setLoading] = useState(0);
    const [saving, setSaving] = useState(false);
    const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
    const [utilitiesHasUnsavedChanges, setUtilitiesHasUnsavedChanges] = useState({});
    // Active utility key
    const [activeUtilityKey, setActiveUtilityKey] = useState('');
    const [utilities, setUtilities] = useState(LimbChatbot.Hooks.applyFilters('lbaic.admin.page.settings.ai-provider.utilities', {
        'embedding': EmbeddingUtility,
        'copilot': Copilot,
    }, 'gemini'));
    // Utilities refs
    const utilitiesRefs = useRef([]);

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

    // Check unsaved changes before leaving the page
    useUnsavedChangesWarning(hasUnsavedChanges || Object.values(utilitiesHasUnsavedChanges).some(Boolean));

    /**
     * Check has unsaved changes
     */
    const checkHasUnsavedChanges = () => {
        const dataToUpdate = getAllSettingsChanges();
        setHasUnsavedChanges(dataToUpdate.length > 0);
    }

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

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

        return 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}
                loading={loading}
                setLoading={setLoading}
                hasUnsavedChanges={utilitiesHasUnsavedChanges[key]}
                setHasUnsavedChanges={hasChanges => setUtilitiesHasUnsavedChanges(prevState => ({
                    ...prevState,
                    [key]: hasChanges
                }))}
                notifications={notifications}
            />
        );
    }

    /**
     * Save settings
     */
    const save = async () => {
        // Check all settings error
        if (isAllSettingsHasError(notifications.set)) {
            return;
        }
        setSaving(true);
        // Get data to update
        const data = LimbChatbot.Hooks.applyFilters('lbaic.admin.page.settings.utility.dataToUpdate', getAllSettingsChanges(), 'gemini');
        if (data.length) {
            try {
                await UpdateSettings(LimbChatbot.rest.url, LimbChatbot.rest.nonce, data);
                sessionStorage.removeItem(ALL_SETTINGS_DATA_KEY);
                handleSuccess(notifications.set, {
                    title: __("Data saved successfully.", 'limb-chatbot'),
                });
                // Data saved, run saved callbacks
                for (const key of Object.keys(utilitiesRefs.current)) {
                    if (utilitiesHasUnsavedChanges[key]) {
                        if (utilitiesRefs.current[key] && typeof utilitiesRefs.current[key].saved === 'function') {
                            utilitiesRefs.current[key].saved();
                        }
                    }
                }
                checkHasUnsavedChanges();
            } catch (e) {
                handleError(e, notifications.set, {
                    title: __("Failed to save changes.", 'limb-chatbot'),
                    description: e.message ? __(e.message, 'limb-chatbot') : __("Please try again.", 'limb-chatbot'),
                });
            }
        } else if (!utilitiesHasUnsavedChanges['assistant']) {
            handleWarning(false, notifications.set, {
                title: __("Attention", 'limb-chatbot'),
                description: __("There is no changes to save.", 'limb-chatbot'),
            });
        }
        setSaving(false);
    }

    /**
     * Discard changes
     */
    const discard = async () => {
        if (await confirm(__("Are you sure you want to discard all changes?", 'limb-chatbot'))) {
            for (const key of Object.keys(utilitiesRefs.current)) {
                if (utilitiesRefs.current[key] && typeof utilitiesRefs.current[key].discard === 'function') {
                    utilitiesRefs.current[key].discard();
                }
            }
            checkHasUnsavedChanges();
        }
    }

    return (
        <>
            <ContentBodyInner>
                <Container className="lbaic-settings-e-oaiu">
                    <div className='lbaic-settings-e-oaiu'>
                        <div
                            className={`lbaic-settings-table-accordion-wrapper lbaic-settings-scroll-style lbaic-settings-scroll-x${activeUtilityKey && ' lbaic-settings-e-oaiu-table-overflow'}`}>
                            <table className='lbaic-settings-table-accordion lbaic-settings-e-oaiu-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'>{column}</span>
                                        </th>
                                    )}
                                </tr>
                                </thead>
                                <tbody className='lbaic-settings-table-accordion-body'>
                                {Object.keys(utilities).map(renderUtility)}
                                </tbody>
                            </table>
                        </div>
                    </div>
                </Container>
            </ContentBodyInner>
            <ContentFooter
                save={save}
                discard={discard}
                loading={loading}
                saving={saving}
                hasUnsavedChanges={hasUnsavedChanges || Object.values(utilitiesHasUnsavedChanges).some(Boolean)}
            />
        </>
    )
}