import {useEffect, useRef, useState} from "@wordpress/element";
import {__} from "@wordpress/i18n";
import Input from "../../../../../../fields/input";
import Toggle from "../../../../../../fields/toggle";
import Container from "../../../../containers/content/container";
import TabSettings from "../../../../../components/tab-settings";
import Dropdown from "../../../../../../fields/dropdown";
import Textarea from "../../../../../../fields/textarea";
import {required, validate} from "../../../../../../../../validations";
import {handleError} from "../../../../../../../helpers/notifications";
import useSettingsErrorsState from "../../../../../components/hooks/settings-errors-state";
import Notice from "../../../../../../sections/notice";
import Description from "../../../../../../sections/description";
import {AI_PROVIDERS} from "../../../../../../../constants/chatbot/ai";
import AddNewConfig from "../../../../../../popups/ai-providers/models/add-edit-config";
import Model from "../../../../../../fields/specific-fields/model";
import Config from "../../../../../../fields/specific-fields/config";
import {GetDefaultSettings, GetUtilitySettings} from "../../../../../../../helpers/rest";

// Constants
const TAB_NAME = 'settings.chatbot.ai-settings';

export default function Settings({notifications, setChatbotPreview}) {
    // Actions states
    const [showPublishNotice, setShowPublishNotice] = useState(false);
    const [isDataFetched, setIsDataFetched] = useState(false);
    const [loading, setLoading] = useState(0);
    const [isDefaultsFetched, setIsDefaultsFetched] = useState(false);
    const [showContent, setShowContent] = useState(false);
    const [aiProvidersFetched, setAIProvidersFetched] = useState(false);
    const [aiProviderModelsFetched, setAIProviderModelsFetched] = useState(false);
    const [aiProviderConfigsFetched, setAIProviderConfigsFetched] = useState(false);
    const [showAddNewConfigPopup, setShowAddNewConfigPopup] = useState(false);
    // Select options
    const [aiProviders, setAIProviders] = useState([]);
    // Settings
    const settings = {
        'status': useState(0),
        'custom_instructions': useState(''),
        'default_custom_instructions': useState(''),
        'ai_provider_id': useState(''),
        'ai_model_id': useState(''),
        'config_id': useState(''),
        'show_sources': useState(true),
        'kb_vector_similarity_score': useState(40),
        'stream': useState(false),
    };
    // Errors
    const errors = {
        'status': useState(false),
        'custom_instructions': useState(false),
        'ai_provider_id': useState(false),
        'ai_model_id': useState(false),
        'config_id': useState(false),
        'show_sources': useState(false),
        'kb_vector_similarity_score': useState(false),
        'stream': useState(false),
    };
    const settingsRef = useRef({});
    // Helpers
    const aiProviderChanged = useRef(-1);
    const fieldConfigRef = useRef(null);

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

            switch (name) {
                case 'ai_provider_id':
                case 'ai_model_id':
                case 'config_id':
                    validations = [required];
                    break;
                default:
                    return true;
            }
            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;
        }
    }

    useSettingsErrorsState({
        settings,
        errors,
        title: __("Chatbot Settings", 'limb-chatbot'),
        validateField,
        isDataFetched,
    });

    useEffect(() => {
        Object.keys(settings).forEach(key => {
            settingsRef.current[key] = settings[key][0];
        });
    }, [settings]);

    useEffect(() => {
        if (isDataFetched) {
            fetchAIProviders();
            // Add defaults
            getDefaults();
        }
    }, [isDataFetched]);

    useEffect(() => {
        if (isDataFetched) {
            if (++aiProviderChanged.current) {
                // Check config and model default values
                checkConfigAndModelDefaultValues(settings['ai_provider_id'][0]);
            }
        }
    }, [isDataFetched, settings['ai_provider_id'][0]]);

    useEffect(() => {
        setShowContent(
            isDataFetched
            && aiProvidersFetched
            && aiProviderModelsFetched
            && aiProviderConfigsFetched
            && isDefaultsFetched
        );
    }, [isDataFetched, aiProvidersFetched, aiProviderModelsFetched, aiProviderConfigsFetched, isDefaultsFetched]);

    /**
     * Get AI providers
     */
    const fetchAIProviders = () => {
        setAIProviders([...AI_PROVIDERS]);
        setAIProvidersFetched(true);
    }

    /**
     * Get defaults
     *
     * @return {Promise<void>}
     */
    const getDefaults = async () => {
        setIsDefaultsFetched(false);
        setLoading(prev => prev + 1);
        const settingsKeys = [];
        if (!settings['ai_provider_id'][0]) {
            settingsKeys.push({
                key: 'ai_provider_id',
                defaultValue: '',
            });
        }
        if (!settings['ai_model_id'][0]) {
            settingsKeys.push({
                key: 'ai_model_id',
                defaultValue: '',
            });
        }
        if (!settings['config_id'][0]) {
            settingsKeys.push({
                key: 'config_id',
                defaultValue: '',
            });
        }
        // Default settings
        if (settingsKeys.length) {
            const defaults = settings['ai_provider_id'][0]
                ?
                await GetUtilitySettings(
                    settings['ai_provider_id'][0],
                    'chatbot',
                    settingsKeys
                )
                :
                await GetDefaultSettings(
                    'chatbot',
                    settingsKeys
                );
            // Setup default values
            settingsKeys.forEach(item => {
                settings[item.key][1](defaults[item.key]);
            });
        }
        setLoading(prev => prev - 1);
        setIsDefaultsFetched(true);
    }

    /**
     * Check config and model default values
     *
     * @param {string} aiProvider AI provider
     * @return {Promise<void>}
     */
    const checkConfigAndModelDefaultValues = async (aiProvider) => {
        setIsDefaultsFetched(false);
        setLoading(prev => prev + 1);
        const settingsInfo = [
            {
                key: 'ai_model_id',
                defaultValue: '',
            },
            {
                key: 'config_id',
                defaultValue: '',
            }
        ];
        // Default settings
        const defaults = await GetUtilitySettings(
            aiProvider,
            'chatbot',
            settingsInfo
        );
        // Setup default values
        settingsInfo.forEach(item => {
            settings[item.key][1](defaults[item.key]);
        });
        setLoading(prev => prev - 1);
        setIsDefaultsFetched(true);
    }

    /**
     * Config selected
     *
     * @param {object} config Config object
     */
    const configSelected = (config) => {
        // Config selection is handled by the Config component
        // This callback is kept for potential future use
    }

    /**
     * New config added
     *
     * @param {object} newConfig New config
     */
    const newConfigAdded = (newConfig) => {
        if (typeof fieldConfigRef.current?.newConfigAdded === 'function') {
            fieldConfigRef.current.newConfigAdded(newConfig);
        }
    }

    const onDbDataReady = (data) => {
        setShowPublishNotice(+data?.status !== 1);
    }

    return <>
        <TabSettings
            name={TAB_NAME}
            settings={settings}
            notifications={notifications}
            keysPrefix='lbaic.utilities.chatbot'
            dataFetched={value => setIsDataFetched(value)}
            shouldUpdatePreviewData
            setChatbotPreview={setChatbotPreview}
            onDbDataReady={onDbDataReady}
            validateField={validateField}
            contentLoading={!showContent}
            tabLoading={loading}
        >
            <Container className="lbaic-settings-cb-ms">
                {showPublishNotice && (
                    <>
                        <Notice
                            type="warning"
                            desc={__("Check the toggle below to publish your chatbot.", 'limb-chatbot')}
                        />
                        <div className="lbaic-settings-divider-gap-end"/>
                    </>
                )}
                <div className="lbaic-settings-column">
                    <div className="lbaic-settings-column-in">
                        <Toggle label={__("Publish the chatbot", 'limb-chatbot')}
                                isActive={+settings['status'][0] === 1}
                                onClick={() => settings['status'][1](prevState => +prevState !== 1 ? 1 : 0)}/>
                        <Description>{__("Make the chatbot visible to visitors on your website", 'limb-chatbot')}</Description>
                    </div>
                    <div className="lbaic-settings-column-in"/>
                </div>
                <div className="lbaic-settings-column">
                    <div className="lbaic-settings-column-in">
                        <Textarea
                            value={settings['custom_instructions'][0]}
                            setValue={settings['custom_instructions'][1]}
                            placeholder={__("Custom instructions", 'limb-chatbot')}
                            errorMessage={errors['custom_instructions'][0]}
                            validate={value => validateField('custom_instructions', value)}
                            textareaProps={{rows: 5}}
                            placeholderChildren={
                                settings['custom_instructions'][0] !== settings['default_custom_instructions'][0] && (
                                    <div className="lbaic-settings-textarea-placeholder-actions">
                                        <button
                                            className="lbaic-settings-textarea-placeholder-action"
                                            type="button"
                                            onClick={() => settings['custom_instructions'][1](settings['default_custom_instructions'][0])}
                                        >{__("Reset to default", 'limb-chatbot')}</button>
                                    </div>
                                )
                            }
                        />
                        <Description>{__("Provide specific instructions for how the chatbot should behave and respond.", 'limb-chatbot')}</Description>
                    </div>
                </div>
                <div className="lbaic-settings-column">
                    <div className="lbaic-settings-column-in">
                        <Dropdown
                            value={settings['ai_provider_id'][0]}
                            setValue={settings['ai_provider_id'][1]}
                            options={aiProviders} placeholder={__("AI provider", 'limb-chatbot')}
                                  errorMessage={errors['ai_provider_id'][0]}
                                  validate={value => validateField('ai_provider_id', value)}/>
                        <Description>{__("Select which AI provider powers your chatbot.", 'limb-chatbot')} <a href="https://wpaichatbot.com/documentation/understanding-ai-models/selecting-your-ai-model/#ai-provider-comparison" target="_blank">{__("Learn more", 'limb-chatbot')}</a></Description>
                    </div>
                    <div className="lbaic-settings-column-in">
                        <Model aiProviderId={settings['ai_provider_id'][0]}
                               isAIProviderRequired={true}
                               isDataFetched={isDataFetched}
                               isDefaultsChecked={isDefaultsFetched}
                               modelId={settings['ai_model_id'][0]}
                               setModelId={settings['ai_model_id'][1]}
                               endpoints={['chat_completions']}
                               setFetched={setAIProviderModelsFetched}
                               fieldProps={{
                                   validate: value => validateField('ai_model_id', value),
                                   errorMessage: errors['ai_model_id'][0],
                               }}
                               autoSelect={false}
                               setLoading={setLoading}
                               notifications={notifications}/>
                        <Description>{__("Choose the AI model used to generate chat responses.", 'limb-chatbot')} <a href="https://wpaichatbot.com/documentation/teaching-your-chatbot/adding-knowledge-to-your-chatbot/#showing-knowledge-sources" target="_blank">{__("Learn more", 'limb-chatbot')}</a></Description>
                    </div>
                </div>
                <div className="lbaic-settings-column">
                    <div className="lbaic-settings-column-in">
                        <Config
                            ref={fieldConfigRef}
                            aiProviderId={settings['ai_provider_id'][0]}
                            isDataFetched={isDataFetched}
                            isDefaultsChecked={isDefaultsFetched}
                            configId={settings['config_id'][0]}
                            setConfigId={settings['config_id'][1]}
                            configSelected={configSelected}
                            setFetched={setAIProviderConfigsFetched}
                            fieldProps={{
                                addNew: () => setShowAddNewConfigPopup(true),
                                validate: value => validateField('config_id', value),
                                errorMessage: errors['config_id'][0],
                            }}
                            setLoading={setLoading}
                            notifications={notifications}
                        />
                        <Description>{__("API credential for the selected AI provider.", 'limb-chatbot')} <a
                            href="https://wpaichatbot.com/documentation/understanding-ai-models/selecting-your-ai-model/#configuring-api-keys" target="_blank">{__("Learn more", 'limb-chatbot')}</a></Description>
                    </div>
                    <div className="lbaic-settings-column-in">
                        <Toggle
                            label={__("Stream", 'limb-chatbot')}
                            isActive={settings['stream'][0]}
                            onClick={() => settings['stream'][1](!settings['stream'][0])}
                        />
                        <Description>{__("Enable streaming responses from the AI", 'limb-chatbot')}</Description>
                    </div>
                </div>
            </Container>
        </TabSettings>
        {showAddNewConfigPopup &&
            <AddNewConfig aiProviderId={settings['ai_provider_id'][0]} added={newConfigAdded}
                          close={() => setShowAddNewConfigPopup(false)}
                          notifications={notifications} showMakeDefault={true}/>}
    </>
}