import {useEffect, useState} from "@wordpress/element";
import {__} from "@wordpress/i18n";
import ContentBodyInner from "../../../../../containers/content/body-inner";
import ContentLoading from "../../../../../containers/content/loading";
import Container from "../../../../../containers/content/container";
import Table from "../../../../../../../sections/table";
import {
    DeleteDatasetEntries,
    DeleteDatasetEntry,
    GetDatasetEntries
} from "../../../../../../../../rest/dataset-entries";
import {handleError, handleSuccess} from "../../../../../../../../helpers/notifications";
import {handlePaginationAfterDeletion} from "../../../../../../../../helpers";
import Checkbox from "../../../../../../../fields/checkbox";
import {renderEntryQuestion, renderSource, renderStorage} from "../../_renderers";
import DatasetEntryDetails from "./dataset-entry-details";
import ContentFooterLayout from "../../../../../containers/content/footer/_components/layout";
import {GetDataset} from "../../../../../../../../rest/datasets";
import Chip from "../../../../../../../fields/chip";
import RealTimeRelativeTime from "../../../../../../../fields/real-time-relative-time";

export default function DatasetEntries({datasetId, cancel, notifications}) {
    const [loading, setLoading] = useState(0);
    const [isDataFetched, setIsDataFetched] = useState(false);
    const [isDatasetFetched, setIsDatasetFetched] = useState(false);
    const [saving, setSaving] = useState(false);
    const [deleting, setDeleting] = useState(false);
    const [deletingSelected, setDeletingSelected] = useState(false);

    const [selected, setSelected] = useState([]);

    const [dataset, setDataset] = useState(null);

    const [datasetEntries, setDatasetEntries] = useState([]);
    const [pagination, setPagination] = useState({
        page: 1,
        perPage: LimbChatbot.screen_options?.lbaic_items_per_page || 10,
        total: 0
    });
    const [order, setOrder] = useState({
        orderBy: 'id',
        order: 'asc',
    });

    const isDataReady = isDataFetched && isDatasetFetched;
    const allSelected = selected.length > 0 && datasetEntries.every(item => selected.indexOf(item.id) !== -1);
    const doing = loading > 0 || saving || deleting || deletingSelected;

    useEffect(() => {
        if (dataset?.id !== datasetId) {
            fetchDataset(datasetId);
        }
    }, [datasetId]);

    useEffect(() => {
        fetchEntries(1, pagination.perPage, order);
    }, [order]);

    /**
     * Fetch dataset
     *
     * @param {number} id Dataset ID
     * @return {Promise<void>}
     */
    const fetchDataset = async (id) => {
        setLoading(prev => prev + 1);
        try {
            const res = await GetDataset(LimbChatbot.rest.url, LimbChatbot.rest.nonce, id, {
                include: ['storage', 'source_object', 'source_url']
            });
            if (res?.dataset?.id) {
                setDataset(res.dataset);
                setIsDatasetFetched(true);
            } else {
                setDataset(null);
            }
        } catch (e) {
            handleError(e, notifications.set, {
                title: __("Failed to get dataset.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Please check and try again."),
            });
            setDataset(null);
        }
        setLoading(prev => prev - 1);
    }

    /**
     * Fetch entries
     *
     * @param {number} page Page
     * @param {number} perPage Per page
     * @param {object} params Params
     * @return {Promise<void>}
     */
    const fetchEntries = async (page, perPage, params = {}) => {
        setLoading(prev => prev + 1);
        try {
            const res = await GetDatasetEntries(LimbChatbot.rest.url, LimbChatbot.rest.nonce, datasetId, {
                page: page,
                per_page: perPage,
                orderby: params.orderBy || 'id',
                order: params.order || 'asc',
            });
            if (res.items?.length) {
                setDatasetEntries([...res.items]);
            } else {
                setDatasetEntries([]);
            }
            // Update pagination
            setPagination(prevState => ({
                ...prevState,
                page: page,
                total: +res.total,
            }));

            setIsDataFetched(true);
        } catch (e) {
            handleError(e, notifications.set, {
                title: __("Failed to get Q&As.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Please check and try again.", 'limb-chatbot'),
            });
        }
        setLoading(prev => prev - 1);
    }

    /**
     * Check/Uncheck all storages
     */
    const toggleAll = () => {
        if (allSelected) {
            setSelected([]);
        } else {
            setSelected(datasetEntries.map(item => item.id));
        }
    }

    /**
     * Delete entry
     *
     * @param {object} entry Entry
     * @param {number} index Index
     * @return {Promise<void>}
     */
    const deleteEntry = async (entry, index) => {
        if (await confirm("Are you sure you want to delete?", 'lbaic-settings-chatbot')) {
            setDeleting(true);
            try {
                await DeleteDatasetEntry(LimbChatbot.rest.url, LimbChatbot.rest.nonce, entry.id);
                
                // Handle pagination after deletion
                handlePaginationAfterDeletion({
                    currentItemsCount: datasetEntries.length,
                    deletedCount: 1,
                    pagination: pagination,
                    fetchFunction: fetchEntries,
                    order: order,
                    setItems: setDatasetEntries,
                    setPagination: setPagination,
                    deletedIds: [entry.id]
                });
            } catch (e) {
                handleError(e, notifications.set, {
                    title: __("Failed to delete.", 'limb-chatbot'),
                    description: e.message ? __(e.message, 'limb-chatbot') : __("Please check and try again.", 'limb-chatbot'),
                });
            }
            setDeleting(false);
        }
    }

    /**
     * Delete selected items
     *
     * @return {Promise<void>}
     */
    const deleteSelected = async () => {
        if (selected.length > 0) {
            if (await confirm(__("Are you sure you want to delete the selected ones?", 'limb-chatbot'))) {
                setDeletingSelected(true);
                try {
                    await DeleteDatasetEntries(LimbChatbot.rest.url, LimbChatbot.rest.nonce, datasetId, selected);

                    // Handle pagination after deletion
                    handlePaginationAfterDeletion({
                        currentItemsCount: datasetEntries.length,
                        deletedCount: selected.length,
                        pagination: pagination,
                        fetchFunction: fetchEntries,
                        order: order,
                        setItems: setDatasetEntries,
                        setPagination: setPagination,
                        deletedIds: selected
                    });

                    handleSuccess(notifications.set, {
                        title: __("Deletion completed successfully.", 'limb-chatbot'),
                    });

                    setSelected([]);
                } catch (e) {
                    handleError(false, notifications.set, {
                        title: __("Failed to delete selected item(s).", 'limb-chatbot'),
                        description: e.message ? __(e.message, 'limb-chatbot') : __("Please check and try again.", 'limb-chatbot'),
                    });
                }
                setDeletingSelected(true);
            }
        }
    }

    /**
     * Dataset entry `entry` property data updated
     *
     * @param {object} entryData Dataset entry `entry` property updated data
     * @param {number} rowId Dataset entry ID
     */
    const rowEntryDataUpdated = (entryData, rowId) => {
        setDatasetEntries(prevState => prevState.map(item => {
            if (item.id === rowId) {
                return {
                    ...item,
                    entry: entryData,
                };
            }

            return item;
        }));
    }

    const tableStructure = {
        columns: [
            {
                id: 'check',
                label: false,
                className: 'lbaic-settings-table-card-checkbox lbaic-settings-table-card-header-checkbox',
                render: () => <Checkbox isChecked={allSelected} toggleValue={toggleAll}
                                        disabled={doing}/>,
                value: {
                    className: 'lbaic-settings-table-card-checkbox lbaic-settings-table-card-body-checkbox',
                    render: (row, index) => {
                        return <Checkbox isChecked={selected.indexOf(row.id) !== -1}
                                         toggleValue={() => {
                                             const i = selected.indexOf(row.id);
                                             if (i === -1) {
                                                 setSelected(prevState => [...prevState, row.id]);
                                             } else {
                                                 setSelected(selected.filter(item => item !== row.id));
                                             }
                                         }}
                                         disabled={doing}/>
                    }
                },
            },
            {
                id: 'question',
                label: __("Question", 'limb-chatbot'),
                className: 'lbaic-settings-table-card-header-input',
                value: {
                    className: 'lbaic-settings-table-card-body-input lbaic-settings-cursor-pointer',
                    render: (row, index) => renderEntryQuestion(row),
                },
                detailsToggler: true,
            },
            {
                id: 'source',
                label: __("Source", 'limb-chatbot'),
                className: 'lbaic-settings-table-card-header-type',
                value: {
                    className: 'lbaic-settings-table-card-body-type',
                    render: (row, index) => renderSource(dataset, index, dataset?.source_type === 'text' || dataset?.source_type === 'q_a' ? 'chip' : 'label'),
                },
            },
            {
                id: 'storage',
                label: __("Storage", 'limb-chatbot'),
                className: 'lbaic-settings-table-card-header-storage',
                value: {
                    className: 'lbaic-settings-table-card-body-storage',
                    render: (row, index) => renderStorage(dataset)
                },
            },
            {
                id: 'updated_at',
                label: __("Updated at", 'limb-chatbot'),
                sortable: true,
                className: 'lbaic-settings-table-card-header-type',
                value: {
                    className: 'lbaic-settings-table-card-body-last-updated',
                    render: (row, index) => {
                        return <Chip>
                            <RealTimeRelativeTime
                                dateString={row.updated_at}
                                className='lbaic-settings-chip-label'
                            />
                        </Chip>
                    },
                },
            },
            {
                id: 'actions',
                label: false,
                className: 'lbaic-settings-table-card-header-actions',
                value: {
                    className: 'lbaic-settings-table-card-floating lbaic-settings-table-card-body-actions',
                    render: (row, index) => {
                        return <div className='lbaic-settings-table-card-actions'>
                            <button
                                onClick={(e) => {
                                    if (!doing) {
                                        e.stopPropagation();
                                        deleteEntry(row, index);
                                    }
                                }}
                                className={`lbaic-settings-table-card-actions-in lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-32 lbaic-settings-button-minimal${doing ? ' 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>
                    }
                },
            },
        ],
        row: {
            className: (row, index) => {
                let classes = 'lbaic-settings-table-accordion-body-in';

                return classes;
            },
            details: {
                show: true,
                render: (row, rowIndex, show) => {
                    return <DatasetEntryDetails
                        key={row.id}
                        row={row} rowIndex={rowIndex}
                        show={show}
                        updated={rowEntryDataUpdated}
                        notifications={notifications}
                    />
                }
            }
        },
    };

    return <>
        <ContentBodyInner>
            {(loading > 0 && !isDataReady) && <ContentLoading/>}
            <Container>
                <Table className='lbaic-settings-scroll-style lbaic-settings-scroll-x lbaic-settings-table-card-has-details lbaic-settings-table-card-kb-items-entries'
                       structure={tableStructure}
                       data={datasetEntries}
                       loading={doing}
                       pagination={pagination}
                       order={{get: order, set: setOrder}}
                       _callback={fetchEntries}>
                </Table>
            </Container>
        </ContentBodyInner>
        <ContentFooterLayout loading={doing}>
            <button
                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-content-footer-actions-end${doing ? ' lbaic-settings-button-disabled' : ''}`}
                onClick={() => !doing && cancel()}>
                <span className='lbaic-settings-button-label'>{__("Back", 'limb-chatbot')}</span>
            </button>
            {selected.length > 0 &&
                <button onClick={() => !doing && deleteSelected()}
                        className={`lbaic-settings-button lbaic-settings-button-center lbaic-settings-button-h-40 lbaic-settings-button-danger${doing ? ' lbaic-settings-button-disabled' : ''}`}>
                    {deletingSelected &&
                        <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>}
                    {!deletingSelected &&
                        <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>
    </>;
}