import {useEffect, useRef, useState} from "@wordpress/element";
import {__} from "@wordpress/i18n";
import {delay} from "../../../../../../../../../../components/chatbots/includes/helpers";
import {handleError, handleSuccess, handleWarning} from "../../../../../../../../../helpers/notifications";
import {GetModelMetas, UpdateModelMetas} from "../../../../../../../../../rest/model-metas";
import {FTFF_PROCESS_KEY_PREFIX} from "../../../../../../../../../data/bg-processes";

const FTFF_PROCESS_STATUS = FTFF_PROCESS_KEY_PREFIX + 'status';
const FTFF_PROCESS_PROGRESS = FTFF_PROCESS_KEY_PREFIX + 'progress';
const FTFF_PROCESS_SUCCESS = FTFF_PROCESS_KEY_PREFIX + 'success';

export default function Actions({model, deleting, deleteModel, notifications}) {
    const [isDeleting, setIsDeleting] = useState(false);
    const [wantResumeFileFormatting, setWantResumeFileFormatting] = useState(false);
    const [wantPauseFileFormatting, setWantPauseFileFormatting] = useState(false);
    // States
    const [followingFileFormattingProgress, setFollowingFileFormattingProgress] = useState(false);
    const [fileFormattingProgress, setFileFormattingProgress] = useState(0);
    const [fileFormattingProcessPaused, setFileFormattingProcessPaused] = useState(false);
    //
    const modelRef = useRef(null);
    const fileFormattingProcessPausedRef = useRef(false);

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

    useEffect(() => {
        if (model?.id) {
            // Check file formatting background progress
            checkIfFileFormattingIsInProgress(model);
        }
    }, [model]);

    /**
     * Check if file formatting is in progress
     */
    const checkIfFileFormattingIsInProgress = (model) => {
        const status = model.metas?.find(item => item.meta_key === FTFF_PROCESS_STATUS)?.meta_value;
        if (status === 'start') {
            // File formatting process is in progress
            followFileFormattingProgress(JSON.parse(JSON.stringify(model)));
        }
        // If the process was paused
        if (status === 'pause') {
            setFileFormattingProcessPaused(true);
            // Check progress
            const progress = model.metas?.find(item => item.meta_key === FTFF_PROCESS_PROGRESS)?.meta_value;
            setFileFormattingProgress(+(progress || 0));
        }
    }

    /**
     * Check file formatting progress
     *
     * @param {object} model Model
     * @return {Promise<void>}
     */
    const followFileFormattingProgress = async (model) => {
        let resetProgress = true;
        if (model?.id) {
            setFollowingFileFormattingProgress(true);
            // Keep the ref
            modelRef.current = model;
            // Get some meta indexes
            const metaIndexes = {
                status: -1,
                progress: -1,
                success: -1,
            };
            if (modelRef.current.metas?.length) {
                for (let i = 0; i < modelRef.current.metas.length; i++) {
                    if (modelRef.current.metas[i].meta_key === FTFF_PROCESS_STATUS) {
                        metaIndexes.status = i;
                    } else if (modelRef.current.metas[i].meta_key === FTFF_PROCESS_PROGRESS) {
                        metaIndexes.progress = i;
                    } else if (modelRef.current.metas[i].meta_key === FTFF_PROCESS_SUCCESS) {
                        metaIndexes.success = i;
                    }
                    if (Object.values(metaIndexes).every(item => item !== -1)) {
                        // All metas found
                        break;
                    }
                }
            } else {
                if (!modelRef.current.metas) {
                    modelRef.current.metas = [];
                }
            }
            // Check the initial state of the process
            const status = metaIndexes.status !== -1 ? +(model.metas[metaIndexes.status].meta_value || 0) : 0;
            const progress = metaIndexes.progress !== -1 ? +(model.metas[metaIndexes.progress].meta_value || 0) : 0;
            setFileFormattingProgress(progress);
            // Start check progress
            let prevProgress = progress;
            while (true) {
                try {
                    // If paused, stop the check process
                    if (fileFormattingProcessPausedRef.current) {
                        resetProgress = false;
                        fileFormattingProcessPausedRef.current = false;
                        break;
                    }
                    let stopCheckProcess = false;
                    await delay(3000);
                    const res = await GetModelMetas(LimbChatbot.rest.url, LimbChatbot.rest.nonce, model.id, {
                        meta_key: [FTFF_PROCESS_STATUS, FTFF_PROCESS_PROGRESS, FTFF_PROCESS_SUCCESS],
                    });
                    if (res?.length) {
                        const status = res.find(item => item.meta_key === FTFF_PROCESS_STATUS)?.meta_value;
                        const progress = +(res.find(item => item.meta_key === FTFF_PROCESS_PROGRESS)?.meta_value || 0);
                        const success = +(res.find(item => item.meta_key === FTFF_PROCESS_SUCCESS)?.meta_value || 0);
                        // Update local state of the model metas
                        const localDataHelper = {status, progress, success};
                        Object.keys(localDataHelper).forEach(item => {
                            if (metaIndexes[item] !== -1) {
                                modelRef.current.metas[metaIndexes[item]].meta_value = localDataHelper.item;
                            } else {
                                modelRef.current.metas.push({
                                    // id: null,
                                    model_id: modelRef.current.id,
                                    meta_key: FTFF_PROCESS_KEY_PREFIX + item,
                                    meta_value: localDataHelper.item // No need to copy, they are simple type of variables
                                });
                                // Keep the index state
                                metaIndexes[item] = modelRef.current.metas.length - 1;
                            }
                        });
                        // Show progress percents
                        if (progress !== prevProgress) {
                            setFileFormattingProgress(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 file formatting failed."
                                }, notifications.set, {
                                    title: __("File formatting process", 'limb-chatbot'),
                                    description: sprintf(__("%d%% of file formatting processes failed.", 'limb-chatbot'), 100 - success),
                                });
                            }, 0);
                        }
                    }
                    // Stop a check process
                    if (stopCheckProcess) {
                        break;
                    }
                } catch (e) {
                    handleError(e, notifications.set, {
                        title: __("File formatting progress check", 'limb-chatbot'),
                        description: e.message ? __(e.message, 'limb-chatbot') : __("Please check your credentials and try again.", 'limb-chatbot'),
                    });
                    break;
                }
            }
            setFollowingFileFormattingProgress(false);
        } else {
            modelRef.current = null;
            handleWarning({
                model
            }, notifications.set, {
                title: __("File formatting process", 'limb-chatbot'),
                description: __("File formatting process check failed, model data not provided.", 'limb-chatbot'),
            });
        }
        // Reset file formatting progress
        setTimeout(() => {
            if (resetProgress) {
                setFileFormattingProgress(0);
            }
        }, 200);
    }

    /**
     * Request to pause file formatting
     *
     * @return {Promise<void>}
     */
    const requestToPauseFileFormatting = async () => {
        if (modelRef.current?.id) {
            setWantPauseFileFormatting(true);
            try {
                await UpdateModelMetas(LimbChatbot.rest.url, LimbChatbot.rest.nonce, modelRef.current.id, [
                    {
                        meta_key: FTFF_PROCESS_STATUS,
                        meta_value: "pause"
                    }
                ]);
                fileFormattingProcessPausedRef.current = true;
                setFileFormattingProcessPaused(true);

                handleSuccess(notifications.set, {
                    title: __("The file formatting process has been paused.", 'limb-chatbot'),
                });
            } catch (e) {
                handleError(e, notifications.set, {
                    title: __("Failed to pause file formatting process.", 'limb-chatbot'),
                    description: e.message ? __(e.message, 'limb-chatbot') : __("Please check your credentials and try again.", 'limb-chatbot'),
                });
            }
            setWantPauseFileFormatting(false);
        } else {
            handleWarning({
                model: modelRef.current,
            }, notifications.set, {
                title: __("Pause file formatting process", 'limb-chatbot'),
                description: __("Can't pause the process, model data not provided.", 'limb-chatbot'),
            });
        }
    }

    /**
     * Resume a file formatting process
     *
     * @return {Promise<void>}
     */
    const requestToResumeFileFormatting = async () => {
        try {
            setWantResumeFileFormatting(true);
            const res = await UpdateModelMetas(LimbChatbot.rest.url, LimbChatbot.rest.nonce, model.id, [
                {
                    meta_key: FTFF_PROCESS_STATUS,
                    meta_value: "start"
                }
            ]);
            setWantResumeFileFormatting(false);
            setFileFormattingProcessPaused(false);
            // Check file formatting progress
            await followFileFormattingProgress(modelRef.current?.id ? modelRef.current : model);
        } 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'),
            });
        }
    }

    return <div className='lbaic-settings-table-card-actions'>
        {followingFileFormattingProgress || fileFormattingProcessPaused ?
            <>
                <button
                    onClick={() => !wantResumeFileFormatting ? (fileFormattingProcessPaused ? requestToResumeFileFormatting() : !wantPauseFileFormatting ? requestToPauseFileFormatting() : null) : null}
                    className={`lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-32 lbaic-settings-button-primary${wantResumeFileFormatting || wantPauseFileFormatting ? ' lbaic-settings-button-disabled' : ''}`}>
                    {wantResumeFileFormatting ?
                        <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>
                        :
                        !fileFormattingProcessPaused ?
                            <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': fileFormattingProgress
                                    }}>
                                    <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'>{fileFormattingProgress}%</span>
                    <span
                        className='lbaic-settings-button-label'>{fileFormattingProcessPaused ? __("Resume", 'limb-chatbot') : __("Pause", 'limb-chatbot')}</span>
                </button>
            </>
            :
            null}
        <button
            onClick={() => !isDeleting && !followingFileFormattingProgress && !wantResumeFileFormatting && deleteModel(model)}
            className={`lbaic-settings-table-card-actions-in lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-32 lbaic-settings-button-minimal${isDeleting || followingFileFormattingProgress || wantResumeFileFormatting ? ' lbaic-settings-button-disabled' : ''}`}>
            <svg className='lbaic-settings-button-i' xmlns='http://www.w3.org/2000/svg' fill='none'
                 viewBox='0 0 24 24'>
                <use href='#lbaic-settings-delete'/>
            </svg>
        </button>
    </div>
}