import {useCallback, useEffect, useState} from "@wordpress/element";
import {__} from "@wordpress/i18n";
import {
    DATASET_TYPE_FINE_TUNING,
    DeleteDataset,
    GetDataset,
    GetDatasets,
    UploadDatasetFile
} from "../../../../../../../rest/datasets";
import {handleError, handleSuccess, handleWarning} from "../../../../../../../helpers/notifications";
import {handlePaginationAfterDeletion} from "../../../../../../../helpers";
import AddEdit from "./add-edit";
import Table from "../../../../../../sections/table";
import Empty from "../../../../containers/content/empty";
import Checkbox from "../../../../../../fields/checkbox";
import {getFormatedDate} from "../../../../../../../../helpers";
import ContentLoading from "../../../../containers/content/loading";
import ContentBodyInner from "../../../../containers/content/body-inner";
import Container from "../../../../containers/content/container";
import ContentFooterLayout from "../../../../containers/content/footer/_components/layout";
import confirm from "../../../../../../../helpers/confirm";
import ImportFiles from "./import-files";
import Actions from "./table/actions";
import {getNavLinkTo} from "../../../../../../../helpers";
import Chip from "../../../../../../fields/chip";
import {NOTIF_QUICK_AUTOCLOSE_TIMEOUT} from "../../../../../../containers/notification-layout";

