import React, { useCallback, useEffect, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Artist, ArtistRosterProject, ProjectDetails } from 'backend-api/models';
import { Table } from '../components/table';
import { PartialLoadingState } from 'common/types';
import { Sort } from 'utils/sort';
import { getAssignableCampaigns, setSelectedCampaigns, updateCampaignsFilters } from '../actions';
import {
  campaignsFiltersSelector,
  campaignsSelector,
  campaignsTotalCountSelector,
  selectedCampaignsSelector,
} from '../selectors';
import { SortField } from '../types';
import { getDefaultSearchTerm } from '../transducers';
import uniqBy from 'lodash/uniqBy';
import { UUID } from 'io-ts-types/lib/UUID';

interface Props {
  project: ProjectDetails | ArtistRosterProject;
  primaryArtist?: Artist;
}

export const BulkCampaignsAssignmentTableContainer = React.memo(({ project, primaryArtist }: Props) => {
  const dispatch = useDispatch();

  const { data: campaigns, loading: campaignsLoading } = useSelector(campaignsSelector);
  const campaignsTotalCount = useSelector(campaignsTotalCountSelector);
  const campaignsFilters = useSelector(campaignsFiltersSelector);
  const selectedCampaigns = useSelector(selectedCampaignsSelector);

  const updateSortFilter = useCallback(
    (sort: Sort<SortField>) => {
      dispatch(updateCampaignsFilters({ sort }));
    },
    [dispatch]
  );

  const fetchCampaigns = useCallback(
    (isInfinite = false, offset = 0) => {
      dispatch(
        getAssignableCampaigns.request({
          projectId: project.id,
          isInfinite,
          filters: {
            sort: campaignsFilters.sort.getString(),
            offset,
            freeText: campaignsFilters.search || undefined,
          },
        })
      );
    },
    [project.id, campaignsFilters, dispatch]
  );

  const infiniteScrollSettings = useMemo(
    () => ({
      isActive: campaignsTotalCount > campaigns.length,
      isLoading: campaignsLoading === PartialLoadingState.StartedPartial,
      onScrollEnd: () => fetchCampaigns(true, campaigns.length),
    }),
    [campaigns.length, campaignsLoading, campaignsTotalCount, fetchCampaigns]
  );

  useEffect(() => {
    const search = getDefaultSearchTerm(project, primaryArtist);
    dispatch(updateCampaignsFilters({ search }));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    fetchCampaigns();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [campaignsFilters]);

  const selectedCampaignUuids = useMemo(() => selectedCampaigns.map(({ uuid }) => uuid), [selectedCampaigns]);

  const onCheckCampaign = useCallback(
    (isChecked: boolean, uuid: UUID) => {
      const selectedCampaign = campaigns.find(campaign => campaign.uuid === uuid);
      if (!selectedCampaign) return;

      const newSelectedIds = isChecked
        ? uniqBy(selectedCampaigns.concat(selectedCampaign), item => item.uuid)
        : selectedCampaigns.filter(selected => selectedCampaign.uuid !== selected.uuid);
      dispatch(setSelectedCampaigns(newSelectedIds));
    },
    [campaigns, dispatch, selectedCampaigns]
  );

  const onSelectedAll = useCallback(
    (isChecked: boolean) => {
      const newSelectedUuids = isChecked
        ? uniqBy(selectedCampaigns.concat(campaigns), item => item.uuid)
        : selectedCampaigns.filter(selected => !campaigns.some(campaign => campaign.uuid === selected.uuid));
      dispatch(setSelectedCampaigns(newSelectedUuids));
    },
    [selectedCampaigns, dispatch, campaigns]
  );

  return (
    <Table
      campaigns={campaigns}
      isLoading={campaignsLoading === PartialLoadingState.Started}
      infiniteScroll={infiniteScrollSettings}
      sort={campaignsFilters.sort}
      onSortChange={updateSortFilter}
      onCheckItem={onCheckCampaign}
      onSelectedAll={onSelectedAll}
      checkedIds={selectedCampaignUuids}
      currencyCode={project.currency}
    />
  );
});
