import {forwardRef, useEffect, useImperativeHandle, useRef, useState} from "@wordpress/element";
import {__} from "@wordpress/i18n";
import {alphanumericAndSpec, required, validate} from "../../../../../../../../validations";
import Dropdown from "../../../../../../fields/dropdown";
import Tooltip from "../../../../../../fields/tooltip";
import Input from "../../../../../../fields/input";
import {ADVANCED_SETTINGS_REQUIRED_DATABASES, DATABASES, METRICS} from "../data";
import {handleError} from "../../../../../../../helpers/notifications";
import AddNewConfig from "../../../../../../popups/ai-providers/models/add-edit-config";
import {GetDefaultSettings} from "../../../../../../../helpers/rest";
import ExpandableContainer from "../../../../../../fields/expandable-container";
import ChatbotField from "../../../../../../fields/specific-fields/chatbot";
import Config from "../../../../../../fields/specific-fields/config";

const AddEdit = forwardRef(({data, loading, setLoading, setShowLoading, notifications}, ref) => {
    // Actions state
    const [showAddNewConfigPopup, setShowAddNewConfigPopup] = useState(false);
    const [isDataSet, setIsDataSet] = useState(false);
    // Data
    const [formData, setFormData] = useState({
        name: '',
        description: '',
        config_id: 0,
        metas: [
            {
                meta_key: 'dimension',
                meta_value: null,
            },
            {
                meta_key: 'metric',
                meta_value: null,
            },
            {
                meta_key: 'chatbot_uuid',
                meta_value: null,
            },
        ],
    });
    const errors = {
        'database': useState(false),
        'name': useState(false),
        'description': useState(false),
        'config_id': useState(false),
        'metas.chatbot_uuid': useState(false),
        'metas.dimension': useState(false),
        'metas.metric': useState(false),
    };
    const [vectorDBId, setVectorDBId] = useState(data?.vector_db_id || '');
    const configFieldRef = useRef(null);

    useImperativeHandle(ref, () => ({
        getDataToSave() {
            // Validate
            let hasError = false;
            const settings = {
                'database': [vectorDBId],
                'name': [formData.name],
                'description': [formData.description],
                'config_id': [formData.config_id],
                'metas.chatbot_uuid': [formData.metas.find(meta => meta.meta_key === 'chatbot_uuid')?.meta_value || ''],
                'metas.dimension': [formData.metas.find(meta => meta.meta_key === 'dimension')?.meta_value || ''],
                'metas.metric': [formData.metas.find(meta => meta.meta_key === 'metric')?.meta_value || ''],
            };
            for (const item of Object.keys(settings)) {
                if (!validateField(item, settings[item][0])) {
                    hasError = true;
                }
            }
            if (!hasError) {
                const preparedFormData = JSON.parse(JSON.stringify(formData));
                if (vectorDBId === 'local') {
                    delete preparedFormData.config_id;
                }
                // Replace 'default' with null for chatbot_uuid
                const chatbotMeta = preparedFormData.metas.find(meta => meta.meta_key === 'chatbot_uuid');
                if (chatbotMeta && chatbotMeta.meta_value === 'default') {
                    chatbotMeta.meta_value = null;
                }
                return LimbChatbot.Hooks.applyFilters('lbaic.admin.page.settings.knowledge.storage.dataToSave', preparedFormData, data?.id);
            }
            return false;
        },
    }));

    useEffect(() => {
        setDefaultValues();
    }, []);

    useEffect(() => {
        setShowLoading(loading > 0 && !isDataSet);
    }, [loading, isDataSet]);

    /**
     * Validate field
     *
     * @param {string} name Field name
     * @param {any} value Field value
     * @return {boolean}
     */
    const validateField = (name, value) => {
        try {
            let validations = [];

            switch (name) {
                case 'config_id':
                    if (vectorDBId !== 'local') {
                        validations = [required];
                    }
                    break;
                case 'database':
                case 'metas.chatbot_uuid':
                case 'metas.dimension':
                case 'metas.metric':
                    validations = [required];
                    break;
                case 'name':
                    validations = [(v) => alphanumericAndSpec(v, '-', {lowercase: true})];
                    break;
                default:
                    break;
            }
            const res = validate(value, validations);
            // Update field errors state
            errors[name][1](!res.valid ? res.message : false);

            return res.valid;
        } catch (e) {
            handleError(e, notifications.set, {
                title: __("Field validation failed.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Something went wrong.", 'limb-chatbot'),
            });
            return false;
        }
    }

    const setDefaultValues = async () => {
        setLoading(prev => prev + 1);
        // Default settings
        const defaults = await GetDefaultSettings('embedding', [
            {
                key: 'dimension',
                defaultValue: 1536
            }
        ]);
        // Name
        const name = data?.name || '';
        // Description
        const description = data?.description || '';
        // Config
        const configId = data?.config_id || 0;
        // Dimension
        const dimension = data?.metas?.find(item => item.meta_key === 'dimension')?.meta_value || defaults.dimension;
        // Metric
        let metric = data?.metas?.find(item => item.meta_key === 'metric')?.meta_value || METRICS[0].value;
        // Chatbot
        const chatbotUuid = data?.metas?.find(item => item.meta_key === 'chatbot_uuid')?.meta_value || null;
        // Setup default values
        setFormData(prevState => ({
            ...prevState,
            name: name,
            description: description,
            config_id: configId,
            metas: prevState.metas.map(item => {
                switch (item.meta_key) {
                    case 'dimension':
                        return {
                            ...item,
                            meta_value: dimension,
                        };
                    case 'metric':
                        return {
                            ...item,
                            meta_value: metric,
                        };
                    case 'chatbot_uuid':
                        return {
                            ...item,
                            meta_value: chatbotUuid,
                        };
                    default:
                        return item
                }
            }),
        }));
        setIsDataSet(true);
        setLoading(prev => prev - 1);
    }

    /**
     * Set config ID
     *
     * @param {number|string} configId Config ID
     */
    const setConfigId = (configId) => {
        // Convert empty string or falsy values to 0, otherwise use the configId
        const id = (configId && configId !== '') ? configId : 0;
        setFormData(prevState => ({
            ...prevState,
            config_id: id
        }));
    }

    /**
     * Add new created config
     *
     * @param {object} newConfig New config data
     */
    const newConfigAdded = (newConfig) => {
        if (configFieldRef.current?.newConfigAdded) {
            configFieldRef.current.newConfigAdded(newConfig);
        }
    }

    /**
     * Update form data meta value
     *
     * @param {string} key Meta key
     * @param {string|number} value Meta value
     */
    const updateMetaValue = (key, value) => {
        setFormData(prevState => ({
            ...prevState,
            metas: [
                ...prevState.metas.map(item => {
                    if (item.meta_key === key) {
                        return {
                            ...item,
                            meta_value: value
                        }
                    } else {
                        return item;
                    }
                })
            ]
        }));
    }

    const selectedChatbotUuid = formData.metas.find(item => item.meta_key === 'chatbot_uuid')?.meta_value;

    return <>
        <div className='lbaic-settings-column'>
            <div className='lbaic-settings-column-in'>
                <Dropdown value={vectorDBId} setValue={setVectorDBId}
                          options={DATABASES} placeholder={__("Provider", 'limb-chatbot')}
                          validate={(value) => validateField('database', value)}
                          errorMessage={errors['database'][0]}
                          iconClassName='lbaic-settings-dropdown-kb-icon'>
                    {/*<Tooltip label={__("Database", 'limb-chatbot')}/>*/}
                </Dropdown>
            </div>
            <div className='lbaic-settings-column-in'>
                {ADVANCED_SETTINGS_REQUIRED_DATABASES.indexOf(vectorDBId) !== -1 &&
                    <Config
                        ref={configFieldRef}
                        aiProviderId={vectorDBId}
                        isDataFetched={isDataSet}
                        isDefaultsChecked={true}
                        configId={formData.config_id}
                        setConfigId={setConfigId}
                        fieldProps={{
                            validate: (value) => validateField('config_id', value),
                            errorMessage: errors['config_id'][0],
                            addNew: () => setShowAddNewConfigPopup(true)
                        }}
                        autoSelect={true}
                        disabled={!vectorDBId || vectorDBId === 'local'}
                        setLoading={setLoading}
                        notifications={notifications}
                    />}
            </div>
        </div>
        {Boolean(vectorDBId) &&
            <>
                <div className='lbaic-settings-column'>
                    <div className='lbaic-settings-column-in'>
                        <Input value={formData.name}
                               setValue={(value) => setFormData(prevState => ({...prevState, name: value}))}
                               placeholder={__("Name", 'limb-chatbot')}
                               autofocus
                               validate={(value) => validateField('name', value)}
                               errorMessage={errors['name'][0]}>
                            {/*<Tooltip label={__("Name", 'limb-chatbot')}/>*/}
                        </Input>
                    </div>
                    <div className='lbaic-settings-column-in'>
                        <Input value={formData.description}
                               setValue={(value) => setFormData(prevState => ({...prevState, description: value}))}
                               placeholder={__("Description", 'limb-chatbot')}
                               validate={(value) => validateField('description', value)}
                               errorMessage={errors['description'][0]}/>
                    </div>
                </div>
                <div className='lbaic-settings-column'>
                    <div className='lbaic-settings-column-in'>
                        <ChatbotField
                            value={selectedChatbotUuid}
                            setValue={(chatbotUuid) => updateMetaValue('chatbot_uuid', chatbotUuid)}
                            setLoading={setLoading}
                            notifications={notifications}
                            fieldProps={{
                                validate: (value) => validateField('metas.chatbot_uuid', value),
                                errorMessage: errors['metas.chatbot_uuid'][0]
                            }}
                        >
                            {/*<Tooltip label={__("Chatbot", 'limb-chatbot')}/>*/}
                        </ChatbotField>
                    </div>
                    <div className='lbaic-settings-column-in'/>
                </div>
                <ExpandableContainer label={__("Advanced", 'limb-chatbot')}>
                    <div className='lbaic-settings-column'>
                        <div className='lbaic-settings-column-in'>
                            <Input value={formData.metas.find(item => item.meta_key === 'dimension')?.meta_value}
                                   setValue={(value) => updateMetaValue('dimension', value)}
                                   type="integer"
                                   placeholder={__("Dimension", 'limb-chatbot')}
                                   validate={(value) => validateField('metas.dimension', value)}
                                   errorMessage={errors['metas.dimension'][0]}>
                                {/*<Tooltip label={__("Dimension", 'limb-chatbot')}/>*/}
                            </Input>
                        </div>
                        <div className='lbaic-settings-column-in'>
                            <Dropdown value={formData.metas.find(item => item.meta_key === 'metric')?.meta_value}
                                      setValue={(value) => updateMetaValue('metric', value)}
                                      options={METRICS} placeholder={__("Metric", 'limb-chatbot')}
                                      validate={(value) => validateField('metas.metric', value)}
                                      errorMessage={errors['metas.metric'][0]}>
                                {/*<Tooltip label={__("Metric", 'limb-chatbot')}/>*/}
                            </Dropdown>
                        </div>
                    </div>
                </ExpandableContainer>
            </>}
        {showAddNewConfigPopup &&
            <AddNewConfig aiProviderId={vectorDBId} added={newConfigAdded}
                          close={() => setShowAddNewConfigPopup(false)}
                          notifications={notifications}/>}
    </>
});

export default AddEdit;