"use client"

import * as React from 'react';

import dayjs from 'dayjs';
import _ from 'lodash';

import { rpcCache } from '@/api/cache';
import { rpc } from '@/api/request';
import type {
    CollectionRelationType,
    DatumDHLTType,
    DatumIMType,
    FieldDescriptionType,
    FilterPresetFKTType,
    SortDFInput,
    StructureType,
} from '@/api/types';
import { toast } from '@/components/ToastRoot';
import { MobileToolbar } from '@/components/ui/mobile';
import { useAppConfig } from '@/contexts/AppConfigContext';
import { useEffectDebounce } from '@/hooks/useEffectDebounce';
import { Lang } from '@/lang/Lang';

import { actionDialogRef } from '../ActionDialog';
import { collectionFieldsDialogRef } from '../CollectionFieldsDialog';
import { confirmAlertRef } from '../ConfirmAlert';
import { exportDialogRef } from '../ExportDialog';
import { GridRow } from '../ui/grid';
import HashUpdate from './components/HashUpdate';
import TableFilterDialog, {
    TableFilterDialogRef,
} from './components/TableFilterDialog';
import TableNavabar from './components/TableNavabar';
import TablePagination from './components/TablePagination';
import TableView from './components/TableView';
import {
    ColumnsType,
    prepareFilterValues,
} from './utils';

export type CollectionTableProps = {
    collection: string;
    defaultFilter?: any;
    dialog?: boolean;
    modalKey?: string;

}

