import {useEffect, useRef, useState} from "@wordpress/element";
import {__} from "@wordpress/i18n";
import {AI_PROVIDERS} from "../../../../../constants/chatbot/ai";
import PopupContainer from "../../../../popups/container";
import {handleError, handleSuccess} from "../../../../../helpers/notifications";
import {getInitialData, getSettingsDataToUpdate, setSettingsDataToUpdate, setupSettings} from "../../../../../helpers";
import {GetSetting, GetSettings, UpdateSettings} from "../../../../../rest/settings";
import Dropdown from "../../../../fields/dropdown";
import Model from "../../../../fields/specific-fields/model";
import Config from "../../../../fields/specific-fields/config";
import {GetDefaultSettings, GetUtilitySettings} from "../../../../../helpers/rest";
import AddNewConfig from "../../../../popups/ai-providers/models/add-edit-config";

const COPILOT_UTILITY_KEY_PREFIX = 'lbaic.utilities.copilot';
const COPILOT_UTILITY_STORAGE_KEY_PREFIX = 'lbaic.utilities.copilot';

export default function Settings({saved, close, notifications}) {
    // Actions state
    const [loading, setLoading] = useState(1);
    const [saving, setSaving] = useState(false);
    const [isDataFetched, setIsDataFetched] = useState(false);
    const [isDefaultsChecked, setIsDefaultsChecked] = useState(false);
    const [isModelsFetched, setIsModelsFetched] = useState(false);
    const [isConfigsFetched, setIsConfigsFetched] = useState(false);
    const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
    const [showAddNewConfigPopup, setShowAddNewConfigPopup] = useState(false);
    // Settings
    const settings = {
        'ai_provider_id': useState(''),
        'ai_model_id': useState(''),
        'config_id': useState(''),
    };
    // Initial data
    const initialData = useRef(getInitialData(settings));

    const selectedModelRef = useRef(null);
    const selectedConfigRef = useRef(null);
    const fieldConfigRef = useRef(null);

    const isDataReady = isDataFetched && isDefaultsChecked;
    const saveButtonDisabled = loading > 0 || saving || !hasUnsavedChanges;

    useEffect(() => {
        // Fetch data
        fetchData();
    }, []);

    useEffect(() => {
        if (isDataFetched) {
            checkDefaultValues();
        }
    }, [isDataFetched]);

    useEffect(() => {
        if (isDataReady) {
            const dataToSave = setSettingsDataToUpdate(settings, initialData.current, `${COPILOT_UTILITY_KEY_PREFIX}.`)
            if (hasUnsavedChanges !== dataToSave?.length > 0) {
                setHasUnsavedChanges(dataToSave?.length > 0);
            }
        }
    }, [isDataReady, settings]);

    /**
     * Get saved settings
     */
    const fetchData = async () => {
        setLoading(prev => prev + 1);
        try {
            const keyPrefix = COPILOT_UTILITY_KEY_PREFIX + '.';
            const res = await GetSettings(LimbChatbot.rest.url, LimbChatbot.rest.nonce, {
                key: Object.keys(settings).map(key => keyPrefix + key),
            });
            setupSettings(settings, COPILOT_UTILITY_STORAGE_KEY_PREFIX, keyPrefix, res, initialData);
        } catch (e) {
            handleError(e, notifications.set, {
                title: __("Failed to retrieve data.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Please check your connection and try again.", 'limb-chatbot'),
            });
        }
        setLoading(prev => prev - 1);
        setIsDataFetched(true);
    }

    /**
     * Check default settings
     */
    const checkDefaultValues = async () => {
        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],
                    'copilot',
                    settingsKeys
                )
                :
                await GetDefaultSettings(
                    'copilot',
                    settingsKeys
                );
            // Setup default values
            settingsKeys.forEach(item => {
                settings[item.key][1](defaults[item.key]);
            });
        }
        setLoading(prev => prev - 2); // Since the loading from the very beginning is 1
        setIsDefaultsChecked(true);
    }

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

    const save = async () => {
        if (saveButtonDisabled) {
            return;
        }
        setSaving(true);
        const data = LimbChatbot.Hooks.applyFilters('lbaic.admin.page.settings.ai-provider.utility.copilot.dataToUpdate', [
            ...getSettingsDataToUpdate(settings, initialData.current, `${COPILOT_UTILITY_KEY_PREFIX}.`),
        ]);
        if (data.length) {
            try {
                UpdateSettings(LimbChatbot.rest.url, LimbChatbot.rest.nonce, data);
                // Make the state as initial
                initialData.current = getInitialData(settings);
                handleSuccess(notifications?.set, {
                    title: __("Data saved successfully.", 'limb-chatbot'),
                });
                // Saved
                saved({
                    model: selectedModelRef.current,
                    config: selectedConfigRef.current
                });
                close();
            } catch (e) {
                handleError(e, notifications?.set, {
                    title: __("Failed to save changes.", 'limb-chatbot'),
                    description: e.message ? __(e.message, 'limb-chatbot') : __("Please try again.", 'limb-chatbot'),
                });
            }
        }
        setSaving(false);
    }

    const popupLoading = loading > 0 || saving;
    const showLoadingContainer = loading > 0 && (!isDataReady || !isModelsFetched || !isConfigsFetched);

    return <PopupContainer
        title={__("Copilot settings", 'limb-chatbot')}
        description=""
        close={close}
        loading={popupLoading}
        showLoadingContainer={showLoadingContainer}
        footer={<>
            <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>
            <button
                className={`lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-40 lbaic-settings-button-primary${saveButtonDisabled ? ' lbaic-settings-button-disabled' : ''}`}
                onClick={save}>
                {saving &&
                    <svg className='lbaic-settings-button-i lbaic-settings-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'>{__("Save", 'limb-chatbot')}</span>
            </button>
        </>}>
        <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={AI_PROVIDERS} placeholder={__("AI provider", 'limb-chatbot')}/>
            </div>
        </div>
        <div className='lbaic-settings-column'>
            <div className="lbaic-settings-column-in">
                <Model aiProviderId={settings['ai_provider_id'][0]}
                       isAIProviderRequired={true}
                       isDataFetched={isDataFetched}
                       isDefaultsChecked={isDefaultsChecked}
                       modelId={settings['ai_model_id'][0]}
                       setModelId={settings['ai_model_id'][1]}
                       endpoints={['chat_completions']}
                       modelSelected={model => selectedModelRef.current = model}
                       setFetched={setIsModelsFetched}
                       setLoading={setLoading}
                       notifications={notifications}/>
            </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={isDefaultsChecked}
                    configId={settings['config_id'][0]}
                    setConfigId={settings['config_id'][1]}
                    getReqParams={{
                        mask: false,
                    }}
                    configSelected={config => selectedConfigRef.current = config}
                    setFetched={setIsConfigsFetched}
                    fieldProps={{
                        addNew: () => setShowAddNewConfigPopup(true),
                    }}
                    setLoading={setLoading}
                    notifications={notifications}
                />
            </div>
        </div>
        {showAddNewConfigPopup && (
            <AddNewConfig
                aiProviderId={settings['ai_provider_id'][0]}
                added={newConfigAdded}
                close={() => setShowAddNewConfigPopup(false)}
                notifications={notifications} showMakeDefault={true}
            />
        )}
    </PopupContainer>
}