import { useEffect, useMemo, useState } from 'react';
import { FormProvider } from 'react-hook-form';
import { useInfiniteQuery, useQuery } from 'react-query';
import { useSearchParams } from 'react-router-dom';

import { format } from 'date-fns';
import useHuPagination from '@material-hu/hooks/useHuPagination';
import { IconFilter, IconInfoCircle } from '@material-hu/icons/tabler';
import Badge from '@material-hu/mui/Badge';
import IconButton from '@material-hu/mui/IconButton';
import Stack from '@material-hu/mui/Stack';
import { useTheme } from '@material-hu/mui/styles';

import CardContainer from '@material-hu/components/design-system/CardContainer';
import Checkbox from '@material-hu/components/design-system/Checkbox/Checkbox';
import Chip from '@material-hu/components/design-system/Chip';
import useHuSnackbar from '@material-hu/components/design-system/Snackbar';
import StateCard from '@material-hu/components/design-system/StateCard';
import Table from '@material-hu/components/design-system/Table';
import TableBody from '@material-hu/components/design-system/Table/components/TableBody';
import TableCell from '@material-hu/components/design-system/Table/components/TableCell';
import TableContainer from '@material-hu/components/design-system/Table/components/TableContainer';
import TableHead from '@material-hu/components/design-system/Table/components/TableHead';
import TableLoader from '@material-hu/components/design-system/Table/components/TableLoader';
import TableRow from '@material-hu/components/design-system/Table/components/TableRow';
import Title from '@material-hu/components/design-system/Title';

import { useReviewCategorizedHourApprovalStep } from 'src/hooks/queryHooks/timeTracking';
import { useDebounce } from 'src/hooks/useDebounce';
import useGeneralError from 'src/hooks/useGeneralError';
import { feedKeys } from 'src/pages/dashboard/feed/queries';
import { getSegmentationGroups } from 'src/services/segmentations';
import {
  type CategorizedHoursParams,
  getCategorizedHoursRequests,
  getHourCategories,
  getRegions,
  getUsers,
} from 'src/services/timeTracking';
import { type Segmentation } from 'src/types/segmentation';
import {
  type ApprovableStatus,
  type SegmentationGroup,
  TimeTrackingCategorizedHourStatus,
} from 'src/types/timeTracking';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { parseGroup } from 'src/components/dashboard/filterDrawer/utils';

import { useGetCategorizedHoursCategoryCounts } from '../hooks/useGetCategorizedHoursCategoryCounts';
import { refetchCategorizedHoursPending, timeTrackingKeys } from '../queries';

import ApprovalReasonMenu from './components/ApprovalReasonMenu';
import ApprovalRequestRow from './components/ApprovalRequestRow';
import BulkSelectionBar from './components/BulkSelectionBar';
import {
  CHECKBOX_COLUMN_WIDTH,
  FIXED_CELL_WIDTH,
  STICKY_LEFT_SX,
  STICKY_RIGHT_SX,
} from './components/constants';
import ListSkeleton from './components/ListSkeleton';
import { useApprovalDetailDrawer } from './components/useApprovalDetailDrawer';
import {
  type ApprovalFiltersFields,
  useApprovalFiltersDrawer,
} from './components/useApprovalFiltersDrawer';
import { useApprovalSelection } from './hooks/useApprovalSelection';
import { useApprovalSelectionLifecycle } from './hooks/useApprovalSelectionLifecycle';
import { useBulkReviewDialog } from './hooks/useBulkReviewDialog';
import { useBulkReviewSubmit } from './hooks/useBulkReviewSubmit';
import { useResolvedLastPendingState } from './hooks/useResolvedLastPendingState';
import { getBulkReviewBreakdown, resolveStepId } from './utils';

enum SortOptions {
  DATE = 'date',
  HOURS = 'hours',
  STATUS = 'status',
}

type RequestsList = 'pending' | 'processed';

const APPROVAL_MENU_TRIGGER_SELECTOR = '[data-approval-menu-trigger]';
const DASHBOARD_LAYOUT_CONTENT_ID = 'dashboard-layout-content';

