import React, { useEffect, useState } from 'react';
import { useReactiveVar } from '@apollo/client';
import { Alert } from '@theorchard/suite-components';
import { isEmpty } from 'lodash-es';
import getErrorBody from 'src/apollo/errors';
import {
    useNRContributorsList,
    useNRContributorSearch,
} from 'src/apollo/queries/nr-contributors';
import paginationStateVar from 'src/apollo/reactive-vars/tables-state';
import {
    sortByColumn,
    sortDirection,
} from 'src/apollo/type-constants/schedule';
import ContributorScheduleFilters from 'src/components/contributor-schedule-list/contributor-schedule-filters';
import ContributorScheduleTable from 'src/components/contributor-schedule-list/contributor-schedule-table';
import { DEFAULT_ITEMS_PER_PAGE } from 'src/constants';
import usePagination from 'src/hooks/pagination';
import { reorderSchedulesList } from 'src/utils/schedules';
import type { GetNRContributorsListQuery } from 'src/apollo/queries/nr-contributors/__generated__/get-nr-contributors';
import './styles.scss';

type NrContributors = NonNullable<GetNRContributorsListQuery['nrContributors']>;
type NRContributor = NrContributors['contributors'] extends (infer T)[] | null
    ? T
    : null;

export const ContributorScheduleList: React.FC = () => {
    const itemsPerPage = DEFAULT_ITEMS_PER_PAGE;
    const [contributorList, setContributorList] = useState<NRContributor[]>([]);
    const [resultsCount, setResultsCount] = useState<number>(0);
    const [isFiltered, setIsFiltered] = useState<boolean>(false);
    const [errors, setErrors] = useState<any>([]);
    const [filterValues, setFilterValues] = useState<any>({
        limit: itemsPerPage,
        offset: 0,
        orderBy: sortByColumn['name'],
        orderDir: sortDirection['asc'],
    });
    const paginationState = useReactiveVar<any>(paginationStateVar);
    const {
        data: nrContributorsList,
        error,
        loading: nrContributorsListLoading,
        getNRContributors,
    } = useNRContributorsList();
    const {
        data: nrContributorSearchResults,
        error: searchError,
        loading: nrContributorSearchLoading,
        getNRContributorSearchResult,
    } = useNRContributorSearch();

    const changeHandler = (e: any) => {
        const {
            target: { name, value },
        } = e;
        setErrors({});
        setIsFiltered(false);
        if (name === 'hasUnassignedContributionsCount')
            setFilterValues({
                ...filterValues,
                filters: { [name]: value },
                offset: 0,
            });
        else setFilterValues({ ...filterValues, [name]: value, offset: 0 });
    };

    const clearAllFilters = () => {
        setFilterValues({
            limit: itemsPerPage,
            offset: 0,
            orderBy: filterValues.orderBy,
            orderDir: filterValues.orderDir,
        });
        setIsFiltered(false);
        setErrors({});
    };

    const fetchMoreWrapper = ({ variables: { limit, offset } }: any) => {
        const variables = { ...filterValues, limit, offset };
        setFilterValues(variables);
    };

    const { renderPagination } = usePagination({
        fetchMore: fetchMoreWrapper,
        totalItemCount: resultsCount,
        itemsPerPage,
        tableId: 'contributor-schedule-list',
    });

    const formatContributorList = (items: NRContributor[] | [] | null) => {
        const contributors = items
            ? items.map((contributor: NRContributor) => {
                  const {
                      id,
                      name,
                      abacusUnassignedContributionsCount,
                      abacusSchedules,
                  } = contributor;
                  return {
                      id,
                      name,
                      abacusUnassignedContributionsCount,
                      abacusSchedules: reorderSchedulesList(abacusSchedules),
                  };
              })
            : [];
        setContributorList(contributors);
    };

    const hasFilterApplied = () =>
        filterValues?.contributorName ||
        filterValues?.filters?.hasUnassignedContributionsCount;

    useEffect(() => {
        if (error || searchError) {
            setErrors({
                serverError: getErrorBody(error) || getErrorBody(searchError),
            });
            formatContributorList([]);
            setResultsCount(0);
        }
    }, [error, searchError]);

    useEffect(() => {
        let variables = { ...filterValues };
        if (hasFilterApplied()) {
            const { contributorName, filters, offset, orderBy, orderDir } =
                filterValues;
            variables = {
                term: contributorName ? contributorName : '',
                limit: itemsPerPage,
                filters,
                offset,
                orderBy: contributorName ? null : orderBy,
                orderDir: contributorName ? null : orderDir,
            };
            getNRContributorSearchResult(variables);
        } else getNRContributors(variables);
    }, [filterValues]);

    useEffect(() => {
        let nrContributors;
        let filtered = false;
        const isFiltered = hasFilterApplied();
        if (nrContributorsList && !isFiltered)
            nrContributors = nrContributorsList?.nrContributors;

        if (nrContributorSearchResults && isFiltered) {
            nrContributors = nrContributorSearchResults?.nrContributorSearch;
            filtered = true;
        }

        if (nrContributors) {
            formatContributorList(nrContributors?.contributors);
            setResultsCount(nrContributors?.totalCount);
            setIsFiltered(filtered);
        }
    }, [
        nrContributorsList,
        nrContributorSearchResults,
        nrContributorsListLoading,
        nrContributorSearchLoading,
    ]);

    useEffect(() => {
        paginationStateVar({
            ...paginationState,
            'contributor-schedule-list': 1,
        });
    }, [isFiltered]);

    return (
        <div className="ContributorScheduleList">
            {!isEmpty(errors.serverError) && (
                <Alert
                    variant="error"
                    text={
                        <div>
                            <span className="errorMessage">
                                Something went wrong.
                            </span>
                            <br />
                            {errors.serverError[0].message ||
                                JSON.stringify(errors.serverError)}
                        </div>
                    }
                />
            )}
            <ContributorScheduleFilters
                changeHandler={changeHandler}
                clearFilters={clearAllFilters}
                filterValues={filterValues}
                isFiltered={isFiltered}
                setFilterValues={setFilterValues}
            />
            <div className="ContributorScheduleList-result-count">
                {isFiltered && (
                    <div>
                        <span className="SearchableList-result-count-label">
                            Results:
                        </span>
                        <span className="SearchableList-result-count-value">
                            {` ${resultsCount}`}
                        </span>
                    </div>
                )}
                <ContributorScheduleTable
                    contributorList={contributorList}
                    renderPagination={renderPagination}
                    isLoading={
                        nrContributorsListLoading || nrContributorSearchLoading
                    }
                    filterValues={filterValues}
                    setFilterValues={setFilterValues}
                />
            </div>
        </div>
    );
};

export default ContributorScheduleList;