export default function Datasets({notifications, navigate}) {
    // Actions states
    const [isDataFetched, setIsDataFetched] = useState(false);
    const [loading, setLoading] = useState(0);
    const [deleting, setDeleting] = useState([]);
    const [addingEditing, setAddingEditing] = useState(false);
    const [showImportFilesPopup, setShowImportFilesPopup] = useState(false);
    // Data
    const [datasetsPagination, setDatasetsPagination] = useState({
        page: 1,
        perPage: LimbChatbot.screen_options?.lbaic_items_per_page || 10,
        total: 0
    });
    const [datasetsOrder, setDatasetsOrder] = useState({
        orderBy: 'id',
        order: 'asc',
    });
    const [datasets, setDatasets] = useState([]);
    const [selectedDatasets, setSelectedDatasets] = useState([]);
    const [selectedDataset, setSelectedDataset] = useState(null);

    /**
     * Auto close notifications
     */
    const autoCloseNotifications = useCallback((timeout = NOTIF_AUTOCLOSE_TIMEOUT) => {
        notifications.set(prevState => prevState.map(item => ({
            ...item,
            autoClose: true,
            timeout,
        })));
    }, [notifications]);

    useEffect(() => {
        // Detect action
        const searchParams = new URLSearchParams(window.location.search);
        const action = searchParams.get('action');
        if (action === 'add') {
            setSelectedDataset(null);
            setAddingEditing(true);
        } else if (action === 'edit') {
            const datasetId = searchParams.get('dataset_id');
            if (datasetId) {
                showDatasetEditForm(datasetId);
            }
        }
        // Hide all permanent notifications
        autoCloseNotifications(NOTIF_QUICK_AUTOCLOSE_TIMEOUT);

        return () => {
            // Hide all permanent notifications
            autoCloseNotifications(NOTIF_QUICK_AUTOCLOSE_TIMEOUT)
        }
    }, []);

    useEffect(() => {
        // Fetch datasets
        fetchDatasets(1, datasetsPagination.perPage, datasetsOrder);
    }, [datasetsOrder]);

    const isAllSelected = datasets.length > 0 && datasets.every(item => selectedDatasets.includes(item.id));
    const isPartiallySelected = !isAllSelected && datasets.some(item => selectedDatasets.includes(item.id));

    /**
     * Show a dataset edit form
     *
     * @param {number} datasetId Dataset id
     * @return {Promise<void>}
     */
    const showDatasetEditForm = async (datasetId) => {
        if (datasetId) {
            setLoading(prev => prev + 1);
            try {
                const res = await GetDataset(LimbChatbot.rest.url, LimbChatbot.rest.nonce, datasetId, {
                    include: ['metas'],
                });
                if (res?.dataset?.id) {
                    setAddingEditing(true);
                    setSelectedDataset(res.dataset);
                    setLoading(prev => prev - 1);

                    return;
                } else {
                    handleError(false, notifications.set, {
                        title: __("Failed to get Q&A data.", 'limb-chatbot'),
                        description: __("Something went wrong.", 'limb-chatbot'),
                    });
                }
            } catch (e) {
                handleError(e, notifications.set, {
                    title: __("Failed to get Q&A data.", 'limb-chatbot'),
                    description: e.message ? __(e.message, 'limb-chatbot') : __("Please check your connection and try again.", 'limb-chatbot'),
                });
            }
            setLoading(prev => prev - 1);
        }
        // Dataset isn't found, maybe :)
        navigate(getNavLinkTo('training', 'qas'));
    }

    /**
     * Get datasets
     */
    const fetchDatasets = (page, perPage, params = {}) => {
        setLoading(prev => prev + 1);
        GetDatasets(LimbChatbot.rest.url, LimbChatbot.rest.nonce, {
            page: page,
            per_page: perPage,
            orderby: params.orderBy || 'id',
            order: params.order || 'asc',
            type: DATASET_TYPE_FINE_TUNING,
            include: ['metas'],
        }).then(res => {
            if (res.items?.length) {
                setDatasets([...res.items]);
            } else {
                setDatasets([]);
            }
            // Pagination state
            setDatasetsPagination(prevState => ({
                ...prevState,
                page: page,
                total: +res.total,
            }));

            setIsDataFetched(true);
            setLoading(prev => prev - 1);
        }).catch(e => {
            setDatasets([]);
            setIsDataFetched(true);
            setLoading(prev => prev - 1);
            handleError(e, notifications.set, {
                title: __("Failed to retrieve datasets data.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Please check your connection and try again.", 'limb-chatbot'),
            });
        });
    }

    /**
     * Delete selected datasets
     */
    const deleteSelected = async () => {
        if (selectedDatasets?.length && await confirm(__("Are you sure you want to delete the selected ones?", 'limb-chatbot'))) {
            setDeleting([...selectedDatasets]);
            // Process states
            const deleted = [];
            const failed = [];
            // Delete selected datasets
            for (const id of selectedDatasets) {
                try {
                    // Delete single one
                    const res = await DeleteDataset(LimbChatbot.rest.url, LimbChatbot.rest.nonce, id);
                    if (res) {
                        deleted.push(id);
                    } else {
                        failed.push(id);
                        handleError(res);
                    }
                } catch (e) {
                    failed.push(id);
                    handleError(e);
                }
            }
            // Update states
            setSelectedDatasets(failed);
            
            // Handle pagination after deletion
            if (deleted.length > 0) {
                handlePaginationAfterDeletion({
                    currentItemsCount: datasets.length,
                    deletedCount: deleted.length,
                    pagination: datasetsPagination,
                    fetchFunction: fetchDatasets,
                    order: datasetsOrder,
                    setItems: setDatasets,
                    setPagination: setDatasetsPagination,
                    deletedIds: deleted
                });
            }
            // Check status to show
            if (failed.length) {
                // Failed to delete some of the datasets
                let warningTitle = __("Failed to delete datasets.", 'limb-chatbot');
                if (failed.length < selectedDatasets.length) {
                    if (failed.length > 1) {
                        warningTitle = __("Failed to delete some of datasets.", 'limb-chatbot');
                    } else {
                        if (selectedDatasets.length > 1) {
                            warningTitle = __("Failed to delete one Q&A.", 'limb-chatbot');
                        } else {
                            warningTitle = __("Failed to delete the Q&A.", 'limb-chatbot');
                        }
                    }
                } else if (selectedDatasets.length === 1) {
                    warningTitle = __("Failed to delete the Q&A.", 'limb-chatbot');
                }
                handleWarning({message: "These vector datasets doesn't deleted: " + failed.join(', ')}, notifications.set, {
                    title: warningTitle,
                    description: __("Please try again.", 'limb-chatbot'),
                });
            } else {
                // Success
                handleSuccess(notifications.set, {
                    title: __("Data saved successfully.", 'limb-chatbot'),
                });
            }
            setDeleting([]);
        }
    }

    /**
     * Delete dataset
     *
     * @param {object} dataset Dataset data
     */
    const deleteDataset = async (dataset) => {
        if (deleting.indexOf(dataset.id) === -1) {
            if (await confirm(__("Are you sure you want to delete the Q&A?", 'limb-chatbot'))) {
                setDeleting(prevState => [...prevState, dataset.id]);
                DeleteDataset(LimbChatbot.rest.url, LimbChatbot.rest.nonce, dataset.id).then(res => {
                    // Handle pagination after deletion
                    handlePaginationAfterDeletion({
                        currentItemsCount: datasets.length,
                        deletedCount: 1,
                        pagination: datasetsPagination,
                        fetchFunction: fetchDatasets,
                        order: datasetsOrder,
                        setItems: setDatasets,
                        setPagination: setDatasetsPagination,
                        deletedIds: [dataset.id]
                    });

                    setDeleting(prevState => prevState.filter(item => item !== dataset.id));
                    handleSuccess(notifications.set, {
                        title: __("Deletion completed successfully.", 'limb-chatbot'),
                    });
                }).catch(e => {
                    setDeleting(prevState => prevState.filter(item => item !== dataset.id));
                    handleError(e, notifications.set, {
                        title: __("Failed to delete Q&A.", 'limb-chatbot'),
                        description: e.message ? __(e.message, 'limb-chatbot') : __("Please try again.", 'limb-chatbot'),
                    });
                });
            }
        }
    }

    /**
     * Upload file
     *
     * @param {File} file File
     * @return {Promise<*>}
     */
    const uploadFile = async (file) => {
        try {
            return await UploadDatasetFile(LimbChatbot.rest.url, LimbChatbot.rest.nonce, file);
        } catch (e) {
            handleError(e, notifications.set, {
                title: __("File upload failed.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Something went wrong.", 'limb-chatbot'),
            });
            return false;
        }
    }

    /**
     * Close import files popup
     *
     * @param dataset
     * @return {Promise<void>}
     */
    const closeImportFilesPopup = async (dataset) => {
        if (dataset?.id) {
            const found = datasets.find(item => item.id === dataset.id);
            if (found) {
                // Update the same page
                fetchDatasets(datasetsPagination.page, datasetsPagination.perPage, datasetsOrder);
            } else {
                // To check the new item,
                // the change will trigger to fetch datasets by the given order
                setDatasetsOrder({
                    orderBy: 'id',
                    order: 'desc',
                });
            }
        }
        // Close popup
        setShowImportFilesPopup(false);
    }

    /**
     * Add new dataset
     */
    const showNewDataset = () => {
        setAddingEditing(true);
        setSelectedDataset(null);
    }

    /**
     * Show edit dataset
     *
     * @param {object} dataset Dataset
     */
    const showEditDataset = (dataset) => {
        setAddingEditing(true);
        setSelectedDataset(dataset);
        // Update the URL
        navigate(getNavLinkTo('training', 'qas', {
            action: 'edit',
            dataset_id: dataset.id,
        }));
    }

    /**
     * Cancel adding/editing
     */
    const cancelAddingEditing = () => {
        setAddingEditing(false);
        setSelectedDataset(null);
    }

    const tableStructure = {
        columns: [
            {
                id: 'check',
                label: false,
                className: 'lbaic-settings-table-card-checkbox',
                render: () => <Checkbox isChecked={isAllSelected}
                                        isIntermediateChecked={isPartiallySelected}
                                        toggleValue={() => {
                                            // Get current page dataset IDs
                                            const currentPageDatasetIds = datasets.map(item => item.id);

                                            // Check if all current page datasets are selected
                                            const allCurrentPageSelected = currentPageDatasetIds.every(id => selectedDatasets.includes(id));

                                            if (allCurrentPageSelected) {
                                                // If all current page datasets are selected, remove them from selection
                                                setSelectedDatasets(prev => prev.filter(id => !currentPageDatasetIds.includes(id)));
                                            } else {
                                                // If not all current page datasets are selected, add all current page datasets to selection
                                                setSelectedDatasets(prev => {
                                                    const newSelection = [...prev];
                                                    currentPageDatasetIds.forEach(id => {
                                                        if (!newSelection.includes(id)) {
                                                            newSelection.push(id);
                                                        }
                                                    });
                                                    return newSelection;
                                                });
                                            }
                                        }}/>,
                value: {
                    className: 'lbaic-settings-table-card-checkbox',
                    render: (row, index) => {
                        const isDeleting = deleting.indexOf(row.id) !== -1;

                        return <Checkbox isChecked={selectedDatasets.indexOf(row.id) !== -1} toggleValue={() => {
                            const i = selectedDatasets.indexOf(row.id);
                            if (i === -1) {
                                setSelectedDatasets(prevState => [...prevState, row.id]);
                            } else {
                                setSelectedDatasets(prevState => prevState.filter(item => item !== row.id));
                            }
                        }} disabled={isDeleting}/>
                    }
                },
            },
            {
                id: 'id',
                label: __("ID", 'limb-chatbot'),
                className: false,
                render: false,
                sortable: true,
                value: {
                    className: false,
                    value: (row, index) => row.id,
                },
            },
            {
                id: 'name',
                label: __("Name", 'limb-chatbot'),
                className: false,
                render: false,
                sortable: true,
                value: {
                    className: false,
                    value: (row, index) => row.name,
                },
            },
            {
                id: 'created_at',
                label: __("Created", 'limb-chatbot'),
                className: false,
                render: false,
                sortable: true,
                value: {
                    className: false,
                    render: (row, index) => {
                        return <Chip label={getFormatedDate(row.created_at, 'MMM D, YYYY')}/>
                    },
                },
            },
            {
                id: 'updated_at',
                label: __("Modified", 'limb-chatbot'),
                className: false,
                render: false,
                sortable: true,
                value: {
                    className: false,
                    nullable: (row, index) => row.created_at === row.updated_at,
                    render: (row, index) => {
                        return <Chip label={getFormatedDate(row.created_at, 'MMM D, YYYY')}/>
                    },
                },
            },
            {
                id: 'actions',
                label: false,
                className: false,
                render: null,
                value: {
                    className: 'lbaic-settings-table-card-floating',
                    render: (row) => {
                        return <Actions key={row.id} dataset={row} deleting={deleting} showEditDataset={showEditDataset}
                                        deleteDataset={deleteDataset} notifications={notifications} navigate={navigate}/>
                    }
                },
            },
        ],
    };

    const footerDisabled = loading > 0 && !isDataFetched;
    const footerActionsDisabled = {
        delete: footerDisabled || (!selectedDatasets?.length || deleting?.length > 0)
    };

    return <>
        {addingEditing ?
            <AddEdit data={selectedDataset} setData={setSelectedDataset}
                     loading={loading} setLoading={setLoading}
                     cancel={cancelAddingEditing}
                     notifications={notifications} navigate={navigate}/>
            :
            <>
                <ContentBodyInner>
                    {loading > 0 && !isDataFetched && <ContentLoading/>}
                    <Container className="lbaic-settings-a-ftds">
                        {
                            datasets.length ? (
                                <Table
                                    className='lbaic-settings-scroll-style lbaic-settings-scroll-x lbaic-settings-table-card-kb-qas'
                                    structure={tableStructure}
                                    data={datasets}
                                    pagination={datasetsPagination}
                                    order={{get: datasetsOrder, set: setDatasetsOrder}}
                                    _callback={fetchDatasets}/>
                            ) : (
                                isDataFetched && (
                                    <Empty title={__("No Q&A yet", 'limb-chatbot')}
                                           subtitle={__("Start by adding your first one", 'limb-chatbot')}
                                           icon="empty-qas-active">
                                        <div className='lbaic-settings-empty-actions'>
                                            <button onClick={() => setShowImportFilesPopup(true)}
                                                    className='lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-40 lbaic-settings-button-tertiary'>
                                            <span
                                                className='lbaic-settings-button-label'>{__("Import Q&A", 'limb-chatbot')}</span>
                                            </button>
                                            <button onClick={showNewDataset}
                                                    className='lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-40 lbaic-settings-button-primary'>
                                            <span
                                                className='lbaic-settings-button-label'>{__("Add new Q&A", 'limb-chatbot')}</span>
                                            </button>
                                        </div>
                                    </Empty>
                                )
                            )
                        }
                    </Container>
                </ContentBodyInner>
                <ContentFooterLayout className='lbaic-settings-a-ei-footer' loading={loading > 0 || deleting?.length > 0}>
                    {datasets.length > 0 &&
                        <>
                            <button onClick={() => !footerDisabled && showNewDataset()}
                                    className={`lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-40 lbaic-settings-button-primary lbaic-settings-content-footer-actions-in${footerDisabled ? ' lbaic-settings-button-disabled' : ''}`}>
                                <span className='lbaic-settings-button-label'>{__("Add Q&A", 'limb-chatbot')}</span>
                            </button>
                            <button onClick={() => !footerDisabled && setShowImportFilesPopup(true)}
                                    className={`lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-40 lbaic-settings-button-secondary lbaic-settings-content-footer-actions-in${footerDisabled ? ' lbaic-settings-button-disabled' : ''}`}>
                                <span className='lbaic-settings-button-label'>{__("Import Q&A", 'limb-chatbot')}</span>
                            </button>
                            {selectedDatasets.length > 0 &&
                                <button onClick={() => !footerActionsDisabled.delete && deleteSelected()}
                                        className={`lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-40 lbaic-settings-button-secondary lbaic-settings-content-footer-actions-in lbaic-settings-a-ftds-footer-actions-in${footerActionsDisabled.delete ? ' 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>
                                    <span className='lbaic-settings-button-label'>{__("Delete", 'limb-chatbot')}</span>
                                </button>}
                        </>}
                </ContentFooterLayout>
            </>}
        {showImportFilesPopup &&
            <ImportFiles addFile={uploadFile}
                         close={closeImportFilesPopup}
                         notifications={notifications}/>}
    </>
}