import {forwardRef, useImperativeHandle, useEffect, useRef, useState} from "@wordpress/element";
import {__, sprintf} from "@wordpress/i18n";
import {UTILITIES_HEADER_KEYS} from "../_data";
import Tooltip from "../../../../../../../fields/tooltip";
import BlockEditable from "../../../../../../../fields/blockeditable";
import Input from "../../../../../../../fields/input";
import Dropdown from "../../../../../../../fields/dropdown";
import Toggle from "../../../../../../../fields/toggle-button";
import {
    getDataFromState,
    getInitialData,
    getSettingsDataToUpdate
} from "../../../../../../../../helpers";
import {getFormatedTimestamp} from "../../../../../../../../../helpers";
import OpenAI from "../../../../../../../../../utilities/ai-providers/open-ai";
import {GetModels} from "../../../../../../../../rest/models";
import {handleError, handleSuccess, handleWarning} from "../../../../../../../../helpers/notifications";
import AddNewFile from "../../../../../../../popups/ai-providers/add-new-file";
import {GetConfigs} from "../../../../../../../../rest/configs";
import AddFunction from "../../../../../../../popups/ai-providers/add-function";
import ExpandableContainer from "../../../../../../../fields/expandable-container";
import TableAccordionContentLoading from "../../../../../containers/table-accordion-content-loading";
import confirm from "../../../../../../../../helpers/confirm";
import LoadingBar from "../../../../../../../fields/loading-bar";

