import {useEffect, useState} from "@wordpress/element";
import {__} from "@wordpress/i18n";
import Input from "../../../../../fields/input";
import {getDataFromState} from "../../../../../../helpers";
import {handleError, handleSuccess} from "../../../../../../helpers/notifications";
import {TuningDataset} from "../../../../../../rest/datasets";
import {required, validate} from "../../../../../../../validations";
import PopupContainer from "../../../../container";
import {GetDefaultSettings} from "../../../../../../helpers/rest";
import Model from "../../../../../fields/specific-fields/model";
import Config from "../../../../../fields/specific-fields/config";
import ExpandableContainer from "../../../../../fields/expandable-container";
import {GetDatasetMetas} from "../../../../../../rest/dataset-metas";

export default function RunDataset({datasetId, close, notifications}) {
    // Actions states
    const [loading, setLoading] = useState(0);
    const [isDataFetched, setIsDataFetched] = useState(false);
    const [isDataSet, setIsDataSet] = useState(false);
    const [running, setRunning] = useState(false);
    const [modelsFetched, setModelsFetched] = useState(false);
    const [configsFetched, setConfigsFetched] = useState(false);
    const [variablesFetched, setVariablesFetched] = useState(false);
    const [aiProviderId, setAIProviderId] = useState(null);
    // Tune data
    const settings = {
        'ai_model_id': useState(''),
        'config_id': useState(''),
        'suffix': useState(''),
    };
    const errors = {
        'ai_model_id': useState(false),
        'config_id': useState(false),
        'suffix': useState(false),
    };
    // Variables
    const [variables, setVariables] = useState({});
    const [variablesKeys, setVariablesKeys] = useState([]);

    useEffect(() => {
        getDefaults();
        getVariables();
    }, []);

    useEffect(() => {
        setIsDataFetched(modelsFetched && configsFetched && variablesFetched);
    }, [modelsFetched, configsFetched, variablesFetched]);

    useEffect(() => {
        setVariablesKeys(Object.keys(variables));
    }, [variables]);

    /**
     * Get defaults
     *
     * @return {Promise<void>}
     */
    const getDefaults = async () => {
        setLoading(prev => prev + 1);
        const settingsKeys = [
            {
                key: 'ai_model_id',
                defaultValue: '',
            },
            {
                key: 'config_id',
                defaultValue: '',
            },
        ];
        const defaults = await GetDefaultSettings(
            'fine-tuning',
            settingsKeys
        );
        // Setup default values
        settingsKeys.forEach(item => {
            settings[item.key][1](defaults[item.key]);
        });
        setIsDataSet(true);
        setLoading(prev => prev - 1);
    }

    /**
     * Get variables
     */
    const getVariables = async () => {
        setLoading(prev => prev + 1);
        try {
            const res = await GetDatasetMetas(LimbChatbot.rest.url, LimbChatbot.rest.nonce, datasetId, {
                meta_key: ['variables'],
            });
            if (res?.length) {
                setVariables(res[0].meta_value);
            }
        } catch (e) {
            handleError(e, notifications.set, {
                title: __("Failed to get variables.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Something went wrong.", 'limb-chatbot'),
            });
        }
        setVariablesFetched(true);
        setLoading(prev => prev - 1);
    }

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

            switch (name) {
                case 'suffix':
                case 'ai_model_id':
                case 'ai_config_id':
                    validations = [required];
                    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;
        }
    }

    /**
     * Run tuning
     */
    const run = () => {
        let hasError = false;
        for (const item of Object.keys(settings)) {
            if (!validateField(item, settings[item][0])) {
                hasError = true;
            }
        }
        if (!hasError) {
            setRunning(true);
            const data = LimbChatbot.Hooks.applyFilters('lbaic.admin.page.settings.advanced.training.datasets.run', getDataFromState(settings));
            // Check for variables
            const variablesData = LimbChatbot.Hooks.applyFilters('lbaic.admin.page.settings.advanced.training.datasets.run.variables', variables);
            if (variablesData && Object.keys(variablesData).length) {
                data.variables = variablesData;
            }
            TuningDataset(LimbChatbot.rest.url, LimbChatbot.rest.nonce, {
                ...data,
                dataset_id: +datasetId,
            }).then(res => {
                handleSuccess(notifications.set, {
                    title: __("Data saved successfully.", 'limb-chatbot'),
                });
                close(true);
                setRunning(false);
            }).catch(e => {
                setRunning(false);
                handleError(e, notifications.set, {
                    title: __("Failed to run Q&A.", 'limb-chatbot'),
                    description: e.message ? __(e.message, 'limb-chatbot') : __("Please check your connection and try again.", 'limb-chatbot'),
                });
            });
        }
    }

    return <PopupContainer title={__("Run", 'limb-chatbot')} description={__("Fill the following fields", 'limb-chatbot')} close={close}
                           loading={loading > 0 || running}
                           showLoadingContainer={loading > 0 && (!isDataFetched || !isDataSet)}
                           footer={<>
                               <button
                                   className={`lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-40 lbaic-settings-button-primary${loading || running ? ' lbaic-settings-button-disabled' : ''}`}
                                   onClick={run}>
                                   {running &&
                                       <svg className='lbaic-settings-button-i lbaic-settings-loading-circle lbaic-settings-button-loading-circle'
                                            xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24'>
                                           <use href='#lbaic-settings-circle'/>
                                       </svg>}
                                   <span className='lbaic-settings-button-label'>{__("Run", 'limb-chatbot')}</span>
                               </button>
                               <button className='lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-40 lbaic-settings-button-secondary'
                                       onClick={close}>
                                   <span className='lbaic-settings-button-label'>{__("Cancel", 'limb-chatbot')}</span>
                               </button>
                           </>}>
        <div className='lbaic-settings-column'>
            <div className='lbaic-settings-column-in'>
                <Model isDataFetched={isDataSet}
                       modelId={settings['ai_model_id'][0]}
                       setModelId={settings['ai_model_id'][1]}
                       endpoints={['fine_tuning']}
                       setFetched={setModelsFetched}
                       aiProviderSelected={setAIProviderId}
                       setLoading={setLoading}
                       notifications={notifications}/>
            </div>
        </div>
        <div className='lbaic-settings-column'>
            <div className='lbaic-settings-column-in'>
                <Config aiProviderId={aiProviderId}
                        isDataFetched={isDataSet}
                        configId={settings['config_id'][0]}
                        setConfigId={settings['config_id'][1]}
                        setFetched={setConfigsFetched}
                        setLoading={setLoading}
                        notifications={notifications}/>
            </div>
        </div>
        <div className='lbaic-settings-column'>
            <div className='lbaic-settings-column-in'>
                <Input value={settings['suffix'][0]} setValue={settings['suffix'][1]}
                       placeholder={__("Suffix", 'limb-chatbot')}
                       validate={(value) => validateField('suffix', value)}
                       errorMessage={errors['suffix'][0]}
                       autofocus/>
            </div>
        </div>
        {variablesKeys.length > 0 &&
            <ExpandableContainer label={__("Variables", 'limb-chatbot')}>
                {variablesKeys.map(key =>
                    <div key={key} className='lbaic-settings-column'>
                        <div className='lbaic-settings-column-in'>
                            <Input value={variables[key]}
                                   setValue={(value) => setVariables(prevState => ({
                                       ...prevState,
                                       [key]: value,
                                   }))}
                                   placeholder={`{{${key}}}`}/>
                        </div>
                    </div>)}
            </ExpandableContainer>}
    </PopupContainer>;
}