const useUsersWithPoliciesQuery = (searchQuery: string) =>
  useQuery(
    timeTrackingKeys.getUsers(searchQuery),
    () => getUsers({ page: 1, limit: 30, search: searchQuery }),
    {
      select: data => data.data.items,
    },
  );

const ApprovalRequests = () => {
  const { t } = useLokaliseTranslation([
    'time_tracker',
    'time_tracking_common',
    'approval_requests',
  ]);
  const [selectedList, setSelectedList] = useState<RequestsList>('pending');
  const { palette } = useTheme();
  const showGeneralError = useGeneralError();
  const [filters, setFilters] = useState<ApprovalFiltersFields | null>(null);
  const [searchParams] = useSearchParams();

  const {
    params,
    Search,
    HuTableSortingHeader: SortingHeader,
    form: paginationForm,
    setPartialParams: setPartialPaginationParams,
  } = useHuPagination({
    defaultPage: 1,
    defaultOrderBy: SortOptions.DATE,
    defaultOrder: 'DESC',
    defaultLimit: 10,
  });
  const { debouncedValue: debouncedSearch } = useDebounce(params.search);

  // Fetch segmentation groups
  const { data: segmentationGroups = [], isLoading: isLoadingSegmentations } =
    useQuery(feedKeys.segmentate.groups(), () => getSegmentationGroups(), {
      select: response => {
        const parseItems = (segmentation: Segmentation) =>
          segmentation.items.map(i => ({
            label: i.name,
            value: i.id,
            checked: false,
          }));
        return response.data.reduce<SegmentationGroup[]>((acc, cur) => {
          if (cur.items.length) {
            acc.push({
              name: cur.name,
              value: cur.id,
              items: parseItems(cur),
            });
          }
          return acc;
        }, []);
      },
      onError: error => {
        showGeneralError(error, t('error_loading_segmentation_groups'));
      },
    });

  // Fetch regions
  const { data: regionsData, isLoading: isLoadingRegions } = useQuery(
    timeTrackingKeys.regions(),
    () => getRegions({ page: 1, limit: 300 }),
    {
      select: response =>
        parseGroup(
          response.data.items.map(r => ({
            id: r.id,
            name: r.title,
            items: r.sites || [],
          })),
        ),
      onError: error => {
        showGeneralError(error, t('REGIONS_ERROR'));
      },
    },
  );

  // Fetch hour categories
  const { data: hourCategoriesData, isLoading: isLoadingHourCategories } =
    useQuery(
      timeTrackingKeys.hourCategories(),
      () => getHourCategories({ page: 1, limit: 100, search: '' }),
      {
        select: response => response.data.items,
        onError: error => {
          showGeneralError(error, t('error_loading_hour_categories'));
        },
      },
    );

  // Users total count for filter drawer description
  const { data: usersTotalCount } = useQuery(
    [...timeTrackingKeys.getUsers(''), 'count'],
    () => getUsers({ page: 1, limit: 1, search: '' }),
    {
      select: data => data.data.count,
    },
  );

  const selection = useApprovalSelection();

  // Filter drawer
  const { showFiltersDrawer, filtersDrawer } = useApprovalFiltersDrawer({
    segmentationGroups,
    isLoadingSegmentations,
    regions: regionsData || [],
    isLoadingRegions,
    hourCategories: hourCategoriesData || [],
    isLoadingHourCategories,
    usersQuery: useUsersWithPoliciesQuery,
    usersTotalCount: usersTotalCount ?? 0,
    initialValues: filters || undefined,
    onValuesChange: (v: ApprovalFiltersFields) => {
      setFilters(v);
      selection.reset();
    },
  });

  // Memoize so the query key only changes when applied filters/params change.
  // Without this, parent re-renders (e.g. from form.watch() in the drawer) would
  // create a new object reference and trigger refetch even before clicking Apply.
  const categorizedHoursParams = useMemo<CategorizedHoursParams>(
    () => ({
      status:
        selectedList === 'pending'
          ? TimeTrackingCategorizedHourStatus.PENDING
          : [
              TimeTrackingCategorizedHourStatus.APPROVED,
              TimeTrackingCategorizedHourStatus.REJECTED,
              TimeTrackingCategorizedHourStatus.AUTO_APPROVED,
              TimeTrackingCategorizedHourStatus.IN_PROGRESS,
            ].join(),
      search: debouncedSearch,
      page: 1,
      limit: params.pagination.limit,
      sortBy: params.orderBy || undefined,
      sortOrder: params.order.includes('DESC') ? 'desc' : 'asc',
      ...(filters?.users &&
        filters.users.length > 0 && {
          userIds: filters.users.map(u => u.value).join(','),
        }),
      ...(filters?.startDate && {
        startDate: format(filters.startDate, 'yyyy-MM-dd'),
      }),
      ...(filters?.endDate && {
        endDate: format(filters.endDate, 'yyyy-MM-dd'),
      }),
      ...(filters?.hourCategoryIds && {
        hourCategoryIds: Object.entries(filters.hourCategoryIds)
          .filter(([_, checked]) => checked)
          .map(([key]) => Number(key))
          .join(','),
      }),
      ...(filters?.segmentationItems && {
        itemIds: Object.entries(filters.segmentationItems)
          .filter(([_, checked]) => checked)
          .map(([key]) => Number(key))
          .join(','),
      }),
      ...(filters?.siteIds && {
        siteIds: Object.entries(filters.siteIds)
          .filter(([_, checked]) => checked)
          .map(([key]) => Number(key))
          .join(','),
      }),
    }),
    [
      selectedList,
      debouncedSearch,
      params.pagination.limit,
      params.orderBy,
      params.order,
      filters,
    ],
  );

  const {
    data: infiniteRegisters,
    isLoading,
    isError,
    isFetching,
    hasNextPage,
    fetchNextPage,
  } = useInfiniteQuery({
    queryKey: timeTrackingKeys.categorizedHoursRequests(categorizedHoursParams),
    queryFn: ({ pageParam = 1 }) =>
      getCategorizedHoursRequests({
        ...categorizedHoursParams,
        page: pageParam,
      }),
    getNextPageParam: lastPage => lastPage?.data.page + 1,
  });

  const requests = useMemo(
    () => infiniteRegisters?.pages?.flatMap(page => page.data.items) || [],
    [infiniteRegisters?.pages],
  );
  const hasData = !!requests?.length;

  const isPendingTab = selectedList === 'pending';
  const visibleIds = useMemo(() => requests.map(r => r.id), [requests]);
  // Memoized so the O(n) scan over visibleIds only runs when selection state
  // or the visible row set actually changes — not on every parent re-render.
  const headerSelectionState = useMemo(
    () => selection.getHeaderState(visibleIds),
    [selection.getHeaderState, visibleIds],
  );

  const categoryCountsFilters = useMemo(() => {
    const { page, limit, sortBy, sortOrder, ...rest } = categorizedHoursParams;
    return rest;
  }, [categorizedHoursParams]);
  const { data: categoryCountsData } = useGetCategorizedHoursCategoryCounts(
    categoryCountsFilters,
    isPendingTab,
  );
  const totalMatchingCount = categoryCountsData?.total ?? 0;

  const bulkSelectedCount = selection.allRows
    ? Math.max(0, totalMatchingCount - selection.excludedIds.size)
    : selection.selectedIds.size;

  const bulkBreakdown = useMemo(
    () =>
      getBulkReviewBreakdown({
        allRows: selection.allRows,
        selectedIds: selection.selectedIds,
        excludedIds: selection.excludedIds,
        requests,
        categoryCounts: categoryCountsData?.hourCategoryCounts,
      }),
    [
      selection.allRows,
      selection.selectedIds,
      selection.excludedIds,
      requests,
      categoryCountsData?.hourCategoryCounts,
    ],
  );

  useApprovalSelectionLifecycle({
    selection,
    debouncedSearch,
    orderBy: params.orderBy,
    order: params.order,
    totalMatchingCount,
  });

  // Use debouncedSearch (not params.search) so this matches what the query
  // actually reflects — otherwise clearing the search input flips
  // hasActiveFilters off before the new data lands, briefly swapping the
  // inner empty state for the outer one and hiding the table header.
  const hasActiveFilters =
    !!debouncedSearch ||
    !!(
      filters &&
      (filters.users.length > 0 ||
        filters.startDate !== null ||
        filters.endDate !== null ||
        Object.values(filters.hourCategoryIds || {}).some(Boolean) ||
        Object.values(filters.segmentationItems || {}).some(Boolean) ||
        Object.values(filters.siteIds || {}).some(Boolean))
    );
  const showInnerEmptyState = Boolean(
    !isLoading && !isError && !hasData && hasActiveFilters,
  );
  const showOuterEmptyState = Boolean(
    !isLoading && !hasData && !hasActiveFilters,
  );

  const { showSuccessEmptyState, markResolved, getWasLastPendingResolution } =
    useResolvedLastPendingState({
      requests,
      isFetching,
      selectedList,
      hasActiveFilters,
    });

  const appliedFiltersCount = useMemo(() => {
    if (!filters) return 0;
    let count = 0;
    if (filters.users.length > 0) count++;
    if (filters.startDate || filters.endDate) count++;
    if (Object.values(filters.hourCategoryIds || {}).some(Boolean)) count++;
    if (Object.values(filters.segmentationItems || {}).some(Boolean)) count++;
    if (Object.values(filters.siteIds || {}).some(Boolean)) count++;
    return count;
  }, [filters]);

  const { drawer: ApprovalDrawer, showApprovalDetailDrawer } =
    useApprovalDetailDrawer({
      getWasLastPendingResolution,
      onResolveSuccess: markResolved,
    });

  const deeplinkCategorizedHourId = searchParams.get('categorizedHourId');

  const { enqueueSnackbar } = useHuSnackbar();
  const reviewMutation = useReviewCategorizedHourApprovalStep();

  const [menuAnchorEl, setMenuAnchorEl] = useState<null | HTMLElement>(null);
  const [selectedRequest, setSelectedRequest] = useState<{
    id: string;
    status: ApprovableStatus;
    approvalStepId: number | string | null;
  } | null>(null);
  const [bulkMenuStatus, setBulkMenuStatus] = useState<ApprovableStatus | null>(
    null,
  );
  const [note, setNote] = useState('');
  const isBulkMenu = bulkMenuStatus != null;

  const handleOpenMenu = (
    event: React.MouseEvent<HTMLElement>,
    requestId: string,
    status: ApprovableStatus,
    currentStepId: number | string | null | undefined,
  ) => {
    setBulkMenuStatus(null);
    setSelectedRequest({
      id: requestId,
      status,
      approvalStepId: resolveStepId(currentStepId),
    });
    setNote('');
    setMenuAnchorEl(event.currentTarget);
  };

  const handleOpenBulkMenu = (
    event: React.MouseEvent<HTMLElement>,
    status: ApprovableStatus,
  ) => {
    setSelectedRequest(null);
    setBulkMenuStatus(status);
    setNote('');
    setMenuAnchorEl(event.currentTarget);
  };

  const handleMenuClose = (
    _event: unknown,
    reason: 'backdropClick' | 'escapeKeyDown',
  ) => {
    if (reason === 'backdropClick') {
      const target = (_event as { target?: EventTarget })?.target as
        | HTMLElement
        | undefined;
      if (target?.closest?.(APPROVAL_MENU_TRIGGER_SELECTOR)) return;
    }
    setMenuAnchorEl(null);
    setBulkMenuStatus(null);
  };

  // Confirm from menu popover. For bulk flow, hands off to the confirmation
  // dialog (the actual mutation lands in step 5). For single flow, runs the
  // existing per-row review mutation.
  const handleConfirmAction = () => {
    if (isBulkMenu && bulkMenuStatus) {
      const status = bulkMenuStatus;
      setMenuAnchorEl(null);
      setBulkMenuStatus(null);
      bulkDialog.openFor(status);
      return;
    }
    if (!selectedRequest) return;
    if (selectedRequest.approvalStepId == null) {
      enqueueSnackbar({
        title: t('approval_requests:feedback.request_modified_error'),
        description: t(
          'approval_requests:feedback.request_modified_error_description',
        ),
        variant: 'error',
      });
      return;
    }

    const wasLastPendingResolution = getWasLastPendingResolution(
      selectedRequest.id,
    );

    reviewMutation.mutate(
      {
        categorizedHourId: selectedRequest.id,
        approvalStepId: selectedRequest.approvalStepId,
        state: selectedRequest.status,
        comment: note || undefined,
      },
      {
        onSuccess: () => {
          setMenuAnchorEl(null);
          setSelectedRequest(null);
          setNote('');
          markResolved(wasLastPendingResolution);
          enqueueSnackbar({
            title: t('approval_requests:feedback.request_modified'),
            variant: 'success',
          });
        },
        onError: () => {
          enqueueSnackbar({
            title: t('approval_requests:feedback.request_modified_error'),
            description: t(
              'approval_requests:feedback.request_modified_error_description',
            ),
            variant: 'error',
          });
        },
      },
    );
  };

  const bulkReview = useBulkReviewSubmit({
    selection,
    filters: categoryCountsFilters,
    onSuccess: () => {
      setNote('');
      selection.reset();
      bulkDialog.close();
    },
  });

  const bulkDialog = useBulkReviewDialog({
    bulkSelectedCount,
    breakdown: bulkBreakdown,
    isSubmitting: bulkReview.isLoading,
    onConfirm: status =>
      bulkReview.submit({ state: status, comment: note || undefined }),
    onClose: () => {
      setNote('');
    },
  });

  const handleShowRequestDetails = (requestId: string) => {
    showApprovalDetailDrawer(requestId);
  };

  const handleSelectListing = (list: RequestsList) => {
    refetchCategorizedHoursPending();
    setSelectedList(list);
    selection.reset();
    // Reset orderBy to date because status column does not apply in pending list
    if (list === 'pending' && params.orderBy === SortOptions.STATUS) {
      setPartialPaginationParams(
        {
          order: 'DESC',
          orderBy: SortOptions.DATE,
        },
        true,
      );
    }
  };

  const HEADER_BACKGROUND = palette.new.background.elements.grey;

  /** Must match between SortingHeader and body cells for aligned sticky columns. */
  const statusColumnWidth = selectedList === 'pending' ? 320 : 120;

  const emptyStateProps = showSuccessEmptyState
    ? {
        title: t('approval_requests:no_pending_requests'),
        description: t('approval_requests:no_pending_requests_description'),
        variant: 'success' as const,
      }
    : {
        title: t('approval_requests:no_requests_found'),
        description: t('approval_requests:no_requests_found_description'),
        icon: IconInfoCircle,
      };

  useEffect(() => {
    if (deeplinkCategorizedHourId)
      showApprovalDetailDrawer(deeplinkCategorizedHourId);
    // eslint-disable-next-line react-hooks/exhaustive-deps Only show on mount or when the id changes
  }, [deeplinkCategorizedHourId]);

  return (
    <>
      {ApprovalDrawer}
      {filtersDrawer}
      <CardContainer fullWidth>
        <Title
          variant="M"
          title={t('approval_requests:requests')}
          sx={{ mb: 1 }}
        />
        <FormProvider {...paginationForm}>
          <Stack
            sx={{
              alignItems: 'center',
              flexDirection: 'row',
              gap: 1,
              mb: 4,
            }}
          >
            <Search
              inputProps={{
                placeholder: t('approval_requests:search_request'),
              }}
            />
            <Chip
              label={t('general:pendings')}
              isSelected={selectedList === 'pending'}
              onClick={() => {
                handleSelectListing('pending');
              }}
            />
            <Chip
              label={t('approval_requests:processed')}
              isSelected={selectedList === 'processed'}
              onClick={() => {
                handleSelectListing('processed');
              }}
            />
            <IconButton
              aria-label={t('general:filter')}
              variant="secondary"
              onClick={() => {
                showFiltersDrawer({});
              }}
            >
              <IconFilter />
              {appliedFiltersCount > 0 && (
                <Badge
                  color="primary"
                  badgeContent={appliedFiltersCount}
                  sx={{ position: 'absolute', top: 0, right: 0 }}
                />
              )}
            </IconButton>
          </Stack>
          {isPendingTab && (
            <BulkSelectionBar
              selectedCount={bulkSelectedCount}
              totalCount={totalMatchingCount}
              isAllRows={selection.allRows}
              onSelectAllAcross={selection.selectAllAcrossFilters}
              onDeselectAll={selection.deselectAll}
              onApproveClick={event =>
                handleOpenBulkMenu(
                  event,
                  TimeTrackingCategorizedHourStatus.APPROVED,
                )
              }
              onRejectClick={event =>
                handleOpenBulkMenu(
                  event,
                  TimeTrackingCategorizedHourStatus.REJECTED,
                )
              }
            />
          )}
          {showOuterEmptyState && <StateCard {...emptyStateProps} />}
          {!isError && (isLoading || hasData || showInnerEmptyState) && (
            <TableContainer
              sx={{
                backgroundColor: palette.new.background.layout.tertiary,
                mb: 1,
                zIndex: 0,
                ...(isPendingTab && bulkSelectedCount > 0
                  ? { borderTopLeftRadius: 0, borderTopRightRadius: 0 }
                  : {}),
              }}
            >
              <Table sx={{ tableLayout: 'fixed', minWidth: 1135 }}>
                <TableHead
                  sx={{
                    position: 'sticky',
                    top: 0,
                    zIndex: 1,
                    borderColor: palette.new.border.neutral.default,
                  }}
                >
                  <TableRow
                    sx={{
                      '& > *': {
                        backgroundColor: HEADER_BACKGROUND,
                      },
                    }}
                    headerRow
                  >
                    {isPendingTab && (
                      <TableCell
                        sx={{
                          ...STICKY_LEFT_SX,
                          width: CHECKBOX_COLUMN_WIDTH,
                          zIndex: 3,
                        }}
                        headerCell
                      >
                        {!showInnerEmptyState && (
                          <Checkbox
                            checked={headerSelectionState.checked}
                            indeterminate={headerSelectionState.indeterminate}
                            onClick={() => selection.toggleHeader(visibleIds)}
                            disabled={!hasData}
                          />
                        )}
                      </TableCell>
                    )}
                    <TableCell
                      sx={{
                        ...STICKY_LEFT_SX,
                        left: isPendingTab ? CHECKBOX_COLUMN_WIDTH : 0,
                        width: 280,
                        zIndex: 3,
                        boxShadow: `inset -1px 0 0 0 ${palette.new.border.neutral.default}`,
                      }}
                      headerCell
                    >
                      {t('approval_requests:requester')}
                    </TableCell>
                    <TableCell
                      sx={{ width: FIXED_CELL_WIDTH }}
                      headerCell
                    >
                      {t('approval_requests:request.type')}
                    </TableCell>
                    <SortingHeader
                      id={SortOptions.DATE}
                      {...(params.orderBy === SortOptions.DATE && {
                        tooltipTitle:
                          params.order === 'ASC'
                            ? t('approval_requests:sorting.oldest_to_newest')
                            : t('approval_requests:sorting.newest_to_oldest'),
                      })}
                      disabled={showInnerEmptyState}
                      sx={{ width: FIXED_CELL_WIDTH }}
                    >
                      {t('approval_requests:request.day')}
                    </SortingHeader>
                    <SortingHeader
                      id={SortOptions.HOURS}
                      disabled={showInnerEmptyState}
                      sx={{ width: FIXED_CELL_WIDTH }}
                    >
                      {t('approvals.hours_to_approve')}
                    </SortingHeader>
                    <SortingHeader
                      id={SortOptions.STATUS}
                      disabled={
                        selectedList === 'pending' || showInnerEmptyState
                      }
                      sx={{
                        ...STICKY_RIGHT_SX,
                        right: 72,
                        width: statusColumnWidth,
                      }}
                    >
                      {t(
                        selectedList === 'pending'
                          ? 'general:action_label'
                          : 'general:state',
                      )}
                    </SortingHeader>
                    <TableCell
                      aria-label={t('general:detail')}
                      sx={{
                        ...STICKY_RIGHT_SX,
                        width: 72,
                      }}
                      headerCell
                    />
                  </TableRow>
                </TableHead>
                <TableBody
                  sx={{
                    overflow: 'auto',
                    border: 'none',
                    transition:
                      'opacity 0.25s ease-in-out, transform 0.25s ease-in-out',
                    backgroundColor: theme =>
                      theme.palette.new.background.layout.tertiary,
                  }}
                >
                  {isLoading && (
                    <ListSkeleton cellsCount={isPendingTab ? 7 : 6} />
                  )}
                  {showInnerEmptyState && (
                    <TableRow>
                      <TableCell
                        colSpan={isPendingTab ? 7 : 6}
                        sx={{ p: 0 }}
                      >
                        <StateCard
                          title={t('approval_requests:no_requests_found')}
                          description={t(
                            'approval_requests:no_requests_found_description',
                          )}
                          icon={IconInfoCircle}
                          slotProps={{
                            card: {
                              sx: { border: 'none', borderRadius: 0 },
                            },
                          }}
                        />
                      </TableCell>
                    </TableRow>
                  )}
                  {!isLoading &&
                    hasData &&
                    requests?.map((request, index) => (
                      <ApprovalRequestRow
                        key={request.id}
                        request={request}
                        index={index}
                        isPendingTab={isPendingTab}
                        selectedList={selectedList}
                        statusColumnWidth={statusColumnWidth}
                        isSelected={
                          isPendingTab && selection.isRowSelected(request.id)
                        }
                        onToggleSelect={() => selection.toggleRow(request.id)}
                        onOpenMenu={(e, status) =>
                          handleOpenMenu(
                            e,
                            request.id,
                            status,
                            request.currentStepId,
                          )
                        }
                        onShowDetails={() =>
                          handleShowRequestDetails(request.id)
                        }
                      />
                    ))}
                </TableBody>
              </Table>
            </TableContainer>
          )}
          {!isLoading && hasData && (
            <TableLoader
              loadedCount={requests?.length || 0}
              onScrollToTop={() => {
                const dashboardContent = document.getElementById(
                  DASHBOARD_LAYOUT_CONTENT_ID,
                );
                if (dashboardContent) {
                  dashboardContent.scrollTo({ top: 0, behavior: 'smooth' });
                  return;
                }
                window.scrollTo({ top: 0, behavior: 'smooth' });
              }}
              slotProps={{
                button: {
                  loading: isFetching,
                  disabled: !hasNextPage,
                },
              }}
              onLoadMore={fetchNextPage}
              totalCount={infiniteRegisters?.pages[0]?.data?.count || 0}
            />
          )}
        </FormProvider>
      </CardContainer>
      <ApprovalReasonMenu
        anchorEl={menuAnchorEl}
        status={isBulkMenu ? bulkMenuStatus : selectedRequest?.status}
        note={note}
        isConfirming={!isBulkMenu && reviewMutation.isLoading}
        onNoteChange={setNote}
        onCancel={() => {
          setMenuAnchorEl(null);
          setBulkMenuStatus(null);
        }}
        onConfirm={handleConfirmAction}
        onClose={handleMenuClose}
      />
    </>
  );
};

export default ApprovalRequests;