export default function AssistantUtility({slug, active, toggle, notifications}) {
    // Actions states
    const [loading, setLoading] = useState(0);
    const [saving, setSaving] = useState(false);
    const [isDataFetched, setIsDataFetched] = useState(false);
    const [isConfigsFetched, setIsConfigsFetched] = useState(false);
    const [isAssistantsFetched, setIsAssistantsFetched] = useState(false);
    const [isModelsFetched, setIsModelsFetched] = useState(false);
    const [showAddNewFilePopup, setShowAddNewFilePopup] = useState(false);
    const [showAddFunctionPopup, setShowAddFunctionPopup] = useState(false);
    // Select options
    const [configs, setConfigs] = useState([]);
    const [configsPagination, setConfigsPagination] = useState({
        page: 1,
        perPage: 10,
        total: 0,
    });
    const [assistants, setAssistants] = useState({options: []});
    const [models, setModels] = useState([]);
    const [modelsPagination, setModelsPagination] = useState({
        page: 1,
        perPage: 10,
        total: 0,
    });
    const [responseFormats, setResponseFormats] = useState([
        {
            label: __("Auto", 'limb-chatbot'),
            value: 'auto',
            disabled: true,
        },
        {
            label: __("Text", 'limb-chatbot'),
            value: 'text',
            extra: {'type': 'text'},
            disabled: true,
        },
        {
            label: __("JSON object", 'limb-chatbot'),
            value: 'json_object',
            extra: {'type': 'json_object'},
        },
        // {
        //     label: __("JSON schema", 'limb-chatbot'),
        //     value: 'json_schema',
        //     extra: {'type': 'json_schema', 'json_schema': {/*TODO: should be added a textarea to provide own schema*/}},
        // },
    ]);
    //
    const aiProvider = useRef(null);
    const [config, setConfig] = useState(null);
    const [assistant, setAssistant] = useState({});
    const [showCreateAssistant, setShowCreateAssistant] = useState(false);
    const [fsFiles, setFsFiles] = useState({});
    const [ciFiles, setCiFiles] = useState([]);
    // Settings
    const settings = {
        'id': useState(null),
        'name': useState(''),
        'instructions': useState(''),
        'tools': useState([]),
        'response_format': useState({type: 'json_object'}),
        'model': useState(''),
    };
    // Initial data
    const initialData = useRef(getInitialData(settings));
    // Previous state
    const prevSelectedId = useRef(null);
    const prevSavedData = useRef(null);
    //
    const saveDebounce = useRef(null);

    useEffect(() => {
        if (active === slug) {
            getConfigs({
                page: 1,
                perPage: configsPagination.perPage
            }, true);
            getModels({
                page: 1,
                perPage: modelsPagination.perPage
            }, true);
        }
    }, [active, slug]);

    useEffect(() => {
        if (isDataFetched) {
            // Reset initial data on new assistant select
            if (prevSelectedId.current !== settings['id'][0]) {
                prevSelectedId.current = settings['id'][0];
                initialData.current = getInitialData(settings);
            }
            // Check for changes
            const dataToSave = getSettingsDataToUpdate(settings, initialData.current);
            if (dataToSave?.length > 0) {
                if (JSON.stringify(dataToSave) !== JSON.stringify(prevSavedData.current)) {
                    prevSavedData.current = dataToSave;
                    clearTimeout(saveDebounce.current);
                    saveDebounce.current = setTimeout(() => {
                        save();
                    }, 500);
                }
            }
        }
    }, [isDataFetched, settings]);

    useEffect(() => {
        setIsDataFetched(isConfigsFetched && isAssistantsFetched && isModelsFetched);
    }, [isConfigsFetched, isAssistantsFetched, isModelsFetched]);

    /**
     * Get open-ai configs
     */
    const getConfigs = async (params, reset = false) => {
        setLoading(prev => prev + 1);
        // Default params
        const reqParams = {
            related_to: 'open-ai',
            page: params?.page || 1,
            per_page: params?.perPage || 10,
            mask: false
        };
        // Add search param
        if (params?.search) {
            reqParams.search = params.search;
            reqParams.search_fields = ['title'];
        }
        try {
            const res = await GetConfigs(LimbChatbot.rest.url, LimbChatbot.rest.nonce, reqParams);
            const newConfigs = [...(reset ? [] : configs), ...(res.items?.length ? res.items : [])];
            // Update state
            setConfigs([...newConfigs]);
            // Set default value
            const defaultConfig = newConfigs.find(item => item.default);
            if (defaultConfig) {
                configSelected(defaultConfig);
            }
            // Pagination info
            setConfigsPagination(prevState => ({
                ...prevState,
                page: reqParams.page,
                total: res.total,
            }));
        } catch (e) {
            handleError(e, notifications.set, {
                title: __("Failed to retrieve API keys data.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Please check your connection and try again.", 'limb-chatbot'),
            });
        }
        setTimeout(() => {
            setIsConfigsFetched(true);
            setLoading(prev => prev - 1);
        }, 200);
    }

    /**
     * Config selected
     *
     * @param {object} config OpenAI config
     */
    const configSelected = async (config) => {
        // Save state
        setConfig(config);
        if (config?.id) {
            // Get assistants
            const apiKey = config?.params?.api_key;
            if (apiKey) {
                // Set AI provider
                aiProvider.current = new OpenAI({
                    apiKey: apiKey,
                });

                await fetchAssistants();
            } else {
                handleError({message: "API key is empty."}, notifications.set, {
                    title: __("API key is empty.", 'limb-chatbot'),
                    description: __("Please check the AI provider API keys.", 'limb-chatbot'),
                });
                // Reset
                setAssistants({options: []});
            }
            setTimeout(() => {
                setIsAssistantsFetched(true);
            }, 200);
        } else {
            // Reset
            setAssistants({options: []});
            setTimeout(() => {
                setIsAssistantsFetched(true);
            }, 200);
        }
    }

    /**
     * Get assistants
     */
    const fetchAssistants = async () => {
        setLoading(prev => prev + 1);
        try {
            const res = await aiProvider.current?.listAssistants();
            if (res?.status) {
                setAssistants({
                    ...res.data,
                    options: res.data.data.map(item => ({
                        label: item.name || (__("Untitled assistant", 'limb-chatbot') + ` (${item.id})`),
                        value: item.id,
                    })),
                });
                setShowCreateAssistant(true);
            } else {
                setAssistants({options: []});
                handleError({message: res.data}, notifications.set, {
                    title: __("Failed to retrieve assistants data.", 'limb-chatbot'),
                    description: res.data ? __(res.data, 'limb-chatbot') : __("Please check your connection and try again.", 'limb-chatbot'),
                });
            }
            setLoading(prev => prev - 1);
        } catch (e) {
            setAssistants({options: []});
            setLoading(prev => prev - 1);
            handleError(e, notifications.set, {
                title: __("Failed to retrieve assistants data.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Please check your connection and try again.", 'limb-chatbot'),
            });
        }
    }

    /**
     * Get selected AI models
     */
    const getModels = async (params, reset = false) => {
        setLoading(prev => prev + 1);
        // Default params
        const reqParams = {
            ai_provider_id: 'open-ai',
            page: params?.page || 1,
            per_page: params?.perPage || 10,
        };
        // Add search param
        if (params?.search) {
            reqParams.search = params.search;
            reqParams.search_fields = ['label'];
        }
        try {
            const res = await GetModels(LimbChatbot.rest.url, LimbChatbot.rest.nonce, reqParams);
            const newModels = [...(reset ? [] : models), ...(res.items?.length ? res.items : [])];
            // Update state
            setModels([...newModels]);
            // Pagination info
            setModelsPagination(prevState => ({
                ...prevState,
                page: reqParams.page,
                total: res.total,
            }));
        } catch (e) {
            handleError(e, notifications.set, {
                title: __("Failed to retrieve the AI models data.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Please check your connection and try again.", 'limb-chatbot'),
            });
        }
        setTimeout(() => {
            setIsModelsFetched(true);
            setLoading(prev => prev - 1);
        }, 200);
    }

    /**
     * Get file search files
     *
     * @param {object} assistant Assistant
     * @return {Promise<void>}
     */
    const getFsFiles = async (assistant) => {
        if (assistant?.tool_resources?.file_search?.vector_store_ids?.length) {
            const files = {};
            // Loop on vector stores and get files
            for (const vectorStoreId of assistant.tool_resources.file_search.vector_store_ids) {
                files[vectorStoreId] = [];
                // TODO add pagination
                const res = await aiProvider.current?.getVectorStoreFiles(vectorStoreId, {limit: 100});
                if (res.status) {
                    if (res.data.data?.length) {
                        // Get files full data
                        for (const file of res.data.data) {
                            const res = await aiProvider.current?.getFile(file.id);
                            if (res.status) {
                                files[vectorStoreId].push(res.data);
                            } else {
                                handleError({message: res.data}, notifications.set, {
                                    title: __("Failed to get file data.", 'limb-chatbot'),
                                    description: res.data || __("Please check your connection and try again.", 'limb-chatbot'),
                                });
                            }
                        }
                    }
                } else {
                    handleError({message: res.data}, notifications.set, {
                        title: __("Failed to get vector store files.", 'limb-chatbot'),
                        description: res.data || __("Please check your connection and try again.", 'limb-chatbot'),
                    });
                }
            }
            setFsFiles(prev => ({...files}));
        } else {
            setFsFiles({});
        }
    }

    /**
     * Get code interpreter files
     *
     * @param {object} assistant Assistant
     * @return {Promise<void>}
     */
    const getCiFiles = async (assistant) => {
        if (assistant?.tool_resources?.code_interpreter?.file_ids?.length) {
            const files = [];
            // Loop on vector stores and get files
            for (const fileId of assistant.tool_resources.code_interpreter.file_ids) {
                const res = await aiProvider.current?.getFile(fileId);
                if (res.status) {
                    files.push(res.data);
                } else {
                    handleError({message: res.data}, notifications.set, {
                        title: __("Failed to get file data.", 'limb-chatbot'),
                        description: res.data || __("Please check your connection and try again.", 'limb-chatbot'),
                    });
                }
            }
            setCiFiles(prev => [...files]);
        } else {
            setCiFiles([]);
        }
    }

    /**
     * Assistant changed
     *
     * @return {Promise<void>}
     */
    const handleAssistantSelectChange = async (assistantId) => {
        settings['id'][1](assistantId);
        // Check for selected assistant
        setLoading(prev => prev + 1);
        let selectedAssistant = null;
        if (!assistantId) {
            // Create assistant
            if (settings['model'][0] || (models.length && models[0].name)) {
                const res = await aiProvider.current?.createAssistant({model: settings['model'][0] || models[0].name});
                if (res.status) {
                    selectedAssistant = res.data;
                    // Add the new assistant
                    await fetchAssistants();
                } else {
                    handleError({message: res.data}, notifications.set, {
                        title: __("Failed to create assistant.", 'limb-chatbot'),
                        description: res.data || __("Please check your connection and try again.", 'limb-chatbot'),
                    });
                }
            } else {
                // There is no models to create assistant
                handleWarning({message: "Models aren't available."}, notifications.set, {
                    title: __("Models aren't available.", 'limb-chatbot'),
                    description: __("Please check your connection and try again.", 'limb-chatbot'),
                });
            }
        } else {
            // Find an assistant in the list
            selectedAssistant = assistants.data?.find(item => item.id === assistantId);
            if (!selectedAssistant?.id) {
                handleWarning({message: `The assistant doesn't exist. ID: ${assistantId}`}, notifications.set, {
                    title: __("The assistant doesn't exist.", 'limb-chatbot'),
                    description: sprintf(__("Assistant by %s ID doesn't exist.", 'limb-chatbot'), assistantId) + '<br/>' + __("Please select from existing ones or create a new one.", 'limb-chatbot'),
                });
            }
        }
        // Set assistant
        setAssistant(selectedAssistant?.id ? selectedAssistant : {});
        // Set settings data
        settings['id'][1](selectedAssistant?.id);
        settings['name'][1](selectedAssistant?.name || '');
        settings['instructions'][1](selectedAssistant?.instructions || '');
        settings['tools'][1](selectedAssistant?.tools || []);
        settings['response_format'][1](/*selectedAssistant?.response_format || */{type: 'json_object'});
        settings['model'][1](selectedAssistant?.model || '');
        // File search
        await getFsFiles(selectedAssistant);
        // Code interpreter
        await getCiFiles(selectedAssistant);
        setLoading(prev => prev - 1);
    }

    /**
     * Delete assistant
     *
     * @return {Promise<void>}
     */
    const deleteAssistant = async () => {
        if (await confirm(__("Are you sure you want to delete the assistant?", 'limb-chatbot'))) {
            setLoading(prev => prev + 1);
            const res = await aiProvider.current?.deleteAssistant(assistant?.id);
            if (res.status) {
                // Update assistants and selected assistant states
                // fetchAssistants();
                setAssistants(prevState => ({
                    ...prevState,
                    options: prevState.options.filter(item => item.value !== assistant.id),
                    data: prevState.data.filter(item => item.id !== assistant.id),
                    first_id: assistant.id === prevState.first_id ? prevState.data[1]?.id : prevState.first_id,
                    last_id: assistant.id === prevState.last_id ? prevState.data[prevState.data.length - 2]?.id : prevState.last_id,
                    total: prevState.total - 1,
                }));
                settings['id'][1](null);
                setAssistant({});
                handleSuccess(notifications.set, {
                    title: __("Assistant deleted.", 'limb-chatbot'),
                });
            } else {
                handleError({message: res.data}, notifications.set, {
                    title: __("Failed to delete assistant.", 'limb-chatbot'),
                    description: res.data || __("Please check your connection and try again.", 'limb-chatbot'),
                });
            }
            setLoading(prev => prev - 1);
        }
    }

    /**
     * Clone assistant
     */
    const cloneAssistant = async () => {
        if (await confirm(__("Are you sure you want to clone the assistant?", 'limb-chatbot'))) {
            setLoading(prev => prev + 1);
            const cloneAssistant = await aiProvider.current?.getAssistant(assistant.id);
            if (cloneAssistant.status) {
                const body = ['instructions', 'model', 'name', 'response_format', 'temperature', 'tool_resources', 'tools', 'top_p'].reduce((acc, key) => ({
                    ...acc,
                    [key]: cloneAssistant.data[key]
                }), {})
                // Add prefix to name
                if (body.name) {
                    body.name = `Copy of ${body.name}`;
                }
                const clonedAssistant = await aiProvider.current?.createAssistant(body);
                if (clonedAssistant.status) {
                    fetchAssistants();
                } else {
                    handleError({message: clonedAssistant.data}, notifications.set, {
                        title: __("Failed to clone assistant.", 'limb-chatbot'),
                        description: clonedAssistant.data || __("Please check your connection and try again.", 'limb-chatbot'),
                    });
                }
            } else {
                handleError({message: cloneAssistant.data}, notifications.set, {
                    title: __("Failed to get assistant data.", 'limb-chatbot'),
                    description: cloneAssistant.data || __("Please check your connection and try again.", 'limb-chatbot'),
                });
            }
            setLoading(prev => prev - 1);
        }
    }

    /**
     * File search: save files
     *
     * @param {object[]} files Files
     * @param {string|false} vectorStoreId Vector store ID
     * @return {Promise<boolean>}
     */
    const fsFileAdded = async (files, vectorStoreId) => {
        // Add files
        const createdFiles = [];
        for (const file of files) {
            const res = await aiProvider.current?.addFile(file, 'assistants');
            if (res.status) {
                createdFiles.push(res.data);
            } else {
                handleError({message: res.data}, notifications.set, {
                    title: __("File upload failed.", 'limb-chatbot'),
                    description: res.data || __("Please check your connection and try again.", 'limb-chatbot'),
                });
            }
        }
        // Add files to vector store
        if (createdFiles?.length) {
            if (vectorStoreId) {
                // Add files to existing vector store
                const res = await aiProvider.current?.addFilesToVectorStore(vectorStoreId, createdFiles.map(file => file.id));
                if (res.status) {
                    handleSuccess(notifications.set, {
                        title: __("Data saved successfully.", 'limb-chatbot'),
                    });
                    // Refresh files list
                    await getFsFiles(assistant);
                    return true;
                } else {
                    handleError({message: res.data}, notifications.set, {
                        title: __("Failed to add files to vector store.", 'limb-chatbot'),
                        description: res.data || __("Please check your connection and try again.", 'limb-chatbot'),
                    });
                }
            } else {
                // Create new vector store with files
                const res = await aiProvider.current?.createVectorStore({
                    file_ids: createdFiles.map(file => file.id),
                });
                if (res.status) {
                    // Add the new vector store to assistant
                    const body = {
                        tool_resources: {
                            ...(assistant.tool_resources || {}),
                            file_search: {
                                ...(assistant.file_search || {}),
                                vector_store_ids: [res.data.id],
                            }
                        },
                    };
                    const res = await aiProvider.current?.updateAssistant(assistant.id, body);
                    if (res.status) {
                        // Update assistant
                        setAssistant(res.data);
                        // Refresh files list
                        await getFsFiles(res.data);
                        handleSuccess(notifications.set, {
                            title: __("Data saved successfully.", 'limb-chatbot'),
                        });
                        return true;
                    } else {
                        handleError({message: res.data}, notifications.set, {
                            title: __("Failed to add files to assistant.", 'limb-chatbot'),
                            description: res.data || __("Please check your connection and try again.", 'limb-chatbot'),
                        });
                    }
                } else {
                    handleError({message: res.data}, notifications.set, {
                        title: __("Failed to create vector store.", 'limb-chatbot'),
                        description: res.data || __("Please check your connection and try again.", 'limb-chatbot'),
                    });
                }
            }
        }
        return !files.length;
    }

    /**
     * File search: delete file
     *
     * @param {string} fileId File ID
     * @param {string} vectorStoreId Vector store ID
     * @return {Promise<boolean>}
     */
    const deleteFSFile = async (fileId, vectorStoreId) => {
        if (await confirm(__("Are you sure you want to delete the file?", 'limb-chatbot'))) {
            const res = await aiProvider.current?.deleteFileFromVectorStore(vectorStoreId, fileId)
            if (res.status) {
                // Refresh files list
                await getFsFiles(assistant);
                handleSuccess(notifications.set, {
                    title: __("File deleted.", 'limb-chatbot'),
                });
                return true;
            } else {
                handleError({message: res.data}, notifications.set, {
                    title: __("Failed to delete file.", 'limb-chatbot'),
                    description: res.data || __("Please check your connection and try again.", 'limb-chatbot'),
                });
            }
        }
        return false;
    }

    /**
     * Code interpreter: save files
     *
     * @param {File[]} files Files
     * @return {Promise<boolean>}
     */
    const ciFileAdded = async (files) => {
        // Add files
        const createdFiles = [];
        for (const file of files) {
            const res = await aiProvider.current?.addFile(file, 'assistants');
            if (res.status) {
                createdFiles.push(res.data);
            } else {
                handleError({message: res.data}, notifications.set, {
                    title: __("File upload failed.", 'limb-chatbot'),
                    description: res.data || __("Please check your connection and try again.", 'limb-chatbot'),
                });
            }
        }
        if (createdFiles.length) {
            // Add files to code interpreter
            const fileIds = assistant?.tool_resources?.code_interpreter?.file_ids || [];
            const body = {
                tool_resources: {
                    ...(assistant?.tool_resources || {}),
                    code_interpreter: {
                        ...(assistant?.tool_resources?.code_interpreter || {}),
                        file_ids: [...createdFiles.map(file => file.id), ...fileIds],
                    }
                },
            };
            const res = await aiProvider.current?.updateAssistant(assistant.id, body);
            if (res.status) {
                // Update assistant
                setAssistant(res.data);
                // Refresh files list
                await getCiFiles(res.data);
                handleSuccess(notifications.set, {
                    title: __("Data saved successfully.", 'limb-chatbot'),
                });
                return true;
            } else {
                handleError({message: res.data}, notifications.set, {
                    title: __("Failed to add files to assistant.", 'limb-chatbot'),
                    description: res.data || __("Please check your connection and try again.", 'limb-chatbot'),
                });
            }
        }
        return !files.length;
    }

    /**
     * Code interpreter: delete file
     *
     * @param {string} fileId File ID
     * @return {Promise<boolean>}
     */
    const deleteCIFile = async (fileId) => {
        if (await confirm(__("Are you sure you want to delete the file?", 'limb-chatbot'))) {
            // Get files ids
            const filesIds = assistant?.tool_resources?.code_interpreter?.file_ids || [];
            const body = {
                tool_resources: {
                    ...(assistant.tool_resources || {}),
                    code_interpreter: {
                        ...(assistant.code_interpreter || {}),
                        // Delete the file from the list
                        file_ids: filesIds.filter(item => item !== fileId),
                    }
                },
            };
            const res = await aiProvider.current?.updateAssistant(assistant.id, body);
            if (res.status) {
                // Update assistant
                setAssistant(res.data);
                // Refresh files list
                await getCiFiles(res.data);
                handleSuccess(notifications.set, {
                    title: __("File deleted.", 'limb-chatbot'),
                });
                return true;
            } else {
                handleError({message: res.data}, notifications.set, {
                    title: __("Failed to delete file.", 'limb-chatbot'),
                    description: res.data || __("Please check your connection and try again.", 'limb-chatbot'),
                });
            }
        }
        return false;
    }

    /**
     * Render file
     *
     * @param {object} file File
     * @param {string} vectorStoreId File vector store ID
     * @param {string} type File type
     * @return {JSX.Element}
     */
    const renderFile = (file, vectorStoreId = false, type = false) => {
        const deleteFile = () => {
            if (type === 'file_search') {
                deleteFSFile(file.id, vectorStoreId);
            } else if (type === 'code_interpreter') {
                deleteCIFile(file.id);
            } else {
                console.error("Limb: Unknown type of file.");
            }
        }

        return <div key={file.id} className='lbaic-settings-e-oaiu-file'>
            <svg className='lbaic-settings-e-oaiu-file-i' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24'>
                <use href='#lbaic-settings-file'/>
            </svg>
            <span className='lbaic-settings-e-oaiu-file-label'>{file.filename}</span>
            <button className={`lbaic-settings-button-reset lbaic-settings-e-oaiu-file-remove${!assistant?.id ? ' lbaic-settings-button-disabled' : ''}`}
                    onClick={deleteFile}>
                <svg className='lbaic-settings-e-oaiu-file-remove-i' xmlns='http://www.w3.org/2000/svg' fill='none'
                     viewBox='0 0 24 24'>
                    <use href='#lbaic-settings-close'/>
                </svg>
            </button>
        </div>
    }

    /**
     * Render files
     *
     * @param {object} data Files
     * @param {string} type Files type
     * @return {*[]}
     */
    const renderFiles = (data, type = false) => {
        return Object.entries(data).map(([vectorStoreId, vectorStoreFiles]) => vectorStoreFiles.map((file) => renderFile(file, vectorStoreId, type)));
    }

    /**
     * Delete function tool
     *
     * @param {object} fn Function
     * @param {number} index Index of the function tool
     * @return {Promise<boolean>}
     */
    const deleteFunction = async (fn, index) => {
        if (await confirm(__("Are you sure you want to delete the function?", 'limb-chatbot'))) {
            // Remove function tool by index
            const tools = settings['tools'][0].filter((item, i) => i !== index);

            const res = await aiProvider.current?.updateAssistant(assistant.id, {tools});
            if (res.status) {
                // Update assistant
                setAssistant(res.data);
                // Refresh tools list, including functions
                settings['tools'][1](res.data.tools || []);
                handleSuccess(notifications.set, {
                    title: __("Real time helper deleted.", 'limb-chatbot'),
                });
                return true;
            } else {
                handleError({message: res.data}, notifications.set, {
                    title: __("Failed to delete real time helper.", 'limb-chatbot'),
                    description: res.data || __("Please check your connection and try again.", 'limb-chatbot'),
                });
            }
        }
        return false;
    }

    /**
     * Render function calling
     *
     * @return {JSX.Element[]}
     */
    const renderFunction = (item, i) => {
        if (item.type === 'function') {
            return <div key={i} className='lbaic-settings-e-oaiu-file'>
                <svg className='lbaic-settings-e-oaiu-file-i' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24'>
                    <use href='#lbaic-settings-function'/>
                </svg>
                <span className='lbaic-settings-e-oaiu-file-label'>{item.function?.name}</span>
                <button
                    className={`lbaic-settings-button-reset lbaic-settings-e-oaiu-file-remove${!assistant?.id ? ' lbaic-settings-button-disabled' : ''}`}
                    onClick={() => deleteFunction(item, i)}>
                    <svg className='lbaic-settings-e-oaiu-file-remove-i' xmlns='http://www.w3.org/2000/svg' fill='none'
                         viewBox='0 0 24 24'>
                        <use href='#lbaic-settings-close'/>
                    </svg>
                </button>
            </div>
        } else {
            return false;
        }
    }

    /**
     * Add function
     *
     * @param {object} obj Function calling function
     */
    const functionAdded = async (obj) => {
        settings['tools'][1]([
            ...settings['tools'][0],
            {
                type: 'function',
                function: obj
            }
        ]);
        return true;
    }

    /**
     * Save
     *
     * @return {Promise<void>}
     */
    const save = async () => {
        if (!aiProvider.current) {
            return;
        }
        setSaving(true);
        // Get data to update
        const data = LimbChatbot.Hooks.applyFilters('lbaic.admin.page.settings.ai-provider.utility.assistant.dataToUpdate', getDataFromState(settings), 'open-ai');
        // Update assistant
        const {id, ...body} = data;
        const res = await aiProvider.current?.updateAssistant(id, body);
        if (res.status) {
            initialData.current = getInitialData(settings);
        } else {
            handleError({message: res.data}, notifications.set, {
                title: __("Failed to save assistant.", 'limb-chatbot'),
                description: res.data || __("Please try again.", 'limb-chatbot'),
            });
        }
        setSaving(false);
    }

    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'>{__("Assistant", 'limb-chatbot')}</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-divider lbaic-settings-divider-loading'>
                    {saving && <LoadingBar/>}
                </div>
                <div className='lbaic-settings-table-accordion-content lbaic-settings-e-oaiu-table-content'>
                    {loading > 0 && !isDataFetched && <TableAccordionContentLoading/>}
                    <div className='lbaic-settings-column'>
                        <div className="lbaic-settings-column-in">
                            <Dropdown value={config?.id}
                                      setValue={configSelected}
                                      defaultIcon='key-vertical'
                                      options={configs.map(item => ({
                                          label: item.title,
                                          value: item.id,
                                          extra: item,
                                      }))}
                                      placeholder={__("API key", 'limb-chatbot')}
                                      searchable
                                      search={async (params) => await getConfigs(params, true)}
                                      loadMore={async (params) => await getConfigs(params)}
                                      pagination={{
                                          get: configsPagination,
                                          set: setConfigsPagination,
                                      }}/>
                        </div>
                    </div>
                    <div className='lbaic-settings-divider lbaic-settings-divider-light lbaic-settings-divider-gap-end'/>
                    <div className="lbaic-settings-column">
                        <div className="lbaic-settings-column-in">
                            <Dropdown value={settings['id'][0]}
                                      setValue={handleAssistantSelectChange}
                                      options={assistants.options}
                                      placeholder={__("Select or create assistant", 'limb-chatbot')}
                                      searchable
                                      hasDeselect={showCreateAssistant}
                                      deselectOptionLabel={'+ ' + __("Create assistant", 'limb-chatbot')}
                                      disabled={!config?.id}/>
                        </div>
                    </div>
                    {!!assistant?.id &&
                        <div className='lbaic-settings-column'>
                            <div className='lbaic-settings-column-in'>
                                <div className="lbaic-settings-e-oaiu-row-in">
                                    <div className="lbaic-settings-e-oaiu-row-inner">
                                        <div className='lbaic-settings-e-oaiu-row-desc'>
                                            <span
                                                className='lbaic-settings-e-oaiu-row-desc-in'>{__("Created on", 'limb-chatbot')} {getFormatedTimestamp(assistant.created_at * 1000)}</span>
                                        </div>
                                        <div className='lbaic-settings-e-oaiu-row-actions'>
                                            <button className='lbaic-settings-e-oaiu-row-actions-in lbaic-settings-button-reset'
                                                    onClick={deleteAssistant}>
                                                <svg className='lbaic-settings-e-oaiu-row-actions-i'
                                                     xmlns='http://www.w3.org/2000/svg'
                                                     fill='none' viewBox='0 0 24 24'>
                                                    <use href='#lbaic-settings-delete'/>
                                                </svg>
                                            </button>
                                            <button className='lbaic-settings-e-oaiu-row-actions-in lbaic-settings-button-reset'
                                                    onClick={cloneAssistant}>
                                                <svg className='lbaic-settings-e-oaiu-row-actions-i'
                                                     xmlns='http://www.w3.org/2000/svg'
                                                     fill='none' viewBox='0 0 24 24'>
                                                    <use href='#lbaic-settings-copy'/>
                                                </svg>
                                            </button>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>}
                    <div className='lbaic-settings-divider lbaic-settings-divider-light lbaic-settings-divider-gap-end'/>
                    <div className="lbaic-settings-column">
                        <div className="lbaic-settings-column-in">
                            <Input value={settings['name'][0]} setValue={settings['name'][1]}
                                   placeholder={__("Name", 'limb-chatbot')} disabled={!assistant?.id}/>
                        </div>
                    </div>
                    <div className="lbaic-settings-column">
                        <div className="lbaic-settings-column-in">
                            <BlockEditable value={settings['instructions'][0]}
                                           setValue={settings['instructions'][1]}
                                           label={__("Instructions", 'limb-chatbot')}
                                           notifications={notifications}
                                           disabled={!assistant?.id}/>
                        </div>
                    </div>
                    <div className="lbaic-settings-column">
                        <div className="lbaic-settings-column-in">
                            <Dropdown value={settings['model'][0]} setValue={settings['model'][1]}
                                      defaultValue={{value: assistant.model, name: assistant.model, icon: 'open-ai'}}
                                      options={models.map(item => ({
                                          label: item.label,
                                          value: item.name,
                                          icon: item.ai_provider_id,
                                      }))}
                                      placeholder={__("Model", 'limb-chatbot')}
                                      searchable
                                      search={async (params) => await getModels(params, true)}
                                      loadMore={async (params) => await getModels(params)}
                                      pagination={{
                                          get: modelsPagination,
                                          set: setModelsPagination,
                                      }}
                                      disabled={!assistant?.id}/>
                        </div>
                        <div className="lbaic-settings-column-in">
                            {/*<Dropdown value={settings['response_format'][0]?.type || settings['response_format'][0]}
                                      setValue={settings['response_format'][1]}
                                      options={responseFormats}
                                      placeholder={__("Response format", 'limb-chatbot')}
                                      disabled={!assistant?.id}/>*/}
                        </div>
                    </div>
                    <div className='lbaic-settings-divider lbaic-settings-divider-light lbaic-settings-divider-gap-end'/>
                    <div className="lbaic-settings-column">
                        <div className="lbaic-settings-column-in">
                            <div className="lbaic-settings-row lbaic-settings-e-oaiu-row">
                                <div className="lbaic-settings-row-in">
                                    <div className="lbaic-settings-label">
                                        <h5 className="lbaic-settings-label-in">{__("File search", 'limb-chatbot')}</h5>
                                        <Tooltip
                                            label={__("File search enables the assistant with knowledge from files that you or your users upload. Once a file is uploaded, the assistant automatically decides when to retrieve content based on user requests.", 'limb-chatbot')}
                                            width={230}/>
                                    </div>
                                    <Toggle
                                        isActive={settings['tools'][0]?.findIndex(item => item.type === 'file_search') !== -1}
                                        onClick={() => {
                                            const i = settings['tools'][0]?.findIndex(item => item.type === 'file_search');
                                            if (i !== -1) {
                                                // Remove
                                                settings['tools'][1](settings['tools'][0].filter(item => item.type !== 'file_search'));
                                            } else {
                                                // Add
                                                settings['tools'][1]([
                                                    ...settings['tools'][0],
                                                    {
                                                        type: 'file_search',
                                                    }
                                                ]);
                                            }
                                        }}
                                        disabled={!assistant?.id}/>
                                </div>
                                {settings['tools'][0]?.findIndex(item => item.type === 'file_search') !== -1 &&
                                    <div className="lbaic-settings-desc">
                                        <button
                                            className={`lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-32 lbaic-settings-button-secondary${!assistant?.id ? ' lbaic-settings-button-disabled' : ''}`}
                                            onClick={() => setShowAddNewFilePopup('file_search')}>
                                            <svg className='lbaic-settings-button-i' xmlns='http://www.w3.org/2000/svg'
                                                 fill='none' viewBox='0 0 24 24'>
                                                <use href='#lbaic-settings-plus'/>
                                            </svg>
                                            <span className='lbaic-settings-button-label'>{__("Add file", 'limb-chatbot')}</span>
                                        </button>
                                        {!!Object.keys(fsFiles).length &&
                                            <div className='lbaic-settings-e-oaiu-file-group'>
                                                {renderFiles(fsFiles, 'file_search')}
                                            </div>}
                                    </div>}
                            </div>
                        </div>
                        <div className="lbaic-settings-column-in">
                            <div className="lbaic-settings-row lbaic-settings-e-oaiu-row">
                                <div className="lbaic-settings-row-in">
                                    <div className="lbaic-settings-label">
                                        <h5 className="lbaic-settings-label-in">{__("Code interpreter", 'limb-chatbot')}</h5>
                                        <Tooltip
                                            label={__("Code Interpreter enables the assistant to write and run code. This tool can process files with diverse data and formatting, and generate files such as graphs.", 'limb-chatbot')}
                                            width={230}/>
                                    </div>
                                    <Toggle
                                        isActive={settings['tools'][0]?.findIndex(item => item.type === 'code_interpreter') !== -1}
                                        onClick={() => {
                                            const i = settings['tools'][0]?.findIndex(item => item.type === 'code_interpreter');
                                            if (i !== -1) {
                                                // Remove
                                                settings['tools'][1](settings['tools'][0].filter(item => item.type !== 'code_interpreter'));
                                            } else {
                                                // Add
                                                settings['tools'][1]([
                                                    ...settings['tools'][0],
                                                    {
                                                        type: 'code_interpreter',
                                                    }
                                                ]);
                                            }
                                        }}
                                        disabled={!assistant?.id}/>
                                </div>
                                {settings['tools'][0]?.findIndex(item => item.type === 'code_interpreter') !== -1 &&
                                    <div className="lbaic-settings-desc">
                                        <button
                                            className={`lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-32 lbaic-settings-button-secondary${!assistant?.id ? ' lbaic-settings-button-disabled' : ''}`}
                                            onClick={() => setShowAddNewFilePopup('code_interpreter')}>
                                            <svg className='lbaic-settings-button-i' xmlns='http://www.w3.org/2000/svg'
                                                 fill='none' viewBox='0 0 24 24'>
                                                <use href='#lbaic-settings-plus'/>
                                            </svg>
                                            <span className='lbaic-settings-button-label'>{__("Add file", 'limb-chatbot')}</span>
                                        </button>
                                        {!!ciFiles.length &&
                                            <div className='lbaic-settings-e-oaiu-file-group'>
                                                {ciFiles.map((file) => renderFile(file, false, 'code_interpreter'))}
                                            </div>}
                                    </div>}
                            </div>
                        </div>
                    </div>
                    <ExpandableContainer label={__("Advanced", 'limb-chatbot')}>
                        <div className="lbaic-settings-column">
                            <div className="lbaic-settings-column-in">
                                <div className="lbaic-settings-row lbaic-settings-e-oaiu-row">
                                    <div className="lbaic-settings-row-in">
                                        <div className="lbaic-settings-label">
                                            <h5 className="lbaic-settings-label-in">{__("Add real time helpers", 'limb-chatbot')}</h5>
                                            <Tooltip
                                                label={__("Function calling lets you describe custom functions of your app or external APIs to the assistant. This allows the assistant to intelligently call those functions by outputting a JSON object containing relevant arguments.", 'limb-chatbot')}
                                                width={230}/>
                                        </div>
                                    </div>
                                    <div className="lbaic-settings-desc">
                                        <button
                                            className={`lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-32 lbaic-settings-button-secondary${!assistant?.id ? ' lbaic-settings-button-disabled' : ''}`}
                                            onClick={() => setShowAddFunctionPopup(true)}>
                                            <svg className='lbaic-settings-button-i' xmlns='http://www.w3.org/2000/svg'
                                                 fill='none' viewBox='0 0 24 24'>
                                                <use href='#lbaic-settings-plus'/>
                                            </svg>
                                            <span className='lbaic-settings-button-label'>{__("Add", 'limb-chatbot')}</span>
                                        </button>
                                        {settings['tools'][0]?.findIndex(item => item.type === 'function') !== -1 &&
                                            <div className='lbaic-settings-e-oaiu-file-group'>
                                                {settings['tools'][0].map(renderFunction)}
                                            </div>}
                                    </div>
                                </div>
                            </div>
                            <div className="lbaic-settings-column-in"/>
                        </div>
                    </ExpandableContainer>
                </div>
            </td>
        </tr>
        {!!showAddNewFilePopup &&
            <AddNewFile type={showAddNewFilePopup}
                        files={showAddNewFilePopup === 'file_search' ? fsFiles : (showAddNewFilePopup === 'code_interpreter' ? ciFiles : [])}
                        added={showAddNewFilePopup === 'file_search' ? fsFileAdded : (showAddNewFilePopup === 'code_interpreter' ? ciFileAdded : null)}
                        deleted={showAddNewFilePopup === 'file_search' ? deleteFSFile : (showAddNewFilePopup === 'code_interpreter' ? deleteCIFile : null)}
                        close={() => setShowAddNewFilePopup(false)} notifications={notifications}/>}
        {showAddFunctionPopup &&
            <AddFunction added={functionAdded} close={() => setShowAddFunctionPopup(false)}
                         notifications={notifications}/>}
    </>
}