import { type FC, useRef } from 'react';
import React, { useCallback, useState } from 'react';
import { Pagination, LoadingSpinner } from '@theorchard/suite-components';
import { Page } from '@theorchard/suite-frontend';
import StickyHeader from 'src/components/stickyHeader';
import { OrderDir, OwnershipNrDeliveryJobsOrderBy } from 'src/data/globalTypes';
import { useOwnershipDeliveryJobsQuery } from 'src/data/queries';
import JobsTable from 'src/pages/monitorOwnershipPage/components/jobs/jobsTable';
import {
    recordGoToFirstPage,
    recordGoToLastPage,
    recordGoToNextPage,
    recordGoToPreviousPage,
    recordRowsPerPageClick,
} from 'src/utils/segment';
import {
    DEFAULT_SORT_DIR_MONITOR_PAGE,
    DEFAULT_SORT_FIELD_MONITOR_PAGE,
    PAGE_SIZE,
} from '../../constants';
import { ensureJobStatusType, ensureProductType } from '../../utils';
import Filters from '../filters';
import type { MonitorRouteParams } from '../../types';
import type { SortBy, SortDirection } from 'src/types';
import type { SetParamsCallback, ParamValue } from 'src/utils';

export const CLASSNAME = 'Jobs';

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

export const ensureSortByType = (
    sortBy: string
): OwnershipNrDeliveryJobsOrderBy | undefined => {
    if (sortBy === 'createdAt')
        return OwnershipNrDeliveryJobsOrderBy.ORDER_CREATED_AT;
    if (sortBy === 'id') return OwnershipNrDeliveryJobsOrderBy.ID;
    if (sortBy === 'lastUpdated')
        return OwnershipNrDeliveryJobsOrderBy.LAST_UPDATED;
    return undefined;
};

export const ensureSortDirectionType = (direction: string) => {
    if (direction === 'desc') return OrderDir.DESC;
    if (direction === 'asc') return OrderDir.ASC;
    return undefined;
};

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

    const {
        selectedTerritory,
        selectedOrder,
        selectedStore,
        selectedStatus,
        orderDir,
        orderBy,
        selectedEntity,
        selectedProductType,
    } = params;
    const getJobsVariables = {
        filters: {
            territory: selectedTerritory,
            cmmId: Number(selectedStore),
            entityName: selectedEntity,
            orderId: Number(selectedOrder),
            status: ensureJobStatusType(selectedStatus),
            type: ensureProductType(selectedProductType),
        },
        limit: pageSize,
        offset: page * pageSize,
        orderBy: ensureSortByType(orderBy),
        orderDir: ensureSortDirectionType(orderDir),
    };

    const { data, loading, error, fetchingMore } =
        useOwnershipDeliveryJobsQuery(getJobsVariables);
    const jobs = !loading ? data?.items ?? [] : [];
    const totalJobs = !loading ? data?.totalCount : 0;

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

    const filtersApplied = !!(
        selectedStore ||
        selectedOrder ||
        selectedStatus ||
        selectedEntity
    );
    const sortingApplied =
        orderDir !== DEFAULT_SORT_FIELD_MONITOR_PAGE ||
        orderBy !== DEFAULT_SORT_DIR_MONITOR_PAGE;

    const handleClearFilters = useCallback(() => {
        setPage(0);
        handleParams({
            orderId: undefined,
            storeId: undefined,
            productType: undefined,
            entity: undefined,
            tab: 'ownership',
        });
    }, [handleParams]);

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

    const handlePageChange = useCallback(
        (currentPage: number) => {
            const shift = currentPage - page;
            const lastPage = Math.ceil((totalJobs ?? 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, totalJobs, pageSize]
    );

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

    return (
        <div className={CLASSNAME} data-testid="JobsContainer">
            <StickyHeader target={headerVisibilityThreshold}>
                <Filters setParams={handleFiltersChange} params={params} />
                <div
                    className={`${CLASSNAME}-sticky-row`}
                    style={{ paddingBottom: 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(
                                'ownershipRights.monitorOwnershipPage.updatingTable'
                            )}
                        </div>
                    )}
                </div>
            </StickyHeader>
            <Filters params={params} setParams={handleFiltersChange} />
            <Page.View error={error} loading={loading} hasData={!!data}>
                <div ref={headerVisibilityThreshold} />
                <JobsTable
                    jobs={jobs}
                    totalCount={totalJobs ?? 0}
                    loading={
                        (loading || fetchingMore) &&
                        (sortingApplied || filtersApplied)
                    }
                    onSort={handleSort}
                    sortBy={{
                        key: orderBy,
                        direction: orderDir as SortDirection,
                    }}
                    page={page}
                    pageSize={pageSize}
                    handlePageChange={handlePageChange}
                    handlePageSizeChange={handlePageSizeChange}
                    onClearFilters={handleClearFilters}
                    filtersApplied={filtersApplied}
                    getJobsVariables={getJobsVariables}
                />
            </Page.View>
        </div>
    );
};

export default Jobs;
