import {useEffect, useRef, useState} from "@wordpress/element";
import {__, sprintf} from "@wordpress/i18n";
import {getNavLinkTo} from "../../../../../../../../../helpers";
import RunDataset from "../../../../../../../../popups/advanced/training/datasets/run";
import {handleError, handleSuccess, handleWarning} from "../../../../../../../../../helpers/notifications";
import {delay} from "../../../../../../../../../../components/chatbots/includes/helpers";
import {GetDatasetMetas, UpdateDatasetMetas} from "../../../../../../../../../rest/dataset-metas";
import KebabMenu from "../../../../../../../../button/kebab-menu";
import {DIM_PROCESS_KEY_PREFIX} from "../../../../../../../../../data/bg-processes";

const DIM_PROCESS_STATUS = DIM_PROCESS_KEY_PREFIX + 'status';
const DIM_PROCESS_PROGRESS = DIM_PROCESS_KEY_PREFIX + 'progress';
const DIM_PROCESS_SUCCESS = DIM_PROCESS_KEY_PREFIX + 'success';

export default function Actions({dataset, deleting, showEditDataset, deleteDataset, notifications, navigate}) {
    const [isDeleting, setIsDeleting] = useState(false);
    const [wantResumeImport, setWantResumeImport] = useState(false);
    const [wantPauseImport, setWantPauseImport] = useState(false);
    const [showRunPopup, setShowRunPopup] = useState(false);
    // States
    const [followingImportProgress, setFollowingImportProgress] = useState(false);
    const [importingProgress, setImportingProgress] = useState(0);
    const [processPaused, setProcessPaused] = useState(false);
    //
    const datasetRef = useRef(null);
    const importProcessPausedRef = useRef(false);

    useEffect(() => {
        // Check import background progress
        checkIfImportIsInProgress();
    }, []);

    useEffect(() => {
        setIsDeleting(deleting.indexOf(dataset.id) !== -1);
    }, [deleting]);

    /**
     * Check if import is in progress
     */
    const checkIfImportIsInProgress = () => {
        const status = dataset.metas?.find(item => item.meta_key === DIM_PROCESS_STATUS)?.meta_value;
        if (status === 'start') {
            // Import process is in progress
            followImportProgress(JSON.parse(JSON.stringify(dataset)));
        }
        // If the process was paused
        if (status === 'pause') {
            setProcessPaused(true);
            // Check progress
            const progress = dataset.metas?.find(item => item.meta_key === DIM_PROCESS_PROGRESS)?.meta_value;
            setImportingProgress(+(progress || 0));
        }
    }

    /**
     * Check import progress
     *
     * @param {object} dataset Dataset
     * @return {Promise<void>}
     */
    const followImportProgress = async (dataset) => {
        let resetProgress = true;
        if (dataset?.id) {
            setFollowingImportProgress(true);
            // Keep the ref
            datasetRef.current = dataset;
            // Get some meta indexes
            const metaIndexes = {
                status: -1,
                progress: -1,
                success: -1,
            };
            if (datasetRef.current.metas?.length) {
                for (let i = 0; i < datasetRef.current.metas.length; i++) {
                    if (datasetRef.current.metas[i].meta_key === DIM_PROCESS_STATUS) {
                        metaIndexes.status = i;
                    } else if (datasetRef.current.metas[i].meta_key === DIM_PROCESS_PROGRESS) {
                        metaIndexes.progress = i;
                    } else if (datasetRef.current.metas[i].meta_key === DIM_PROCESS_SUCCESS) {
                        metaIndexes.success = i;
                    }
                    if (Object.values(metaIndexes).every(item => item !== -1)) {
                        // All metas found
                        break;
                    }
                }
            } else {
                if (!datasetRef.current.metas) {
                    datasetRef.current.metas = [];
                }
            }
            // Check the initial state of the process
            const status = metaIndexes.status !== -1 ? +(dataset.metas[metaIndexes.status].meta_value || 0) : 0;
            const progress = metaIndexes.progress !== -1 ? +(dataset.metas[metaIndexes.progress].meta_value || 0) : 0;
            setImportingProgress(progress);
            // Start check progress
            let prevProgress = progress;
            while (true) {
                try {
                    // If paused, stop the check process
                    if (importProcessPausedRef.current) {
                        resetProgress = false;
                        importProcessPausedRef.current = false;
                        break;
                    }
                    let stopCheckProcess = false;
                    await delay(1000);
                    const res = await GetDatasetMetas(LimbChatbot.rest.url, LimbChatbot.rest.nonce, dataset.id, {
                        meta_key: [DIM_PROCESS_STATUS, DIM_PROCESS_PROGRESS, DIM_PROCESS_SUCCESS],
                    });
                    if (res?.length) {
                        const status = res.find(item => item.meta_key === DIM_PROCESS_STATUS)?.meta_value;
                        const progress = +(res.find(item => item.meta_key === DIM_PROCESS_PROGRESS)?.meta_value || 0);
                        const success = +(res.find(item => item.meta_key === DIM_PROCESS_SUCCESS)?.meta_value || 0);
                        // Update local state of the dataset metas
                        const localDataHelper = {status, progress, success};
                        Object.keys(localDataHelper).forEach(item => {
                            if (metaIndexes[item] !== -1) {
                                datasetRef.current.metas[metaIndexes[item]].meta_value = localDataHelper.item;
                            } else {
                                datasetRef.current.metas.push({
                                    // id: null,
                                    dataset_id: datasetRef.current.id,
                                    meta_key: DIM_PROCESS_KEY_PREFIX + item,
                                    meta_value: localDataHelper.item // No need to copy, they are simple type of variables
                                });
                                // Keep the index state
                                metaIndexes[item] = datasetRef.current.metas.length - 1;
                            }
                        });
                        // Show progress percents
                        if (progress !== prevProgress) {
                            setImportingProgress(progress);
                            prevProgress = progress;
                        }
                        // Status/Progress
                        if (typeof status !== 'undefined') {
                            if (status === 'failed') {
                                handleError({
                                    data: {status, progress, success},
                                    message: "The process failed.",
                                }, notifications.set, {
                                    title: __("The process failed.", 'limb-chatbot'),
                                    description: __("Please try again.", 'limb-chatbot'),
                                });
                                stopCheckProcess = true;
                            } else if (status === 'complete') {
                                handleSuccess(notifications.set, {
                                    title: __("The process is complete.", 'limb-chatbot'),
                                });
                                stopCheckProcess = true;
                            }
                        } else {
                            handleWarning({
                                data: {status, progress, success},
                                message: "Invalid status state response.",
                            }, notifications.set, {
                                title: __("Invalid state of the process.", 'limb-chatbot'),
                                description: __("Please try again.", 'limb-chatbot')
                            });
                            stopCheckProcess = true;
                        }
                        // Show succeed rows info
                        if (stopCheckProcess && success < 100) {
                            setTimeout(() => {
                                handleWarning({
                                    data: {status, progress, success},
                                    message: "Some of the rows import failed."
                                }, notifications.set, {
                                    title: __("Import process", 'limb-chatbot'),
                                    description: sprintf(__("%d%% of import processes failed.", 'limb-chatbot'), 100 - success),
                                });
                            }, 0);
                        }
                    }
                    // Stop a check process
                    if (stopCheckProcess) {
                        break;
                    }
                } catch (e) {
                    handleError(e, notifications.set, {
                        title: __("Import progress check", 'limb-chatbot'),
                        description: e.message ? __(e.message, 'limb-chatbot') : __("Please check your credentials and try again.", 'limb-chatbot'),
                    });
                    break;
                }
            }
            setFollowingImportProgress(false);
        } else {
            datasetRef.current = null;
            handleWarning({
                dataset
            }, notifications.set, {
                title: __("Import process", 'limb-chatbot'),
                description: __("Import process check failed, Q&A data not provided.", 'limb-chatbot'),
            });
        }
        // Reset importing progress
        setTimeout(() => {
            if (resetProgress) {
                setImportingProgress(0);
            }
        }, 200);
    }

    /**
     * Request to pause import
     *
     * @return {Promise<void>}
     */
    const requestToPauseImport = async () => {
        if (datasetRef.current?.id) {
            setWantPauseImport(true);
            try {
                await UpdateDatasetMetas(LimbChatbot.rest.url, LimbChatbot.rest.nonce, datasetRef.current.id, [
                    {
                        meta_key: DIM_PROCESS_STATUS,
                        meta_value: "pause"
                    }
                ]);
                importProcessPausedRef.current = true;
                setProcessPaused(true);

                handleSuccess(notifications.set, {
                    title: __("The importing process has been paused.", 'limb-chatbot'),
                });
            } catch (e) {
                handleError(e, notifications.set, {
                    title: __("Failed to pause import process.", 'limb-chatbot'),
                    description: e.message ? __(e.message, 'limb-chatbot') : __("Please check your credentials and try again.", 'limb-chatbot'),
                });
            }
            setWantPauseImport(false);
        } else {
            handleWarning({
                dataset: datasetRef.current,
            }, notifications.set, {
                title: __("Pause import process", 'limb-chatbot'),
                description: __("Can't pause the process, Q&A data not provided.", 'limb-chatbot'),
            });
        }
    }

    /**
     * Import file
     *
     * @return {Promise<void>}
     */
    const requestToResumeImport = async () => {
        try {
            setWantResumeImport(true);
            const res = await UpdateDatasetMetas(LimbChatbot.rest.url, LimbChatbot.rest.nonce, dataset.id, [
                {
                    meta_key: DIM_PROCESS_STATUS,
                    meta_value: "start"
                }
            ]);
            setWantResumeImport(false);
            setProcessPaused(false);
            // Check import progress
            await followImportProgress(datasetRef.current?.id ? datasetRef.current : dataset);
        } catch (e) {
            handleError(e, notifications.set, {
                title: __("Failed to resume the process.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Something went wrong.", 'limb-chatbot'),
            });
        }
    }

    /**
     * Toggle run popup
     *
     * @param {boolean} autoClose After run request close the edit screen also
     */
    const toggleRunPopup = (autoClose = false) => {
        if (showRunPopup) {
            if (autoClose === true) {
                navigate(getNavLinkTo('training', 'my-models'));
            }
        }
        setShowRunPopup(!showRunPopup);
    }

    const deleteDisabled = isDeleting || followingImportProgress || wantResumeImport;

    const actions = [
        {
            label: __("Delete", 'limb-chatbot'),
            icon: 'delete',
            onClick: () => {
                if (!deleteDisabled) {
                    deleteDataset(dataset);
                }
            },
            disabled: deleteDisabled,
            loading: isDeleting
        },
    ];

    if (followingImportProgress || processPaused) {
        actions.unshift({
            label: processPaused ? __("Resume", 'limb-chatbot') : __("Pause", 'limb-chatbot'),
            icon: 'sync',
            onClick: () => {
                if (!wantResumeImport) {
                    if (processPaused) {
                        requestToResumeImport();
                    } else if (!wantPauseImport) {
                        requestToPauseImport();
                    }
                }
            },
            disabled: wantResumeImport || wantPauseImport,
            beforeLabel: <>
                {wantResumeImport ?
                    <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>
                    :
                    !processPaused ?
                        <div className='lbaic-settings-button-save-process'>
                            <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'
                                style={{
                                    '--lbaic-settings-button-loading-circle-progress': importingProgress
                                }}>
                                <use href='#lbaic-settings-circle'/>
                            </svg>
                            <svg className='lbaic-settings-button-i lbaic-settings-button-save-process-i'
                                 xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24'>
                                <use href='#lbaic-settings-pause'/>
                            </svg>
                        </div>
                        :
                        <></>}
                <span className='lbaic-settings-button-process-progress'>{importingProgress}%</span>
            </>
        });
    } else {
        actions.unshift(
            {
                label: __("Run", 'limb-chatbot'),
                icon: 'run',
                onClick: () => {
                    toggleRunPopup();
                },
            },
            {
                label: __("Edit", 'limb-chatbot'),
                icon: 'edit',
                onClick: () => {
                    showEditDataset(dataset);
                },
            }
        );
    }

    return <>
        <div className='lbaic-settings-table-card-actions'>
            <KebabMenu actions={actions}/>
        </div>
        {showRunPopup &&
            <RunDataset datasetId={dataset?.id} close={toggleRunPopup} notifications={notifications}/>}
    </>
}