// TODO: see if this component can be deleted, it isn't imported by anything but its spec file.
import type { ChangeEventHandler, JSX } from 'react';
import React, { useEffect, useState } from 'react';
import { useReactiveVar } from '@apollo/client';
import { Button, useToast } from '@theorchard/suite-components';
import classNames from 'classnames';
import defaultTo from 'lodash-es/defaultTo';
import isEmpty from 'lodash-es/isEmpty';
import { useHistory, useLocation } from 'react-router-dom';
import { Link, useParams } from 'react-router-dom';
import {
    useDeletePaymentGroupPaymentAccount,
    useUpdatePaymentGroupPaymentAccount,
} from 'src/apollo/mutations/payment-group-payment-account';
import { usePaymentGroupPaymentAccounts } from 'src/apollo/queries/payment-group-payment-account';
import paginationStateVar from 'src/apollo/reactive-vars/tables-state';
import AccountFilters from 'src/components/account-list/account-filters';
import PaymentGroupPaymentAccountDeleteButton from 'src/components/payment-group-detail/payment-group-payment-account-delete-button';
import PaymentGroupPaymentAccountNotePopup from 'src/components/payment-group-detail/payment-group-payment-account-note-popup';
import { PopupModal } from 'src/components/shared/popup-modal';
import TableWithSortableHeader from 'src/components/shared/table-with-sortable-header';
import {
    DEFAULT_ITEMS_PER_PAGE,
    NO_PAYMENT_ACCOUNT_RESULTS,
    PAYMENT_GROUP_PAYMENT_ACTIONS,
    PAYMENT_APPROVAL_WARNING_MSG,
    PAYMENT_APPROVAL_STEPS,
} from 'src/constants';
import usePagination, { type PaginationPropType } from 'src/hooks/pagination';
import { selectAccountingTab } from 'src/urls/frontend-royalties';
import { isActionComplete, isActionRunning } from 'src/utils/action-states';
import { smartFormatter } from 'src/utils/amount-helpers';
import { getCurrencyLabel } from 'src/utils/currency';
import {
    getCompletedPaymentApprovalSteps,
    getPaymentApprovalAbacusEvents,
} from 'src/utils/payment-approval';
import { getQueryParams, updateQueryParam } from 'src/utils/route';
import type { SoftDeletePaymentGroupPaymentAccountMutationVariables } from 'src/apollo/mutations/payment-group-payment-account/__generated__/soft-delete-payment-group-payment-account';
import type { UpdatePaymentGroupPaymentAccountMutationVariables } from 'src/apollo/mutations/payment-group-payment-account/__generated__/update-payment-group-payment-account';
import type { PaymentAccountsTableProps } from 'src/components/payment-group-detail/payment-group-payment-accounts-table';
import type { AbacusEvent } from 'src/types/abacus-event';
import type {
    AbacusPaymentGroupPaymentAccount,
    AbacusPaymentGroupPaymentAccountsItem,
    PaymentGroupPaymentAccount,
} from 'src/types/payment-group';

export interface PaymentGroupPaymentAccountsProps {
    abacusEvents: AbacusEvent[];
    actionStates: PaymentAccountsTableProps['actionStates'];
    setErrors: (error: Record<string, string>) => void;
    statementPeriod?: {
        statementPeriodName: string;
    };
}

type AccountListItem = {
    account: PaymentGroupPaymentAccount;
} & AbacusPaymentGroupPaymentAccountsItem;

