import React, {
    type FC,
    useCallback,
    useEffect,
    useRef,
    useState,
} from 'react';
import { LoadingSpinner, Pagination } from '@theorchard/suite-components';
import { Page } from '@theorchard/suite-frontend';
import StickyHeader from 'src/components/stickyHeader';
import { NrDeliveryOrderStatus } from 'src/data/globalTypes';
import { useGetNrDeliveryJobsQuery } from 'src/data/queries';
import Filters from 'src/pages/monitorPage/components/filters';
import {
    ensureJobsSortByType,
    ensureJobStatusType,
} from 'src/pages/monitorPage/utils';
import { type SortBy, type SortDirection } from 'src/types';
import { ensureSortDirectionType, type ParamValue } from 'src/utils';
import { type SetParamsCallback } from 'src/utils/route';
import {
    recordGoToFirstPage,
    recordGoToLastPage,
    recordGoToNextPage,
    recordGoToPreviousPage,
    recordJobsSortingByKey,
    recordRowsPerPageClick,
} from 'src/utils/segment';
import { DEFAULT_SORT_DIR_JOBS_PAGE, PAGE_SIZE } from '../constants';
import { type MonitorRouteParams } from '../types';
import JobsTable from './jobsTable';

export const CLASSNAME = 'Jobs';

interface Props {
    params: MonitorRouteParams;
    handleParams: SetParamsCallback;
}

const Jobs: FC<Props> = ({ params, handleParams }) => {
    const [page, setPage] = useState(0);
    const [pageSize, setPageSize] = useState(PAGE_SIZE);
    const headerVisibilityThreshold = useRef<HTMLDivElement>(null);

    const {
        selectedStatus,
        selectedOrder,
        selectedContributor,
        selectedStore,
        orderBy,
        orderDir,
    } = params;

    const { data, loading, error, fetchingMore, onFetchMore } =
        useGetNrDeliveryJobsQuery({
            filters: {
                cmoId: selectedStore,
                contributorId: selectedContributor,
                orderId: selectedOrder,
                status: ensureJobStatusType(selectedStatus),
                orderStatus: [
                    NrDeliveryOrderStatus.PROCESSING_JOBS,
                    NrDeliveryOrderStatus.STARTED,
                    NrDeliveryOrderStatus.SUCCESS,
                ],
            },
            limit: pageSize,
            orderBy: ensureJobsSortByType(orderBy),
            orderDir: ensureSortDirectionType(orderDir),
            offset: page * pageSize,
        });

    const filtersApplied = !!(
        selectedStatus ||
        selectedContributor ||
        selectedOrder ||
        selectedStore
    );
    const sortingApplied =
        orderDir !== DEFAULT_SORT_DIR_JOBS_PAGE ||
        orderBy !== DEFAULT_SORT_DIR_JOBS_PAGE;

    const handleSort = (sortBy: SortBy[]) => {
        recordJobsSortingByKey(sortBy[0].key, sortBy[0].direction);
        handleParams({ orderBy: sortBy[0].key, orderDir: sortBy[0].direction });
    };

    const handleFetchMore = useCallback(
        async (limit: number, offset: number) => {
            await onFetchMore({ variables: { limit, offset } });
        },
        [onFetchMore]
    );

    const handleClearFilters = useCallback(() => {
        setPage(0);
        handleParams({
            orderId: undefined,
            status: undefined,
            contributor: undefined,
            store: undefined,
            tab: 'performance',
        });
    }, [handleParams]);

    const handleFiltersChange = useCallback(
        (filters: string | Record<string, ParamValue | undefined>) => {
            // reset pagination when filters change
            setPage(0);
            handleParams(filters);
        },
        [handleParams]
    );

    useEffect(() => {
        if (!loading)
            handleFetchMore(pageSize, page * pageSize).catch(error =>
                console.error(error)
            );
    }, [page, pageSize, loading, handleFetchMore]);

    const handlePageChange = useCallback(
        (currentPage: number) => {
            const shift = currentPage - page;
            const lastPage = Math.ceil((data?.totalCount ?? 0) / pageSize) - 1;

            if (shift === 1) {
                recordGoToNextPage();
            } else if (shift === -1) {
                recordGoToPreviousPage();
            } else if (currentPage === lastPage) {
                recordGoToLastPage();
            } else if (currentPage === 0) {
                recordGoToFirstPage();
            }

            setPage(currentPage);
        },
        [page, data?.totalCount, pageSize]
    );

    const handlePageSizeChange = useCallback((size: number) => {
        setPageSize(size);
        recordRowsPerPageClick(size);
    }, []);

    return (
        <div className={CLASSNAME}>
            <StickyHeader target={headerVisibilityThreshold}>
                <Filters setParams={handleFiltersChange} params={params} />
                <div
                    className={`${CLASSNAME}-sticky-row`}
                    style={{
                        paddingBottom: loading ? 10 : 0,
                        paddingTop: loading ? 10 : 0,
                    }}
                >
                    <Pagination
                        totalCount={data?.totalCount ?? 0}
                        currentPage={page}
                        pageSize={pageSize}
                        onChange={handlePageChange}
                        onSetPageSize={handlePageSizeChange}
                        loading={loading}
                    />
                    {loading && (
                        <div className={`${CLASSNAME}-sticky-row-status`}>
                            <LoadingSpinner
                                show
                                className={`${CLASSNAME}-sticky-row-status-icon`}
                            />
                            {$t('neighbouringRights.monitorPage.updatingTable')}
                        </div>
                    )}
                </div>
            </StickyHeader>
            <Filters setParams={handleFiltersChange} params={params} />
            <Page.View error={error} loading={loading} hasData={!!data}>
                <div ref={headerVisibilityThreshold} />
                <JobsTable
                    jobs={data?.items ?? []}
                    totalJobs={data?.totalCount}
                    loading={
                        (loading || fetchingMore) &&
                        (sortingApplied || filtersApplied)
                    }
                    onSort={handleSort}
                    sortBy={{
                        key: orderBy,
                        direction: orderDir as SortDirection,
                    }}
                    onClearFilters={handleClearFilters}
                    filtersApplied={filtersApplied}
                    page={page}
                    pageSize={pageSize}
                    handlePageChange={handlePageChange}
                    handlePageSizeChange={handlePageSizeChange}
                />
            </Page.View>
        </div>
    );
};

export default Jobs;
