import React, { useCallback, useEffect, useMemo } from 'react';
import { Id, PurchaseOrderDetails, PurchaseOrdersListResponse, PurchaseOrdersProvider } from 'backend-api/models';
import { PurchaseOrderFilterParams, PurchaseOrderSortField } from 'backend-api/types';
import { PurchaseOrdersTable } from '../components/table';
import { usePurchaseOrdersFilters } from '../hooks/use-purchase-orders-filters';
import { BreakdownValuesByEntityId, FiltersSelectorType, UpdateFiltersType } from '../types';
import { usePagination } from 'hooks';
import { DEFAULT_SORT } from '../constants';
import { getPurchaseOrdersFiltersParamsFromSearchQuery } from '../transducers';
import { useLocation } from 'react-router-dom';
import { getSearchParamsFromLocation } from 'utils/navigation';
import { PurchaseOrdersHeader } from '../components/purchase-orders-header';
import { TableTheme } from 'app/theme/table';
import { ALL_OPTION_ID } from 'common/components/form/select/constants';
import { Sort } from 'utils/sort';
import { debounce } from 'lodash';
import { SEARCH_DEBOUNCE_TIME } from 'common/constants';
import { useSelector } from 'react-redux';
import { activeProjectSelector } from 'common/selectors';

interface Props {
  projectId: Id;
  purchaseOrderId?: Id;
  filterUpdateAction: UpdateFiltersType;
  filtersSelector: FiltersSelectorType;
  purchaseOrdersResponse?: PurchaseOrdersListResponse;
  onRequestData(params: PurchaseOrderFilterParams): void;
  isLoading?: boolean;
  isLoadingFailed?: boolean;
  providers: PurchaseOrdersProvider[];
  breakdowns?: BreakdownValuesByEntityId;
  onExpandItem?: (item: PurchaseOrderDetails, isExpanded: boolean, params: PurchaseOrderFilterParams) => void;
  onExportClick?: () => void;
  onSortClick?: (sort: Sort<PurchaseOrderSortField>) => void;
  className?: string;
  currencyCode?: string;
}

export const PurchaseOrders = React.memo(
  React.forwardRef<HTMLDivElement, Props>(
    (
      {
        projectId,
        purchaseOrderId,
        filtersSelector,
        filterUpdateAction,
        purchaseOrdersResponse,
        isLoading,
        isLoadingFailed,
        onRequestData,
        providers,
        breakdowns,
        onExpandItem,
        onExportClick,
        onSortClick,
        className,
        currencyCode,
      }: Props,
      ref
    ) => {
      const [filters, filtersDispatcher] = usePurchaseOrdersFilters(
        projectId,
        filterUpdateAction,
        filtersSelector,
        purchaseOrderId
      );

      const project = useSelector(activeProjectSelector);
      const isUnassigned = !!project && project.isClaimed;

      const pagination = usePagination(filters, purchaseOrdersResponse?.total);
      const sort = useMemo(() => filters.sort || DEFAULT_SORT, [filters.sort]);
      const status = useMemo(() => (filters.status === undefined ? ALL_OPTION_ID : filters.status), [filters.status]);
      const provider = useMemo(() => (filters.provider === undefined ? ALL_OPTION_ID : filters.provider), [
        filters.provider,
      ]);
      const location = useLocation();

      const isBlanketPOChildrenTable = purchaseOrderId !== undefined;
      const isTableEmpty = !purchaseOrdersResponse?.items || purchaseOrdersResponse.items.length === 0;
      const search = useMemo(() => getSearchParamsFromLocation(location), [location]);
      const params = useMemo(() => getPurchaseOrdersFiltersParamsFromSearchQuery(search), [search]);
      useEffect(() => {
        onRequestData(params);
      }, [params, onRequestData]);

      const onExpandClick = useCallback(
        (item: PurchaseOrderDetails, isExpanded: boolean) => {
          // eslint-disable-next-line @typescript-eslint/no-unused-vars
          const { offset, ...rest } = params;
          onExpandItem && onExpandItem(item, isExpanded, rest);
        },
        [params, onExpandItem]
      );

      const changeStatus = useCallback(
        (statusId: number) => {
          filtersDispatcher.setFilters({ status: statusId === ALL_OPTION_ID ? undefined : statusId, offset: 0 });
        },
        [filtersDispatcher]
      );

      const changeProvider = useCallback(
        (providerId: number) => {
          filtersDispatcher.setFilters({ provider: providerId === ALL_OPTION_ID ? undefined : providerId, offset: 0 });
        },
        [filtersDispatcher]
      );

      const debouncedSearch = useCallback(
        debounce(
          (search: string) => filtersDispatcher.setFilters({ search: search || undefined, offset: 0 }),
          SEARCH_DEBOUNCE_TIME
        ),
        [filtersDispatcher]
      );

      const changeSearch = useCallback((search: string) => debouncedSearch(search), [debouncedSearch]);

      const sortChanged = useCallback(
        (sort: Sort<PurchaseOrderSortField>) => {
          filtersDispatcher.setSort(sort);
          onSortClick && onSortClick(sort);
        },
        [onSortClick, filtersDispatcher]
      );

      return (
        <div ref={ref} className={className}>
          <PurchaseOrdersHeader
            onSearchChange={changeSearch}
            onExportClick={onExportClick}
            providers={providers}
            onProviderChange={changeProvider}
            selectedProvider={provider}
            selectedStatus={status}
            onStatusChange={changeStatus}
            isBlanketPOTableHeader={isBlanketPOChildrenTable}
            purchaseOrdersCount={purchaseOrdersResponse?.items.length}
            isTableEmpty={isTableEmpty}
          />
          <PurchaseOrdersTable
            projectId={projectId}
            sort={sort}
            onSortChange={sortChanged}
            pagination={pagination}
            onPaginationChange={filtersDispatcher.setPagination}
            search={filters.search}
            breakdowns={breakdowns}
            onExpandItem={onExpandClick}
            isLoading={isLoading}
            isUnassigned={isUnassigned}
            isLoadingFailed={isLoadingFailed}
            purchaseOrders={purchaseOrdersResponse?.items || []}
            theme={isBlanketPOChildrenTable ? TableTheme.GREY : TableTheme.WHITE}
            currencyCode={currencyCode}
          />
        </div>
      );
    }
  )
);
