import React, { useEffect, useState } from 'react';
import { useApolloClient } from '@apollo/client';
import { Alert } from '@theorchard/suite-components';
import { difference } from 'lodash-es';
import { useParams } from 'react-router-dom';
import { useNRContributionsList } from 'src/apollo/queries/nr-contributions';
import {
    sortByColumn,
    sortDirection,
} from 'src/apollo/type-constants/schedule';
import { ContributionItems } from 'src/components/schedule-form/contribution-items';
import { CONTRIBUTIONS_LOADING_ERROR_MSG } from 'src/types/schedule';
import { formatContributions } from 'src/utils/contributions';
import { checkForUUID } from 'src/utils/uuid';
import './styles.scss';

const DEFAULT_PAGE_SIZE = 100;

export interface ContributionsPropTypes {
    contributions: any;
    setContributions: (params: object) => void;
}

export const Contributions: React.FC<ContributionsPropTypes> = ({
    contributions,
    setContributions,
}) => {
    const client = useApolloClient();
    const { contributorId, scheduleId } = useParams<{
        contributorId: string;
        scheduleId: string;
    }>();
    const [filterValues, setFilterValues] = useState<any>({
        assignedContributions: { limit: 100, offset: 0 },
        unassignedContributions: { limit: 100, offset: 0 },
    });
    const [error, setError] = useState<string>('');
    const [fetchAllContributions, setFetchAllContributions] = useState<any>({
        assignedContributions: false,
        unassignedContributions: false,
    });
    const [itemMoveList, setItemMoveList] = useState<any>({
        unassignedContributions: [],
        assignedContributions: [],
    });
    const [undoMovedList, setUndoMovedList] = useState<any>({
        unassignedContributions: [],
        assignedContributions: [],
    });
    const [movingList, setMovingList] = useState<string>('');
    const contributionIdUnassigned = checkForUUID(
        filterValues?.unassignedContributions?.term
    )
        ? filterValues?.unassignedContributions?.term
        : undefined;
    const contributionIdAssigned = checkForUUID(
        filterValues?.assignedContributions?.term
    )
        ? filterValues?.assignedContributions?.term
        : undefined;
    const [selectedContainer, setSelectedContainer] = useState({
        assignedContributions: false,
        unassignedContributions: false,
    });

    const [unassignedFilterItems, setUnassignedFilterItems] = useState<any>([]);
    const [assignedFilterItems, setAssignedFilterItems] = useState<any>([]);

    const [assignedFilterCount, setAssignedFilterCount] = useState<number>(0);
    const [unassignedFilterCount, setUnassignedFilterCount] =
        useState<number>(0);

    const [unassignedItems, setUnassignedItems] = useState<any>([]);
    const [assignedItems, setAssignedItems] = useState<any>([]);
    const [contributionsTotalCount, setContributionsTotalCount] =
        useState<number>(0);
    const [isInitialPageLoading, setIsInitialPageLoading] =
        useState<boolean>(false);

    const {
        data: dataUnassigned,
        loading: loadingUnassigned,
        error: unassignedContributionsError,
        fetchNextExistingPage: fetchNextExistingPageUnassigned,
    } = useNRContributionsList(
        {
            filters: {
                contributorId,
                hasAbacusSchedule: false,
                mainArtist: filterValues?.unassignedContributions?.term,
                recordingTitle: filterValues?.unassignedContributions?.term,
                contributionId: contributionIdUnassigned,
                validContributions: true,
            },
            limit: DEFAULT_PAGE_SIZE,
            offset: 0,
            orderBy: sortByColumn['nrsrNameVersion'],
            orderDir: sortDirection['asc'],
        },
        () => {
            if (fetchAllContributions.unassignedContributions)
                fetchNextExistingPageUnassigned(DEFAULT_PAGE_SIZE);
        }
    );

    const {
        data: dataAssigned,
        loading: loadingAssigned,
        error: assignedContributionsError,
        fetchNextExistingPage: fetchNextExistingPageAssigned,
    } = useNRContributionsList(
        {
            filters: {
                contributorId,
                hasAbacusSchedule: true,
                mainArtist: filterValues?.assignedContributions?.term,
                recordingTitle: filterValues?.assignedContributions?.term,
                contributionId: contributionIdAssigned,
                abacusScheduleId: parseInt(scheduleId, 10),
                validContributions: true,
            },
            limit: DEFAULT_PAGE_SIZE,
            offset: 0,
            orderBy: sortByColumn['nrsrNameVersion'],
            orderDir: sortDirection['asc'],
        },
        () => {
            if (fetchAllContributions.assignedContributions)
                fetchNextExistingPageAssigned(DEFAULT_PAGE_SIZE);
        }
    );

    useEffect(() => {
        setIsInitialPageLoading(true);
    }, []);

    useEffect(() => {
        if (unassignedContributionsError || assignedContributionsError) {
            setError(CONTRIBUTIONS_LOADING_ERROR_MSG);
            setIsInitialPageLoading(false);
        }
    }, [unassignedContributionsError, assignedContributionsError]);

    useEffect(() => {
        const unassignedCount = dataUnassigned?.nrContributions.totalCount || 0;
        const assignedCount = dataAssigned?.nrContributions.totalCount || 0;
        if (
            isInitialPageLoading &&
            (unassignedCount || assignedCount) &&
            !loadingAssigned &&
            !loadingUnassigned
        ) {
            setContributionsTotalCount(unassignedCount + assignedCount);
            setIsInitialPageLoading(false);
        }
    }, [isInitialPageLoading, dataUnassigned, dataAssigned]);

    const moveTo = (value: string) => {
        if (
            value === 'unassignedContributions' &&
            itemMoveList?.unassignedContributions
        ) {
            const { unassignedContributions } = itemMoveList;

            const newAssignedContributions: string[] = [
                ...contributions.assignedContributions,
                ...difference(
                    unassignedContributions,
                    contributions.unassignedContributions
                ),
            ];
            const newUnassignedContributions: string[] = difference(
                contributions.unassignedContributions,
                unassignedContributions
            );
            // Update POST variable
            setContributions({
                assignedContributions: newAssignedContributions,
                unassignedContributions: newUnassignedContributions,
            });
            const newUnassignedCount =
                unassignedItems.length +
                newUnassignedContributions.length -
                newAssignedContributions.length;

            // Update undo list
            setUndoMovedList({
                assignedContributions: unassignedContributions,
            });

            // After moving contributions, if batch count less than default page size then load another batch.
            if (newUnassignedCount <= DEFAULT_PAGE_SIZE)
                fetchNextExistingPageUnassigned(DEFAULT_PAGE_SIZE);
        }

        if (
            value === 'assignedContributions' &&
            itemMoveList?.assignedContributions
        ) {
            const { assignedContributions } = itemMoveList;

            const newUnassignedContributions = [
                ...contributions.unassignedContributions,
                ...difference(
                    assignedContributions,
                    contributions.assignedContributions
                ),
            ];
            const newAssignedContributions = difference(
                contributions.assignedContributions,
                itemMoveList.assignedContributions
            );
            const newAssignedCount =
                assignedItems.length +
                newAssignedContributions.length -
                newUnassignedContributions.length;
            // Update POST variable
            setContributions({
                assignedContributions: newAssignedContributions,
                unassignedContributions: newUnassignedContributions,
            });

            // Update undo list
            setUndoMovedList({
                unassignedContributions: assignedContributions,
            });

            // After moving contributions, if batch count less than 20 then load another batch.
            if (newAssignedCount <= DEFAULT_PAGE_SIZE)
                fetchNextExistingPageAssigned(DEFAULT_PAGE_SIZE);
        }

        setSelectedContainer({
            assignedContributions: false,
            unassignedContributions: false,
        });
        setItemMoveList({ ...itemMoveList, [value]: [] });
        setFetchAllContributions({
            assignedContributions: false,
            unassignedContributions: false,
        });
    };

    const onClickMoveTo = (value: string) => {
        setMovingList(value);
        moveTo(value);
    };

    useEffect(() => {
        const unassignedCount = dataUnassigned?.nrContributions.totalCount || 0;
        const unassignedItems = dataUnassigned?.nrContributions.items || [];
        setUnassignedItems(unassignedItems);

        if (
            selectedContainer?.unassignedContributions ||
            (!selectedContainer?.unassignedContributions &&
                !selectedContainer?.assignedContributions)
        ) {
            const { items, totalCount }: any = formatContributions(
                unassignedItems,
                contributions.assignedContributions,
                contributions.unassignedContributions,
                unassignedCount,
                filterValues?.unassignedContributions?.term,
                client.cache
            );
            setUnassignedFilterItems(items);
            setUnassignedFilterCount(totalCount);
            setMovingList('');
        }
    }, [dataUnassigned, selectedContainer]);

    useEffect(() => {
        const assignedCount = dataAssigned?.nrContributions.totalCount || 0;
        const assignedItems = dataAssigned?.nrContributions.items || [];
        setAssignedItems(assignedItems);

        if (
            selectedContainer?.assignedContributions ||
            (!selectedContainer?.unassignedContributions &&
                !selectedContainer?.assignedContributions)
        ) {
            const { totalCount, items }: any = formatContributions(
                assignedItems,
                contributions.unassignedContributions,
                contributions.assignedContributions,
                assignedCount,
                filterValues?.assignedContributions?.term,
                client.cache
            );
            setAssignedFilterItems(items);
            setAssignedFilterCount(totalCount);
            setMovingList('');
        }
    }, [dataAssigned, selectedContainer]);

    const undoMovedItemsHandler = (value: string) => {
        if (
            value === 'unassignedContributions' &&
            undoMovedList?.unassignedContributions
        ) {
            const { unassignedContributions } = undoMovedList;
            // save post variable
            setContributions({
                assignedContributions: [
                    ...contributions.assignedContributions,
                    ...difference(
                        unassignedContributions,
                        contributions.unassignedContributions
                    ),
                ],
                unassignedContributions: difference(
                    contributions.unassignedContributions,
                    unassignedContributions
                ),
            });
        }

        if (
            value === 'assignedContributions' &&
            undoMovedList?.assignedContributions
        ) {
            const { assignedContributions } = undoMovedList;
            // save post variable
            setContributions({
                unassignedContributions: [
                    ...contributions.unassignedContributions,
                    ...difference(
                        assignedContributions,
                        contributions.assignedContributions
                    ),
                ],
                assignedContributions: difference(
                    contributions.assignedContributions,
                    undoMovedList.assignedContributions
                ),
            });
        }
        setUndoMovedList({});
        setSelectedContainer({
            assignedContributions: false,
            unassignedContributions: false,
        });
    };

    const formatContributionsUndoMessage = (contributions: any) =>
        `${contributions.length} Contribution(s) Moved`;

    const moreToSelectAssigned =
        assignedFilterItems.length > itemMoveList.assignedContributions.length;
    if (fetchAllContributions.assignedContributions && moreToSelectAssigned)
        setItemMoveList({
            ...itemMoveList,
            assignedContributions: assignedFilterItems.map(
                (item: any) => item.value
            ),
        });
    const moreToSelectUnassigned =
        unassignedFilterItems.length >
        itemMoveList.unassignedContributions.length;
    if (fetchAllContributions.unassignedContributions && moreToSelectUnassigned)
        setItemMoveList({
            ...itemMoveList,
            unassignedContributions: unassignedFilterItems.map(
                (item: any) => item.value
            ),
        });

    return (
        <div>
            {error && (
                <Alert variant="error" text={error} className="error-alert" />
            )}
            <div className="EditScheduleForm-UnassignedContributions">
                <ContributionItems
                    filterValues={filterValues}
                    setFilterValues={setFilterValues}
                    itemList={unassignedFilterItems}
                    forward
                    headerText="Unassigned Contributions"
                    listType="unassignedContributions"
                    message="ASSIGNED CONTRIBUTIONS TO"
                    totalCount={contributionsTotalCount}
                    areContributionsLoading={loadingUnassigned}
                    filterCount={unassignedFilterCount}
                    onClickMoveTo={onClickMoveTo}
                    itemMoveList={itemMoveList}
                    setItemMoveList={setItemMoveList}
                    undoMovedList={undoMovedList}
                    undoMessage={formatContributionsUndoMessage(
                        undoMovedList?.unassignedContributions || []
                    )}
                    undoHandler={undoMovedItemsHandler}
                    fetchMore={() =>
                        fetchNextExistingPageUnassigned(DEFAULT_PAGE_SIZE)
                    }
                    unfilteredCount={unassignedItems.length}
                    setSelectAll={(val: boolean) =>
                        setFetchAllContributions({
                            ...fetchAllContributions,
                            unassignedContributions: val,
                        })
                    }
                    movingFrom={movingList == 'unassignedContributions'}
                    movingTo={movingList == 'assignedContributions'}
                    movingFromMessage={`Please wait on this page while we move selected (${undoMovedList?.assignedContributions?.length}) to the Assigned Contributions`}
                    movingToMessage={`Moving Selected (${undoMovedList?.unassignedContributions?.length}) to the Unassigned Contributions in progress... Please don't leave the page`}
                    setSelectedContainer={setSelectedContainer}
                    isDisabled={
                        fetchAllContributions.assignedContributions &&
                        loadingAssigned
                    }
                    isInitialPageLoading={isInitialPageLoading}
                />
            </div>
            <div className="EditScheduleForm-AssignedContributions">
                <ContributionItems
                    filterValues={filterValues}
                    setFilterValues={setFilterValues}
                    itemList={assignedFilterItems}
                    forward={false}
                    headerText="Assigned Contributions"
                    listType="assignedContributions"
                    message="UNASSIGNED CONTRIBUTIONS TO"
                    totalCount={contributionsTotalCount}
                    areContributionsLoading={loadingAssigned}
                    filterCount={assignedFilterCount}
                    onClickMoveTo={onClickMoveTo}
                    itemMoveList={itemMoveList}
                    setItemMoveList={setItemMoveList}
                    undoMovedList={undoMovedList}
                    undoMessage={formatContributionsUndoMessage(
                        undoMovedList?.assignedContributions || []
                    )}
                    undoHandler={undoMovedItemsHandler}
                    fetchMore={() =>
                        fetchNextExistingPageAssigned(DEFAULT_PAGE_SIZE)
                    }
                    unfilteredCount={assignedItems.length}
                    setSelectAll={(val: boolean) =>
                        setFetchAllContributions({
                            ...fetchAllContributions,
                            assignedContributions: val,
                        })
                    }
                    movingFrom={movingList == 'assignedContributions'}
                    movingTo={movingList == 'unassignedContributions'}
                    movingFromMessage={`Please wait on this page while we move selected (${undoMovedList?.unassignedContributions?.length}) to the Unassigned Contributions`}
                    movingToMessage={`Moving Selected (${undoMovedList?.assignedContributions?.length}) to the Assigned Contributions in progress... Please don't leave the page`}
                    setSelectedContainer={setSelectedContainer}
                    isDisabled={
                        fetchAllContributions.unassignedContributions &&
                        loadingUnassigned
                    }
                    isInitialPageLoading={isInitialPageLoading}
                />
            </div>
        </div>
    );
};

export default Contributions;