const CollectionTable = ({ collection, defaultFilter = {}, dialog = false, modalKey }: CollectionTableProps) => {




    const { openDialog } = useAppConfig();
    const [sortable, setSortable] = React.useState<boolean>(false);


    const [filter, setFilter] = React.useState<{}>({});


    const [loading, setLoading] = React.useState<boolean>(false);

    const [structure, setStructure] = React.useState<StructureType | null>(null);

    const [relations, setRelations] = React.useState<CollectionRelationType[]>([]);
    const [data, setData] = React.useState<DatumDHLTType | null>(null);
    const [sort, setSort] = React.useState<SortDFInput | null>(null);

    const [limit, setLimit] = React.useState<number>(20);
    const [offset, setOffset] = React.useState<number>(0);

    const [search, setSearch] = React.useState<string | null>(null);
    const [total, setTotal] = React.useState<number>(0);

    const [descriptions, setDescriptions] = React.useState<FieldDescriptionType | null>(null);

    const [filterPreset, setFilterPreset] = React.useState<FilterPresetFKTType | null>(null);

    const searchTimeout = React.useRef<any>(null);
    React.useEffect(() => {
        if (searchTimeout.current) {
            clearTimeout(searchTimeout.current);
        }
        searchTimeout.current = setTimeout(() => {
            loadTableData();
        }, 1000);
    }, [search])



    const loadTableDataInProgress = React.useRef<boolean>(false);
    const loadTableData = React.useCallback(() => {

        if (structure) {
            setLoading(true);

            localStorage.setItem(`collection_table_sort_${collection}`, JSON.stringify(sort));
            localStorage.setItem(`collection_table_search_${collection}`, search ?? "");
            localStorage.setItem(`collection_table_filterPreset_${collection}`, JSON.stringify(filterPreset));


            loadTableDataInProgress.current = true;
            rpc.data({
                sort: sort ?? undefined,
                search: (!!search && !!search.trim()) ? search.trim() : undefined,
                collection: collection,

                limit: limit,
                filter: { ...prepareFilterValues(filter), ...defaultFilter, },
                pipeline: filterPreset?.filter,
                offset: offset,

            }).then((data) => {

                if (data?.result?.data?.length == 0 && offset > 0) {

                    setOffset(0);
                    return;
                }


                setData(data.result ?? null);
                setTotal(data.result?.total ?? 0);
            }).finally(() => {
                loadTableDataInProgress.current = false;
                setLoading(false);
            });
        }
    }, [structure, collection, sort, search, limit, offset, filterPreset, filter]);

    useEffectDebounce(1000, () => {


        let _filterPreset = localStorage.getItem(`collection_table_filterPreset_${collection}`);
        if (_filterPreset) {
            setFilterPreset(JSON.parse(_filterPreset));
        }

        let sort = localStorage.getItem(`collection_table_sort_${collection}`);
        if (sort) {
            setSort(JSON.parse(sort));
        }

        let search = localStorage.getItem(`collection_table_search_${collection}`);
        if (search) {
            setSearch(search);
        }

        if (!dialog) {

            let _filter = localStorage.getItem(`collection_table_filter_${collection}`);


            if (_filter) {
                console.log('=====> load filter: ' + _filter);
                setFilter(JSON.parse(_filter));
            }
        }

        setLoading(true);
        setStructure(null);
        rpcCache.collection({ collection: collection }).then((json) => {

            if (json?.result?.structure) {
                setStructure(json.result.structure);
            }
            setRelations(json?.result?.relations ?? []);
            if (json?.result?.descriptions) {
                setDescriptions(json.result.descriptions);
            }
        }).finally(() => {
            //  setLoading(false);
        });

    }, [collection]);




    React.useEffect(() => {

        if (structure?.filterPresets && !filterPreset) {
            setFilterPreset(structure?.filterPresets[0]);
        }

        loadTableData();

    }, [structure, sort, limit, offset, filterPreset, filter]);

    React.useEffect(() => {
        if (sortable) {
            setSort(null);
        }
    }, [sortable]);

    const onClickSort = (column: ColumnsType) => {


        if (sortable) {
            toast.error(Lang.key("sortingByHandDisabledWithManualSort"));
            return;
        }

        if (sort?.field == column.dataIndex) {

            if (sort?.direction == "ASC") {
                setSort({
                    field: column.dataIndex,
                    direction: "DESC",
                });
            } else {
                setSort(null);
            }
        } else {
            setSort({
                field: column.dataIndex,
                direction: "ASC",
            });
        }

    }


    const [selectedRows, setSelectedRows] = React.useState<string[]>([]);


    const onSelectRow = (_id?: string) => {

        if (!_id) {

            return;
        }

        if (selectedRows.includes(_id)) {
            setSelectedRows(selectedRows.filter((id) => id !== _id));
        } else {
            setSelectedRows([...selectedRows, _id]);
        }

    }

    const onSelectAll = () => {


        if (selectedRows.length == data?.data?.length) {
            setSelectedRows([]);
        } else {
            setSelectedRows(data?.data?.map((item) => item._id!) ?? []);
        }

    }


    const onReorder = React.useCallback((activeIndex: number, overIndex: number, newData: DatumIMType[]) => {
        if (!data?.data || activeIndex === overIndex) {
            return;
        }

        const movedItem = data.data[activeIndex];

        if (!movedItem?._id) {
            return;
        }

        // После arrayMove элемент находится на позиции overIndex в newData
        // Определяем элемент, относительно которого размещаем
        const moveParams: any = {
            _id: movedItem._id,
            collection: collection,
        };

        // Определяем позицию относительно соседних элементов в новом порядке
        if (overIndex > 0) {
            // Размещаем ниже элемента выше (aboveId)
            moveParams.aboveId = newData[overIndex - 1]._id;
        } else if (overIndex < newData.length - 1) {
            // Размещаем выше элемента ниже (belowId) - только если не первый
            moveParams.belowId = newData[overIndex + 1]._id;
        } else {
            // Единственный элемент или переместили в конец
            if (newData.length > 1) {
                moveParams.aboveId = newData[overIndex - 1]._id;
            }
        }

        // Оптимистично обновляем UI
        setData((prevData) => {
            if (!prevData) return prevData;
            return {
                ...prevData,
                data: newData,
            };
        });

        // Вызываем API для сохранения нового порядка
        rpc.moveUpdate(moveParams).then(() => {
            toast.success(Lang.key("sortingByHandSuccess"));
        }).catch((error) => {
            toast.error(Lang.key("sortingByHandError"));
            console.error('Failed to update order:', error);
            // В случае ошибки перезагружаем данные
            loadTableData();
        });
    }, [data, collection, loadTableData]);


    const rootRef = React.useRef<HTMLDivElement>(null);
    const headerRef = React.useRef<HTMLDivElement>(null);
    const [headerHeight, setHeaderHeight] = React.useState<number>(0);
    const [width, setWidth] = React.useState<number>(0);

    React.useEffect(() => {
        if (headerRef.current) {
            setHeaderHeight(headerRef.current.clientHeight);
        }
        if (rootRef.current) {
            setWidth(rootRef.current.clientWidth);
        }
    }, [headerRef.current, rootRef.current]);



    React.useEffect(() => {

        let changeResizeTimeout: any = null;

        let changeScreenSizeEvent = window.addEventListener('resize', () => {
            clearTimeout(changeResizeTimeout);
            changeResizeTimeout = setTimeout(() => {

                if (headerRef.current) {
                    setHeaderHeight(headerRef.current.clientHeight);
                }

                if (rootRef.current) {
                    setWidth(rootRef.current.clientWidth);
                }
            }, 1000);
        });

        return () => {
            clearTimeout(changeResizeTimeout);
            window.removeEventListener('resize', changeScreenSizeEvent as any);
        };


    }, []);

    const onCreate = () => {
        openDialog({
            modalKey: `collection_create_${collection}`,
            collection: collection,
        });
    }

    const onApplyFilter = (filterStructureData: StructureType[], values: any) => {
        setFilter((prev) => {
            return { ...values };
        });
        if (!dialog) {
            console.log('=====> save filter: ' + JSON.stringify(values));
            localStorage.setItem(`collection_table_filter_${collection}`, JSON.stringify(values));
        }
    }


    const { openTableDialog } = useAppConfig();


    const onOpenRelationTable = (item: CollectionRelationType, row_id?: string) => {
        openTableDialog({
            ...item,
            ids: row_id ? [row_id] : selectedRows,
        });
    }




    const onExportSelected = () => {
        onExport(selectedRows);
    }


    const onExport = (ids?: string[]) => {





        if (!structure?.collection) return;

        let title = "";


        title += structure.title || structure.collection || "data";

        if (filterPreset) {
            title += `-${filterPreset.title}`;
        }

        title += `-${dayjs().format('DD-MM-YYYY-HH-mm')}`;

        confirmAlertRef.current?.open({
            title: ids ? Lang.key("export_selected_items") : Lang.key("export_data_confirm"),
            description: ids ? Lang.key("export_selected_items_description") : Lang.key("export_data_confirm_description"),
            buttons: [
                {
                    label: Lang.key("export_data"),
                    onClick: () => {
                        if (!structure?.collection) return;

                        rpc.makeExport({
                            ids: ids ?? undefined,
                            title: title,

                            collection: structure?.collection,
                            filter: { ...prepareFilterValues(filter), ...defaultFilter },
                            pipeline: filterPreset?.filter,
                        }).then((res) => {
                            toast.success(Lang.key("exportCreatedSuccess"));
                            exportDialogRef?.current?.open();
                        }).catch((error) => {
                            exportDialogRef?.current?.open();
                        });
                    }
                },
                {
                    label: Lang.key("cancel"),
                    onClick: () => {
                        confirmAlertRef.current?.close();
                    }
                }
            ]
        })





    }

    const onEditFields = (item: StructureType, row_id?: string) => {

        console.log('=====> onEditFields: ' + JSON.stringify(item));
        console.log('=====> row_id: ' + row_id);
        console.log('=====> selectedRows: ' + selectedRows);


        collectionFieldsDialogRef.current?.open({
            structure: item,
            initialValues: {},
            onSave: (values: any) => {


                let loading = toast.loading(Lang.key("saving"));
                rpc.update({
                    collection: collection,
                    _ids: row_id ? [row_id] : selectedRows,
                    values: values
                }).then(() => {
                    toast.success(Lang.key("saved_successfully"));
                    loadTableData();
                }).finally(() => {
                    toast.dismiss(loading);
                });
            }
        });
    }
    const onDoAction = (item: StructureType, row_id?: string) => {


        if (!row_id && !selectedRows.length) {
            return;
        }

        actionDialogRef.current?.open({
            collection: collection,
            action: item,
            ids: row_id ? [row_id] : selectedRows,
            onSuccess: () => {
                loadTableData();
            }
        });
    }
    const onDeleteSelected = (row_id?: string) => {

        confirmAlertRef.current?.open({
            title: row_id ? Lang.key("remove_item") : Lang.key("remove_selected_items"),
            description: row_id ? Lang.key("remove_item_description") : Lang.key("remove_selected_items_description"),
            buttons: [
                {
                    label: Lang.key("cancel"), onClick: () => {




                    }
                },
                {
                    label: Lang.key("delete"), onClick: () => {

                        let loading = toast.loading(Lang.key("removing_selected_items"));
                        rpc.deleteData({ collection: collection, _ids: row_id ? [row_id] : selectedRows }).then(() => {
                            toast.success(Lang.key("remove_selected_items_success"));
                            setSelectedRows([]);
                            loadTableData();
                        }).finally(() => {
                            toast.dismiss(loading);
                        });

                    }
                },
            ]
        });

    }

    const tableFilterDialogRef = React.useRef<TableFilterDialogRef>(null);

    const { closeDialog } = useAppConfig();
    const { isMobile } = useAppConfig();

    if (isMobile) {
        return <>
            <TableNavabar

                onCloseTableDialog={() => {
                    closeDialog(modalKey);
                }}
                dialog={dialog}
                onOpenRelationTable={onOpenRelationTable}
                relations={relations}
                filterCount={Object.keys(filter).length}

                onOpenFilter={() => {
                    tableFilterDialogRef.current?.open();
                }}
                onExportSelected={onExportSelected}
                onEditFields={onEditFields}
                onDoAction={onDoAction}
                onDeleteSelected={onDeleteSelected}
                onExport={onExport}
                structure={structure}
                filterPreset={filterPreset}
                setFilterPreset={setFilterPreset}
                search={search}
                setSearch={setSearch}
                onCreate={onCreate}
                selectedRows={selectedRows}
                setSortable={setSortable}
                sortable={sortable}

            />

            <HashUpdate
                lock={loading}
                collection={collection}
                limit={limit}
                offset={offset}
                search={search}
                sort={sort ?? undefined}
                filter={{ ...prepareFilterValues(filter), ...defaultFilter, ...filterPreset?.filter }}
                pipeline={filterPreset?.filter}
                currentHash={data?.hash}
                onHashUpdate={loadTableData}
            />

            <div className='h-full'>
                <TableView
                    onOpenRelationTable={onOpenRelationTable}
                    relations={relations}
                    onDeleteSelected={onDeleteSelected}
                    onEditFields={onEditFields}
                    sortable={sortable}
                    loading={loading}
                    onDoAction={onDoAction}
                    data={data?.data ?? []}
                    selectedRows={selectedRows}
                    sort={sort}
                    onSelectAll={onSelectAll}
                    onSelectRow={onSelectRow}
                    onClickSort={onClickSort}
                    onCreate={onCreate}
                    structure={structure}
                    onReorder={onReorder}
                />
            </div>

            <MobileToolbar className={`left-0 sticky bottom-0 w-full mt-auto`}>
                <TablePagination
                    onChangeOffset={setOffset}
                    total={total} limit={limit} offset={offset} />
            </MobileToolbar>


            <TableFilterDialog
                onApply={(data, values) => {
                    onApplyFilter(data, values);
                }}
                initialFilter={filter}
                ref={tableFilterDialogRef}
                structure={structure}
            />
        </>
    }

    return <>
        <TableNavabar
            onCloseTableDialog={() => {
                closeDialog(modalKey);
            }}
            onOpenRelationTable={onOpenRelationTable}
            relations={relations}
            filterCount={Object.keys(filter).length}

            onOpenFilter={() => {
                tableFilterDialogRef.current?.open();
            }}
            onExportSelected={onExportSelected}
            onEditFields={onEditFields}
            onDoAction={onDoAction}
            onDeleteSelected={onDeleteSelected}
            onExport={onExport}
            structure={structure}
            filterPreset={filterPreset}
            setFilterPreset={setFilterPreset}
            search={search}
            setSearch={setSearch}
            onCreate={onCreate}
            selectedRows={selectedRows}
            setSortable={setSortable}
            sortable={sortable}

        />

        <GridRow className='flex flex-col px-4'

        >

            <HashUpdate
                lock={loading}
                collection={collection}
                limit={limit}
                offset={offset}
                search={search}
                sort={sort ?? undefined}
                filter={{ ...prepareFilterValues(filter), ...defaultFilter }}
                pipeline={filterPreset?.filter}
                currentHash={data?.hash}
                onHashUpdate={loadTableData}
            />


            <TableView
                onOpenRelationTable={onOpenRelationTable}
                relations={relations}
                onDeleteSelected={onDeleteSelected}
                onEditFields={onEditFields}
                sortable={sortable}
                loading={loading}
                data={data?.data ?? []}
                onDoAction={onDoAction}
                selectedRows={selectedRows}
                sort={sort}
                onSelectAll={onSelectAll}
                onSelectRow={onSelectRow}
                onClickSort={onClickSort}
                onCreate={onCreate}
                structure={structure}
                onReorder={onReorder}
            />

        </GridRow>
        <GridRow autoSize className='p-4'>

            <TablePagination
                onChangeOffset={setOffset}
                total={total} limit={limit} offset={offset} />
        </GridRow>

        <TableFilterDialog
            onApply={(data, values) => {
                onApplyFilter(data, values);
            }}
            ref={tableFilterDialogRef}
            structure={structure}
        />
    </>


}


export default CollectionTable;