import {useEffect, useRef, useState} from "@wordpress/element";
import {__} from "@wordpress/i18n";
import Container from "../../../containers/content/container";
import TabSettings from "../../../../components/tab-settings";
import {handleError} from "../../../../../../helpers/notifications";
import {required, validate} from "../../../../../../../validations";
import useSettingsErrorsState from "../../../../components/hooks/settings-errors-state";
import Toggle from "../../../../../fields/toggle";
import Description from "../../../../../sections/description";
import Range from "../../../../../fields/range";
import Model from "../../../../../fields/specific-fields/model";
import Config from "../../../../../fields/specific-fields/config";
import AddEditConfig from "../../../../../popups/ai-providers/models/add-edit-config";
import {GetDefaultSettings, GetUtilitySettings} from "../../../../../../helpers/rest";
import Dropdown from "../../../../../fields/dropdown";
import {DATABASES, ADVANCED_SETTINGS_REQUIRED_DATABASES} from "../storages/data";

// Constants
const TAB_NAME = 'settings.knowledge.settings';

export default function KnowledgeSettings({notifications}) {
    const [loading, setLoading] = useState(0);
    const [isDataFetched, setIsDataFetched] = useState(false);
    const [showContent, setShowContent] = useState(false);
    const [isDefaultsFetched, setIsDefaultsFetched] = useState(false);
    const [modelsFetched, setModelsFetched] = useState(false);
    const [configsFetched, setConfigsFetched] = useState(false);
    const [kbAIProviderId, setKbAIProviderId] = useState(null);
    const [showAddNewConfigPopup, setShowAddNewConfigPopup] = useState(false);
    const [showAddNewVectorIndexConfigPopup, setShowAddNewVectorIndexConfigPopup] = useState(false);
    const configRef = useRef(null);
    const vectorIndexConfigRef = useRef(null);
    const initialValuesRef = useRef({
        kb_ai_model_id: null,
        kb_config_id: null,
        ai_provider_id: null,
    });
    const isInitialLoadRef = useRef(true);
    const needsRefetchWithAIProviderRef = useRef(false);
    // Settings
    const settings = {
        'kb_ai_model_id': useState(''),
        'kb_config_id': useState(''),
        'show_sources': useState(true),
        'kb_vector_similarity_score': useState(40),
        'kb_vector_index_type': useState(''),
        'kb_vector_index_config_id': useState(''),
        'kb_sources_section_items_count': useState(1),
    };
    // Errors
    const errors = {
        'kb_ai_model_id': useState(false),
        'kb_config_id': useState(false),
        'show_sources': useState(false),
        'kb_vector_similarity_score': useState(false),
        'kb_vector_index_type': useState(false),
        'kb_vector_index_config_id': useState(false),
        'kb_sources_section_items_count': useState(false),
    };

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

            switch (name) {
                case 'kb_ai_model_id':
                case 'kb_config_id':
                case 'kb_vector_index_type':
                    validations = [required];
                    break;
                case 'kb_vector_index_config_id':
                    if (ADVANCED_SETTINGS_REQUIRED_DATABASES.includes(settings['kb_vector_index_type'][0])) {
                        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: __("Knowledge Settings", 'limb-chatbot'),
        validateField,
        isDataFetched,
    });

    /**
     * Get embeddings utility defaults
     *
     * @param {string|null} aiProviderId AI provider ID (null if not available)
     * @return {Promise<void>}
     */
    const getEmbeddingsUtilityDefaults = async (aiProviderId = null) => {
        setLoading(prev => prev + 1);

        // Mapping between local field names (with kb_ prefix) and API field names (without kb_ prefix)
        const fieldMapping = {
            'kb_ai_model_id': 'ai_model_id',
            'kb_config_id': 'config_id',
        };

        const settingsKeys = [];
        const localFieldNames = [];

        if (!settings['kb_ai_model_id'][0]) {
            const apiKey = fieldMapping['kb_ai_model_id'];
            settingsKeys.push({
                key: apiKey,
                defaultValue: '',
            });
            localFieldNames.push('kb_ai_model_id');
        }
        if (!settings['kb_config_id'][0]) {
            const apiKey = fieldMapping['kb_config_id'];
            settingsKeys.push({
                key: apiKey,
                defaultValue: '',
            });
            localFieldNames.push('kb_config_id');
        }

        if (settingsKeys.length) {
            try {
                const defaults = aiProviderId
                    ? await GetUtilitySettings(aiProviderId, 'embedding', settingsKeys)
                    : await GetDefaultSettings('embedding', settingsKeys);

                // Setup default values - map API response keys back to local field names
                settingsKeys.forEach((item, index) => {
                    const localFieldName = localFieldNames[index];
                    // Check both API key and local key in case response uses different format
                    const value = defaults[item.key] !== undefined ? defaults[item.key] : defaults[localFieldName];
                    if (value !== undefined) {
                        settings[localFieldName][1](value);
                    }
                });
            } catch (e) {
                handleError(e, notifications.set, {
                    title: __("Failed to get default values.", 'limb-chatbot'),
                    description: e.message ? __(e.message, 'limb-chatbot') : __("Something went wrong.", 'limb-chatbot'),
                });
            }
        }

        setLoading(prev => prev - 1);
    }

    /**
     * Get defaults on page load
     *
     * @return {Promise<void>}
     */
    const getDefaults = async () => {
        setIsDefaultsFetched(false);

        // Store initial values
        initialValuesRef.current = {
            kb_ai_model_id: settings['kb_ai_model_id'][0] || null,
            kb_config_id: settings['kb_config_id'][0] || null,
            ai_provider_id: kbAIProviderId || initialValuesRef.current.ai_provider_id || null,
        };

        // Set default value for vector_index_type if not set (default is 'local')
        if (!settings['kb_vector_index_type'][0]) {
            settings['kb_vector_index_type'][1]('local');
        }

        // Determine if we have a saved model
        const hasSavedModel = !!settings['kb_ai_model_id'][0];
        const currentAIProviderId = kbAIProviderId || initialValuesRef.current.ai_provider_id;

        // Get defaults for fields that are not saved
        if (!hasSavedModel) {
            // No model saved - get defaults including default AI provider
            await getEmbeddingsUtilityDefaults(null);
            setIsDefaultsFetched(true);
        } else if (!currentAIProviderId) {
            // Model saved but AI provider ID not available yet - get defaults with null for now
            // Mark that we need to refetch when AI provider becomes available
            needsRefetchWithAIProviderRef.current = true;
            await getEmbeddingsUtilityDefaults(null);
            setIsDefaultsFetched(true);
        } else {
            // Model saved and AI provider ID available - get defaults for this AI provider
            needsRefetchWithAIProviderRef.current = false;
            await getEmbeddingsUtilityDefaults(currentAIProviderId);
            setIsDefaultsFetched(true);
        }
    }

    /**
     * Handle AI provider selected/changed
     *
     * @param {string|null} newAIProviderId New AI provider ID
     */
    const handleAIProviderSelected = (newAIProviderId) => {
        // Update the state
        setKbAIProviderId(newAIProviderId);

        // On initial load
        if (isInitialLoadRef.current) {
            // Store initial AI provider ID
            if (newAIProviderId) {
                initialValuesRef.current.ai_provider_id = newAIProviderId;
            }

            // If we need to refetch defaults with the AI provider (model was saved but AI provider wasn't available)
            if (needsRefetchWithAIProviderRef.current && newAIProviderId && isDefaultsFetched) {
                // Refetch defaults with the correct AI provider
                setIsDefaultsFetched(false);
                getEmbeddingsUtilityDefaults(newAIProviderId).then(() => {
                    setIsDefaultsFetched(true);
                });
                needsRefetchWithAIProviderRef.current = false;
            }
            return;
        }

        // After initial load - handle AI provider changes
        const initialAIProviderId = initialValuesRef.current.ai_provider_id;

        if (newAIProviderId === initialAIProviderId) {
            // Changed back to initial AI provider - restore initial values
            if (initialValuesRef.current.kb_config_id !== null) {
                settings['kb_config_id'][1](initialValuesRef.current.kb_config_id);
            }
        } else if (newAIProviderId) {
            // Changed to new AI provider - get defaults for this provider
            getEmbeddingsUtilityDefaults(newAIProviderId);
        }
    }

    useEffect(() => {
        if (isDataFetched && !isDefaultsFetched) {
            getDefaults().then(() => {
                // Mark initial load as complete after defaults are fetched
                isInitialLoadRef.current = false;
            });
        }
    }, [isDataFetched, isDefaultsFetched]);

    useEffect(() => {
        if (!showContent) {
            if (
                !loading
                && isDataFetched
                && modelsFetched
                && configsFetched
                && isDefaultsFetched
            ) {
                setShowContent(true)
            }
        }
    }, [loading, isDataFetched, modelsFetched, configsFetched, isDefaultsFetched]);

    /**
     * Config selected callback
     *
     * @param {object|null} config Config object
     */
    const handleConfigSelected = (config) => {
        // Ensure state is updated when config is selected (including autoselect)
        if (config?.id) {
            settings['kb_config_id'][1](config.id);
        } else {
            settings['kb_config_id'][1]('');
        }
    }

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

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

    /**
     * Handle vector index type change
     *
     * @param {string} value New vector index type
     */
    const handleVectorIndexTypeChange = (value) => {
        settings['kb_vector_index_type'][1](value);
        validateField('kb_vector_index_type', value);
        if (!ADVANCED_SETTINGS_REQUIRED_DATABASES.includes(value)) {
            settings['kb_vector_index_config_id'][1]('');
            errors['kb_vector_index_config_id'][1](false);
        } else {
            validateField('kb_vector_index_config_id', settings['kb_vector_index_config_id'][0]);
        }
    }

    /**
     * Config selected callback for vector index config
     *
     * @param {object|null} config Config object
     */
    const handleVectorIndexConfigSelected = (config) => {
        if (config?.id) {
            settings['kb_vector_index_config_id'][1](config.id);
        } else {
            settings['kb_vector_index_config_id'][1]('');
        }
    }

    const vectorIndexConfigRequired = ADVANCED_SETTINGS_REQUIRED_DATABASES.includes(settings['kb_vector_index_type'][0]);

    return <>
        <TabSettings name={TAB_NAME}
                     settings={settings}
                     keysPrefix='lbaic.utilities.chatbot'
                     validateField={validateField}
                     tabLoading={loading}
                     contentLoading={!showContent}
                     dataFetched={value => setIsDataFetched(value)}
                     notifications={notifications}>
            <Container>
                <div className="lbaic-settings-column">
                    <div className="lbaic-settings-column-in">
                        <Model
                            isDataFetched={isDataFetched}
                            isDefaultsChecked={isDefaultsFetched}
                            modelId={settings['kb_ai_model_id'][0]}
                            setModelId={settings['kb_ai_model_id'][1]}
                            endpoints={['embeddings']}
                            aiProviderSelected={handleAIProviderSelected}
                            setFetched={setModelsFetched}
                            fieldProps={{
                                validate: (value) => validateField('kb_ai_model_id', value),
                                errorMessage: errors['kb_ai_model_id'][0],
                            }}
                            setLoading={setLoading}
                            notifications={notifications}
                        />
                        <Description>{__("Select the embedding model for knowledge collection.", 'limb-chatbot')} <a
                            href="https://wpaichatbot.com/documentation/teaching-your-chatbot/adding-knowledge-to-your-chatbot/#ai-model"
                            target="_blank">{__("Learn more", 'limb-chatbot')}</a></Description>
                    </div>
                    <div className="lbaic-settings-column-in">
                        <Config
                            ref={configRef}
                            aiProviderId={kbAIProviderId}
                            isDataFetched={isDataFetched}
                            isDefaultsChecked={isDefaultsFetched}
                            configId={settings['kb_config_id'][0]}
                            setConfigId={settings['kb_config_id'][1]}
                            configSelected={handleConfigSelected}
                            setFetched={setConfigsFetched}
                            fieldProps={{
                                addNew: () => kbAIProviderId && setShowAddNewConfigPopup(true),
                                validate: (value) => validateField('kb_config_id', value),
                                errorMessage: errors['kb_config_id'][0],
                            }}
                            setLoading={setLoading}
                            notifications={notifications}
                            disabled={!kbAIProviderId}
                        />
                        <Description>{__("Select the API key for the chosen embedding model's provider.", 'limb-chatbot')} <a href="https://wpaichatbot.com/documentation/teaching-your-chatbot/adding-knowledge-to-your-chatbot/#api-key" target="_blank">{__("Learn more", 'limb-chatbot')}</a></Description>
                    </div>
                </div>
                <div className="lbaic-settings-column">
                    <div className="lbaic-settings-column-in">
                        <Dropdown
                            value={settings['kb_vector_index_type'][0]}
                            setValue={handleVectorIndexTypeChange}
                            options={DATABASES}
                            placeholder={__("Storage type", 'limb-chatbot')}
                            validate={(value) => validateField('kb_vector_index_type', value)}
                            errorMessage={errors['kb_vector_index_type'][0]}
                            iconClassName='lbaic-settings-dropdown-kb-icon'
                        />
                        <Description>{__("Select where your chatbot's knowledge will be stored.", 'limb-chatbot')} <a
                            href="https://wpaichatbot.com/documentation/teaching-your-chatbot/knowledge-storage-options/#selecting-storage-type"
                            target="_blank">{__("Learn more", 'limb-chatbot')}</a></Description>
                    </div>
                    <div className="lbaic-settings-column-in">
                        {vectorIndexConfigRequired && (
                            <>
                                <Config
                                    ref={vectorIndexConfigRef}
                                    aiProviderId={settings['kb_vector_index_type'][0]}
                                    isDataFetched={isDataFetched && Boolean(settings['kb_vector_index_type'][0])}
                                    isDefaultsChecked={isDefaultsFetched}
                                    configId={settings['kb_vector_index_config_id'][0]}
                                    setConfigId={settings['kb_vector_index_config_id'][1]}
                                    configSelected={handleVectorIndexConfigSelected}
                                    fieldProps={{
                                        validate: (value) => validateField('kb_vector_index_config_id', value),
                                        errorMessage: errors['kb_vector_index_config_id'][0],
                                        addNew: () => settings['kb_vector_index_type'][0] && setShowAddNewVectorIndexConfigPopup(true),
                                    }}
                                    autoSelect={true}
                                    disabled={!settings['kb_vector_index_type'][0]}
                                    setLoading={setLoading}
                                    notifications={notifications}
                                />
                                <Description>{__("Select Pinecone API key.", 'limb-chatbot')} <a
                                    href="https://wpaichatbot.com/documentation/api-keys-external-services/connecting-pinecone/"
                                    target="_blank">{__("Learn more", 'limb-chatbot')}</a></Description>
                            </>
                        )}
                    </div>
                </div>
                <div className="lbaic-settings-column">
                    <div className="lbaic-settings-column-in">
                        <Toggle
                            label={__("Show knowledge sources", 'limb-chatbot')}
                            isActive={settings['show_sources'][0]}
                            onClick={() => settings['show_sources'][1](!settings['show_sources'][0])}
                        />
                        <Description>{__("Display the knowledge sources referenced for each AI reply below the message.", 'limb-chatbot')} <a href="https://wpaichatbot.com/documentation/teaching-your-chatbot/adding-knowledge-to-your-chatbot/#show-knowledge-sources" target="_blank">{__("Learn more", 'limb-chatbot')}</a></Description>
                    </div>
                    <div className="lbaic-settings-column-in">
                        <Range
                            value={settings['kb_vector_similarity_score'][0]}
                            setValue={settings['kb_vector_similarity_score'][1]}
                            label={__("Similarity threshold", 'limb-chatbot')}
                            className="lbaic-settings-range-h-42"
                            min={0}
                            max={100}
                        />
                        <Description>{__("Minimum similarity score (0–100) for using knowledge in replies. Higher = stricter.", 'limb-chatbot')} <a href="https://wpaichatbot.com/documentation/teaching-your-chatbot/adding-knowledge-to-your-chatbot/#similarity-threshold" target="_blank">{__("Learn more", 'limb-chatbot')}</a></Description>
                    </div>
                </div>
                <div className="lbaic-settings-column">
                    <div className="lbaic-settings-column-in">
                        <Range
                            value={settings['kb_sources_section_items_count'][0]}
                            setValue={settings['kb_sources_section_items_count'][1]}
                            label={__("Show min similars", 'limb-chatbot')}
                            className="lbaic-settings-range-h-42"
                            min={0}
                            max={3}
                            step={1}
                        />
                        <Description>{__("Minimum number of similar knowledge sources to display.", 'limb-chatbot')}</Description>
                    </div>
                    <div className="lbaic-settings-column-in"/>
                </div>
            </Container>
        </TabSettings>
        {showAddNewConfigPopup &&
            <AddEditConfig
                aiProviderId={kbAIProviderId}
                added={newConfigAdded}
                close={() => setShowAddNewConfigPopup(false)}
                notifications={notifications}
                showMakeDefault={true}
            />}
        {showAddNewVectorIndexConfigPopup &&
            <AddEditConfig
                aiProviderId={settings['kb_vector_index_type'][0]}
                added={newVectorIndexConfigAdded}
                close={() => setShowAddNewVectorIndexConfigPopup(false)}
                notifications={notifications}
                showMakeDefault={true}
            />}
    </>
}