import {useEffect, useRef, useState} from "@wordpress/element";
import {__, _n, sprintf} from "@wordpress/i18n";
import PopupContainer from "../../../../../popups/container";
import FileUpload from "../../../../file-upload";
import FileRow from "./components/file-row";
import Pagination from "../../../../../sections/pagination";
import Badge from "../../../../badge";
import {handleError, handleSuccess, handleWarning} from "../../../../../../helpers/notifications";
import {GetFiles, UploadFiles, DeleteFile} from "../../../../../../rest/files";
import confirm from "../../../../../../helpers/confirm";

const FILES_DEFAULT_PARAMS = {
    perPage: 10,
    orderBy: 'created_at',
    order: 'desc',
};

export default function AddNewFiles({
                                        supportedTypes,
                                        fileMaxSize,
                                        aiProviderId,
                                        configId,
                                        onDone,
                                        onClose,
                                        addNotification
                                    }) {
    const [loading, setLoading] = useState(1);
    const [isDataFetched, setIsDataFetched] = useState(false);
    const [files, setFiles] = useState([]);
    const [pagination, setPagination] = useState({
        page: 1,
        perPage: FILES_DEFAULT_PARAMS.perPage,
        total: 0,
    });
    const [initialUpload, setInitialUpload] = useState(false);
    const [deleting, setDeleting] = useState([]);
    const [showingSuccess, setShowingSuccess] = useState([]);
    const [newFiles, setNewFiles] = useState([]);
    const deletedFilesUuidsRef = useRef([]);
    const successTimeoutsRef = useRef({});

    const doingSomething = loading > 0 || initialUpload || deleting.length > 0;

    useEffect(() => {
        getFiles();
    }, [aiProviderId]);


    // Cleanup timeouts on unmount
    useEffect(() => {
        return () => {
            Object.values(successTimeoutsRef.current).forEach(timeout => {
                clearTimeout(timeout);
            });
        };
    }, []);

    /**
     * Get files
     *
     * @param {object} params Query params
     * @param {boolean} reset Reset or append
     */
    const getFiles = async (params = {}, reset = true) => {
        setLoading(prev => prev + 1);
        // Default params
        const reqParams = {
            page: params?.page || 1,
            per_page: params?.perPage || FILES_DEFAULT_PARAMS.perPage,
            orderby: FILES_DEFAULT_PARAMS.orderBy,
            order: FILES_DEFAULT_PARAMS.order,
        };
        // Add search param
        if (params?.search) {
            reqParams.search = params.search;
        }
        // Filter files by AI provider
        if (aiProviderId) {
            reqParams.related_to = aiProviderId;
        }
        try {
            // Get files
            const res = await GetFiles(LimbChatbot.rest.url, LimbChatbot.rest.nonce, reqParams);
            // Prepare options
            const items = res.items?.length ? res.items : [];
            // Update state
            if (reset) {
                setFiles([...items]);
            } else {
                setFiles(prevState => [...prevState, ...items]);
            }
            // Pagination info
            setPagination(prevState => ({
                ...prevState,
                page: reqParams.page,
                total: res.total,
            }));
        } catch (e) {
            handleError(e, addNotification, {
                title: __("Failed to get files.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Please check and try again.", 'limb-chatbot'),
            });
        }
        setIsDataFetched(true);
        setLoading(prev => prev - 2);
    }

    /**
     * Handle file deletion
     *
     * @param {string} uuid File UUID to delete
     */
    const handleDelete = async (uuid) => {
        if (!await confirm(__("Are you sure you want to delete the file?", 'limb-chatbot'))) {
            return;
        }

        // Add to deleting state
        setDeleting(prevState => [...prevState, uuid]);

        try {
            // Delete file
            await DeleteFile(LimbChatbot.rest.url, LimbChatbot.rest.nonce, uuid);

            // Show success notification
            handleSuccess(addNotification, {
                title: __("File has been deleted.", 'limb-chatbot'),
            });

            // Remove from newFiles state
            setNewFiles(prevState => prevState.filter(file => file.uuid !== uuid));
            deletedFilesUuidsRef.current.push(uuid);

            // Determine which page to fetch
            // If this was the last file on the page and we're not on page 1, go to previous page
            const targetPage = files.length === 1 && pagination.page > 1
                ? pagination.page - 1
                : pagination.page;

            // Refresh files list
            await getFiles({
                page: targetPage,
                perPage: pagination.perPage,
            });
        } catch (e) {
            handleError(e, addNotification, {
                title: __("Failed to delete file.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Please check and try again.", 'limb-chatbot'),
            });
        }

        // Remove from deleting state
        setDeleting(prevState => prevState.filter(id => id !== uuid));
    }

    /**
     * New file(s) attached
     *
     * @param {File[]} files New files
     */
    const handleFilesAttach = async (files) => {
        // Check and filter files
        let filteredFiles;
        if (files?.length) {
            try {
                filteredFiles = Array.from(files).filter(file => file.size);
                if (filteredFiles.length) {
                    if (filteredFiles.length !== files.length) {
                        // Some files have no size
                        const invalidFiles = Array.from(files).filter(file => !file.size);
                        handleWarning({
                            message: "Some files don't have a size.",
                            data: {
                                files: invalidFiles
                            },
                        }, addNotification, {
                            title: _n("Invalid file attached.", "Invalid files attached.", invalidFiles.length, 'limb-chatbot'),
                            description: sprintf(_n("This file will be skipped: %s.", "These files will be skipped %s.", invalidFiles.length, 'limb-chatbot'), invalidFiles.map(file => file.name).join(', ')),
                        });
                    }
                } else {
                    // There is no valid file
                    handleError({
                        message: "File(s) don't have a size.",
                        data: {
                            files
                        },
                    }, addNotification, {
                        title: _n("Invalid file attached.", "Invalid files attached.", files.length, 'limb-chatbot'),
                        description: __("Please check and try again.", 'limb-chatbot'),
                    });
                }
            } catch (e) {
                handleError(e);
            }
        }

        if (filteredFiles?.length) {
            // Upload files
            setInitialUpload(true);
            try {
                const res = await UploadFiles(LimbChatbot.rest.url, LimbChatbot.rest.nonce, filteredFiles);
                if (res.items?.length) {
                    setNewFiles(prevState => [...prevState, ...res.items]);
                    // Show notification
                    handleSuccess(addNotification, {
                        title: _n("File has been uploaded.", "Files have been uploaded.", filteredFiles.length, 'limb-chatbot')
                    });
                    // Update files list
                    await getFiles();
                } else {
                    handleError({
                        message: "Failed to upload file(s).",
                        data: {
                            files: filteredFiles,
                            response: res,
                        },
                    }, addNotification, {
                        title: _n("Failed to upload file.", "Failed to upload files.", filteredFiles.length, 'limb-chatbot'),
                        description: __("Something went wrong.", 'limb-chatbot'), // TODO check errors - res.errors
                    });
                }
            } catch (e) {
                handleError(e, addNotification, {
                    title: _n("Failed to upload file.", "Failed to upload files.", filteredFiles.length, 'limb-chatbot'),
                    description: e.message ? __(e.message, 'limb-chatbot') : __("Please check and try again.", 'limb-chatbot'),
                });
            }
            setInitialUpload(false);
        }
    }


    const handleClose = () => {
        if (!doingSomething) {
            onClose();
        }
    }

    const handleDone = () => {
        if (!doingSomething) {
            // Files are now used directly after upload - no need to filter by external status
            onDone(newFiles, deletedFilesUuidsRef.current);
        }
    }

    /**
     * Navigate to specific page
     *
     * @param {number} page Page number
     */
    const goToPage = async (page) => {
        if (!doingSomething) {
            await getFiles({
                page: page,
                perPage: pagination.perPage,
            });
        }
    }

    return (
        <PopupContainer
            title={__("Files", 'limb-chatbot')}
            description={__("Add a new file or select from the existing files.", 'limb-chatbot')}
            close={handleClose}
            loading={loading > 0}
            showLoadingContainer={loading > 0 && !isDataFetched}
            bodyClassName='lbaic-settings-e-anf-popup-body'
            footer={<>
                <button
                    className={`lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-40 lbaic-settings-button-secondary${doingSomething ? ' lbaic-settings-button-disabled' : ''}`}
                    onClick={handleClose}
                >
                    <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${doingSomething ? ' lbaic-settings-button-disabled' : ''}`}
                    onClick={handleDone}
                >
                    <span className='lbaic-settings-button-label'>{__("Done", 'limb-chatbot')}</span>
                </button>
            </>}
        >
            {files?.length > 0 &&
                <div className='lbaic-settings-e-anf-table-wrapper lbaic-settings-scroll-hidden'>
                    <div className="lbaic-settings-scroll-x">
                        <table className='lbaic-settings-e-anf-table'>
                            <thead className='lbaic-settings-e-anf-table-header'>
                            <tr className='lbaic-settings-e-anf-table-header-in'>
                                <th className='lbaic-settings-e-anf-table-header-item lbaic-settings-e-anf-table-header-file'>
                                    <span
                                        className='lbaic-settings-e-anf-table-header-label'>{__("File", 'limb-chatbot')}</span>
                                </th>
                                <th className='lbaic-settings-e-anf-table-header-item'>
                                    <span
                                        className='lbaic-settings-e-anf-table-header-label'>{__("Size", 'limb-chatbot')}</span>
                                </th>
                                <th colSpan='2' className='lbaic-settings-e-anf-table-header-item'>
                                    <span
                                        className='lbaic-settings-e-anf-table-header-label'>{__("Uploaded", 'limb-chatbot')}</span>
                                </th>
                            </tr>
                            </thead>
                            <tbody className='lbaic-settings-e-anf-table-body'>
                            {files.map(file => {
                                const deletingTheFile = deleting.includes(file.uuid);
                                const showingSuccessForFile = showingSuccess.includes(file.uuid);

                                return (
                                    <FileRow
                                        key={file.uuid}
                                        file={file}
                                        actions={(
                                            <>
                                                {showingSuccessForFile ? (
                                                    <Badge icon='check'
                                                           className='lbaic-settings-badge-green lbaic-settings-badge-icon-only'
                                                           custom/>
                                                ) : (
                                                    <button
                                                        className={`lbaic-settings-e-anf-table-body-remove-in lbaic-settings-button-reset${deleting.length ? ' lbaic-settings-button-disabled' : ''}`}
                                                        onClick={() => handleDelete(file.uuid)}
                                                    >
                                                        {deletingTheFile ?
                                                            <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'>
                                                                <use href='#lbaic-settings-circle'/>
                                                            </svg>
                                                            :
                                                            <svg className='lbaic-settings-e-anf-table-body-remove-i'
                                                                 xmlns='http://www.w3.org/2000/svg' fill='none'
                                                                 viewBox='0 0 16 16'>
                                                                <use href='#lbaic-settings-delete'/>
                                                            </svg>}
                                                    </button>
                                                )}
                                            </>
                                        )}
                                    />
                                );
                            })}
                            </tbody>
                        </table>
                    </div>
                </div>}
            {/*Pagination*/}
            <Pagination
                page={pagination.page}
                perPage={pagination.perPage}
                total={pagination.total}
                goTo={goToPage}
                loading={doingSomething}
            />
            <div className='lbaic-settings-divider-gap-end lbaic-settings-e-anf-divider-gap-end'/>
            <FileUpload
                label={__("Upload a file", 'limb-chatbot')}
                supportedTypes={supportedTypes}
                fileMaxSize={fileMaxSize}
                added={handleFilesAttach}
                multiple
                disabled={doingSomething}
                addNotification={addNotification}
            />
        </PopupContainer>
    );
}