export default function PaymentGroupPaymentAccounts({
    abacusEvents,
    actionStates,
    setErrors,
    statementPeriod,
}: PaymentGroupPaymentAccountsProps) {
    const history = useHistory();
    const location = useLocation();
    const [statementPeriodName, setStatementPeriodName] = useState('');
    const paginationState = useReactiveVar(paginationStateVar);
    const addToast = useToast();

    const HEADERS = [
        { label: 'Account Name', value: 'account_name', sortable: true },
        { label: 'Account Id', value: 'account_id', sortable: true },
        { label: 'Currency', value: 'currency_code', sortable: true },
        { label: 'Last Payment', value: 'last_payment', sortable: true },
        {
            label: 'Outstanding Balance',
            value: 'current_balance',
            sortable: true,
        },
        { label: 'Tax Withholding', value: 'tax_withholding', sortable: true },
        {
            label: 'Last Payment Statement Period',
            value: 'last_statement_period_id',
            sortable: true,
        },
        {
            label: `${statementPeriodName} Payment`,
            value: 'balance_after_tax',
            sortable: true,
        },
        { label: 'Diff', value: 'payment_difference', sortable: true },
        { label: 'Diff %', value: 'percent_difference', sortable: true },
        { label: 'Note', value: 'note', sortable: true },
        { label: 'Status', value: 'payment_status', sortable: true },
        { label: 'Error Message', value: 'payment_error_code', sortable: true },
        { label: '', value: 'delete_payment_account', sortable: false },
    ];
    const [paymentAccountId, setPaymentAccountId] = useState<
        string | null | undefined
    >(null);
    const { paymentGroupPaymentId } = useParams<{
        paymentGroupPaymentId: string;
    }>();
    const [paymentAccounts, setPaymentAccounts] = useState<
        {
            id: string;
            cols: (string | false | JSX.Element | undefined)[];
        }[]
    >([]);
    const [requestParams, setRequestParams] = useState({
        limit: DEFAULT_ITEMS_PER_PAGE,
        offset: 0,
        paymentGroupPaymentId,
        sortBy: 'account_name',
        sortOrder: 'asc' as 'asc' | 'desc',
        searchTerm: '',
    });
    const [shouldResetApproval, setShouldResetApproval] = useState(false);
    const [isResetWarningModalOpen, setIsResetWarningModalOpen] =
        useState(false);
    const [resetWarningModalPopupName, setResetWarningModalPopupName] =
        useState<string | null>(null);
    const [selectedPaymentAccount, setSelectedPaymentAccount] = useState(
        {} as AbacusPaymentGroupPaymentAccount
    );
    const [deletedPaymentAccountCurrency, setDeletedPaymentAccountCurrency] =
        useState({});
    const [completedPaymentApprovalSteps, setCompletedPaymentApprovalSteps] =
        useState<string[]>([]);
    const [totalCount, setTotalCount] = useState(0);
    const { data, loading } = usePaymentGroupPaymentAccounts(requestParams);
    const { data: unfilteredData, loading: unfilteredDataLoading } =
        usePaymentGroupPaymentAccounts({
            limit: 1,
            paymentGroupPaymentId,
            searchTerm: '',
        });
    const [isFiltered, setIsFiltered] = useState(false);

    const queryParams = {
        searchTerm: {
            name: 'searchTerm',
            type: 'string' as const,
        },
    };
    const unfilteredItemsCount =
        unfilteredData?.abacusPaymentGroupPaymentAccounts?.totalCount ?? 0;

    const deletePaymentGroupPaymentAccount =
        useDeletePaymentGroupPaymentAccount(
            requestParams,
            deletedPaymentAccountCurrency
        );

    const { updatePaymentGroupPaymentAccount } =
        useUpdatePaymentGroupPaymentAccount(requestParams);

    const deleteHandler = (
        accountName?: string,
        paymentGroupPaymentAccountId?: string | null
    ) => {
        const variables: SoftDeletePaymentGroupPaymentAccountMutationVariables =
            {
                paymentGroupPaymentAccountId:
                    paymentGroupPaymentAccountId ?? '',
            };

        deletePaymentGroupPaymentAccount({ variables })
            .then(response => {
                if (
                    response &&
                    response.data?.abacusSoftDeletePaymentGroupPaymentAccount
                )
                    addToast(`${accountName} was removed`);
            })
            .catch(error => setErrors({ serverError: error }));
        setShouldResetApproval(false);
    };

    const arePaymentsSent =
        isActionComplete(
            actionStates,
            PAYMENT_GROUP_PAYMENT_ACTIONS.SEND_PAYMENTS
        ) ||
        isActionRunning(
            actionStates,
            PAYMENT_GROUP_PAYMENT_ACTIONS.SEND_PAYMENTS
        );

    const fetchMoreWrapper: PaginationPropType['fetchMore'] = ({
        variables: { limit, offset },
    }) => {
        const variables = { ...requestParams, limit, offset };
        setRequestParams(variables);
    };

    const handlePaymentApprovalReset = () => {
        setIsResetWarningModalOpen(false);
        if (resetWarningModalPopupName === 'addNote')
            setPaymentAccountId(
                selectedPaymentAccount?.paymentGroupPaymentAccountId
            );

        if (resetWarningModalPopupName === 'delete')
            deleteHandler(
                selectedPaymentAccount?.accountName,
                selectedPaymentAccount?.paymentGroupPaymentAccountId
            );
    };

    const formatList = (items: AccountListItem[] | null) => {
        const formattedItems =
            items?.map(item => {
                const {
                    account: { accountId, accountName },
                    balanceAfterTax,
                    currencyCode,
                    currentBalance,
                    lastStatementPeriod,
                    lastPayment,
                    paymentDifference,
                    paymentErrorCode,
                    paymentGroupPaymentAccountId,
                    paymentStatus,
                    percentDifference,
                    note,
                    taxWithholding,
                } = item ?? {};
                const accountLink = (
                    <Link
                        key={`account-link-${accountId}`}
                        to={selectAccountingTab(accountId)}
                    >
                        {accountName}
                    </Link>
                );

                const formattedDiff =
                    paymentDifference &&
                    smartFormatter(paymentDifference, currencyCode);
                const paymentDiffSpan =
                    parseFloat(defaultTo(paymentDifference, '0')) < 0 ? (
                        <span
                            className="payment-diff-red"
                            data-testid="payment-diff-red"
                        >
                            {formattedDiff}
                        </span>
                    ) : (
                        <span
                            className="payment-diff-green"
                            data-testid="payment-diff-green"
                        >
                            {formattedDiff}
                        </span>
                    );

                const percentDiffSpan =
                    parseFloat(defaultTo(percentDifference, '0')) < 0 ? (
                        <span
                            className="payment-diff-red"
                            data-testid="payment-diff-red"
                        >
                            {percentDifference}%
                        </span>
                    ) : (
                        <span
                            className="payment-diff-green"
                            data-testid="payment-diff-green"
                        >
                            {percentDifference}%
                        </span>
                    );

                const addNoteButton = (
                    <Button
                        onClick={() => {
                            if (shouldResetApproval) {
                                setResetWarningModalPopupName('addNote');
                                setIsResetWarningModalOpen(true);
                                setSelectedPaymentAccount({
                                    accountName,
                                    paymentGroupPaymentAccountId,
                                });
                            } else
                                setPaymentAccountId(
                                    paymentGroupPaymentAccountId
                                );
                        }}
                        variant="quartenary"
                        disabled={arePaymentsSent ?? undefined}
                    >
                        Add Note
                    </Button>
                );

                const deleteButton = (
                    <PaymentGroupPaymentAccountDeleteButton
                        deleteHandler={() =>
                            deleteHandler(
                                accountName,
                                paymentGroupPaymentAccountId
                            )
                        }
                        shouldResetApproval={shouldResetApproval}
                        setResetWarningModalPopupName={
                            setResetWarningModalPopupName
                        }
                        setIsResetWarningModalOpen={setIsResetWarningModalOpen}
                        setPaymentAccountDetails={() =>
                            setSelectedPaymentAccount({
                                accountName,
                                paymentGroupPaymentAccountId,
                            })
                        }
                        setPaymentAccountCurrencyDetails={() =>
                            setDeletedPaymentAccountCurrency({
                                currencyCode: currencyCode,
                                amount: balanceAfterTax,
                            })
                        }
                    />
                );

                return {
                    id: paymentGroupPaymentAccountId ?? '',
                    cols: [
                        accountLink,
                        accountId,
                        getCurrencyLabel(currencyCode),
                        smartFormatter(lastPayment, currencyCode),
                        smartFormatter(currentBalance, currencyCode),
                        taxWithholding
                            ? smartFormatter(taxWithholding, currencyCode)
                            : '-',
                        lastStatementPeriod
                            ? lastStatementPeriod.statementPeriodName
                            : '-',
                        smartFormatter(balanceAfterTax, currencyCode),
                        paymentDifference ? (
                            paymentDiffSpan
                        ) : (
                            <div className="no-data">-</div>
                        ),
                        percentDifference ? (
                            percentDiffSpan
                        ) : (
                            <div className="no-data">-</div>
                        ),
                        note || addNoteButton,
                        paymentStatus || <div className="no-data">-</div>,
                        paymentErrorCode || <div className="no-data">-</div>,
                        unfilteredItemsCount > 1 &&
                            !arePaymentsSent &&
                            deleteButton,
                    ],
                };
            }) ?? [];

        setPaymentAccounts(formattedItems);
    };

    const { renderPagination } = usePagination({
        fetchMore: fetchMoreWrapper,
        totalItemCount: totalCount,
        tableId: 'payment-group-payment-accounts',
    });

    const sortingHandler = (sortValue: string) => {
        const { sortBy, sortOrder } = requestParams;
        let sortDirection = 'asc' as 'asc' | 'desc';
        if (sortBy === sortValue)
            sortDirection = sortOrder === 'asc' ? 'desc' : 'asc';

        paginationStateVar({
            ...paginationState,
            'payment-group-payment-accounts': 1,
        });
        setRequestParams({
            ...requestParams,
            offset: 0,
            sortBy: sortValue,
            sortOrder: sortDirection,
        });
    };

    const updateHandler = (
        note: UpdatePaymentGroupPaymentAccountMutationVariables['note']
    ) => {
        const variables: UpdatePaymentGroupPaymentAccountMutationVariables = {
            note,
            paymentGroupPaymentAccountId: paymentAccountId ?? '',
        };

        updatePaymentGroupPaymentAccount({ variables })
            .then(response => {
                if (
                    response &&
                    response.data?.abacusUpdatePaymentGroupPaymentAccount
                )
                    setPaymentAccountId(null);
            })
            .catch(error => setErrors({ serverError: error }));
        setShouldResetApproval(false);
    };

    useEffect(() => {
        const parsedParams = getQueryParams(location, queryParams);
        if (!isEmpty(parsedParams)) {
            setRequestParams({ ...requestParams, ...parsedParams });
            setIsFiltered(true);
        }
    }, []);

    useEffect(() => {
        if (data && data.abacusPaymentGroupPaymentAccounts) {
            const { abacusPaymentGroupPaymentAccounts } = data;
            // @ts-expect-error: items type includes null, ignoring for now since we handle it in the formatList function
            formatList(abacusPaymentGroupPaymentAccounts.items);
            setTotalCount(abacusPaymentGroupPaymentAccounts.totalCount ?? 0);
        }
    }, [data, unfilteredData, shouldResetApproval]);

    useEffect(() => {
        const allowResetApprovals = [
            PAYMENT_APPROVAL_STEPS.GENERATE_EXPORT,
            PAYMENT_APPROVAL_STEPS.UPLOAD_APPROVAL_FILE,
            PAYMENT_APPROVAL_STEPS.CONFIRM_FUNDS,
        ];

        if (
            (!isEmpty(abacusEvents) && !shouldResetApproval) ||
            (!isEmpty(abacusEvents) &&
                abacusEvents.length !== completedPaymentApprovalSteps.length)
        ) {
            // Get a list of available payment approval abacus events
            const { paymentApprovalEventsArray } =
                // @ts-expect-error: abacusEvent type doesn't exactly match gql response type. Ignore for now.
                getPaymentApprovalAbacusEvents(abacusEvents);

            // get completed payment approval steps based on paymentApprovalEventsArray
            const completedApprovalSteps = getCompletedPaymentApprovalSteps(
                paymentApprovalEventsArray
            );

            setCompletedPaymentApprovalSteps(completedApprovalSteps);
            // Below code will return empty array if 'send_payments' and 'complete' events are not completed.
            const disallowResetApprovals = completedApprovalSteps.filter(
                step => allowResetApprovals.indexOf(step) === -1
            );

            if (
                isEmpty(disallowResetApprovals) &&
                !isEmpty(paymentApprovalEventsArray)
            )
                setShouldResetApproval(true);
            else setShouldResetApproval(false);
            // here we also need to add logic to show warning popup if 'send_payments' event is completed
        }
    }, [abacusEvents]);

    useEffect(() => {
        if (paymentGroupPaymentId !== requestParams.paymentGroupPaymentId)
            setRequestParams({ ...requestParams, paymentGroupPaymentId });
    }, [paymentGroupPaymentId]);

    useEffect(() => {
        if (statementPeriod)
            setStatementPeriodName(statementPeriod.statementPeriodName);
    }, [statementPeriod]);

    const changeHandler: ChangeEventHandler<HTMLInputElement> = e => {
        const {
            target: { name, value },
        } = e;
        const key = name;
        const filterValue = value.trim();
        setRequestParams({ ...requestParams, offset: 0, [key]: filterValue });
        setIsFiltered(!!value);
        updateQueryParam(location, history, queryParams, key, filterValue);
    };

    const clearFilter = () => {
        setIsFiltered(false);
        setRequestParams({
            ...requestParams,
            limit: DEFAULT_ITEMS_PER_PAGE,
            offset: 0,
            paymentGroupPaymentId,
            searchTerm: '',
        });
        updateQueryParam(location, history, queryParams, null, null);
    };

    return (
        <div className="PaymentGroupDetails-accounts">
            <div data-testid="AccountFiltersWrapper">
                <AccountFilters
                    changeHandler={changeHandler}
                    clearFilters={clearFilter}
                    isFiltered={isFiltered}
                    filterValues={requestParams}
                    setFilterValues={setRequestParams}
                />
                <div className="PaymentGroupDetails-result-count">
                    {isFiltered && !loading && (
                        <div>
                            <span className="SearchableList-result-count-label">
                                Results:
                            </span>
                            <span className="SearchableList-result-count-value">
                                {`${totalCount}`}
                            </span>
                        </div>
                    )}
                </div>
            </div>
            <div
                className={classNames('PaymentGroupDetails-accounts-table', {
                    NoPaymentsFound: !paymentAccounts.length,
                    PaymentSent: arePaymentsSent,
                })}
            >
                <div className="sticky-view">
                    <div className="sticky-wrapper">
                        <TableWithSortableHeader
                            headers={HEADERS}
                            isLoading={loading || unfilteredDataLoading}
                            rows={paymentAccounts}
                            itemsPerPage={DEFAULT_ITEMS_PER_PAGE}
                            onClickHandler={sortingHandler}
                            sortBy={requestParams.sortBy}
                            sortOrder={requestParams.sortOrder}
                            className=""
                        />
                    </div>
                </div>
                <PaymentGroupPaymentAccountNotePopup
                    closeHandler={() => setPaymentAccountId(null)}
                    isModalOpen={Boolean(paymentAccountId)}
                    saveHandler={updateHandler}
                />
                {isResetWarningModalOpen && (
                    <PopupModal
                        className="PaymentGroupDetails-accounts-reset-warning-popup"
                        closeHandler={() => {
                            setIsResetWarningModalOpen(false);
                        }}
                        headerLabel="WARNING"
                        isOpen={isResetWarningModalOpen}
                        modalContent={<>{PAYMENT_APPROVAL_WARNING_MSG}</>}
                        saveHandler={handlePaymentApprovalReset}
                        saveButtonText="Yes"
                    />
                )}
                {!paymentAccounts.length && (
                    <div className="NoResultsFound">
                        {NO_PAYMENT_ACCOUNT_RESULTS}
                    </div>
                )}
            </div>
            {renderPagination()}
        </div>
    );
}
