import React, { useEffect, useState } from 'react';
import { GridTable, Button, useToast } from '@theorchard/suite-components';
import { GlyphIcon } from '@theorchard/suite-icons';
import { isEmpty, snakeCase } from 'lodash-es';
import { useHistory, useLocation, 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 {
    DEFAULT_ITEMS_PER_PAGE,
    NO_PAYMENT_ACCOUNT_RESULTS,
    PAYMENT_GROUP_PAYMENT_ACTIONS,
    PAYMENT_APPROVAL_WARNING_MSG,
    PAYMENT_APPROVAL_STEPS,
    PAYMENT_ACCOUNT_DELETE_MSG,
    PAYMENT_ACCOUNT_DELETE_MSG_WARN,
    USER_FEATURES,
} from 'src/constants';
import { isActionComplete, isActionRunning } from 'src/utils/action-states';
import { exportCsv } from 'src/utils/export-csv';
import {
    getCompletedPaymentApprovalSteps,
    getPaymentApprovalAbacusEvents,
} from 'src/utils/payment-approval';
import './payment-group-payment-accounts-table.scss';
import { getQueryParams, updateQueryParam } from 'src/utils/route';
import AccountFilters from '../account-list/account-filters';
import { PopupModal } from '../shared/popup-modal';
import PaymentGroupPaymentAccountNotePopup from './payment-group-payment-account-note-popup';
import PaymentGroupPaymentAccountsTableColumns from './payment-group-payment-accounts-table-columns';
import type { ColumnDefinition } from '@theorchard/suite-components/dist/esm/src/components/table/base/types';
import { QueryParamsConfig, useFeatureFlag } from '@theorchard/suite-frontend';
import type { ActionState } from 'src/types/action-state';
import type {
    AbacusPaymentGroupPaymentAccount,
    AbacusPaymentGroupPaymentAccountsItem,
    PaymentGroupPayment,
} from 'src/types/payment-group';

type AbacusEvent = NonNullable<PaymentGroupPayment['abacusEvents']>[number];

export interface PaymentAccountsTableProps {
    statementPeriod: {
        statementPeriodId: string;
        statementPeriodName: string;
    };
    abacusEvents: AbacusEvent[];
    actionStates: {
        approve: ActionState;
        generate_payments: ActionState;
        post: ActionState;
        send_payments: ActionState;
    };
    setErrors: (serverError: { serverError: string }) => void;
}

export const filename = 'payment-accounts-table';

export default function PaymentGroupPaymentAccountsTable({
    abacusEvents,
    actionStates,
    setErrors,
    statementPeriod,
}: PaymentAccountsTableProps) {
    const history = useHistory();
    const location = useLocation();
    const addToast = useToast();
    const [pageSize, setPageSize] = useState(DEFAULT_ITEMS_PER_PAGE);
    const [page, setPage] = useState(0);
    const [totalCount, setTotalCount] = useState(0);
    const [list, setList] = useState<AbacusPaymentGroupPaymentAccount[]>([]);
    const [isResetWarningModalOpen, setIsResetWarningModalOpen] =
        useState(false);
    const [shouldResetApproval, setShouldResetApproval] = useState(false);
    const [resetWarningModalPopupName, setResetWarningModalPopupName] =
        useState<string | null>(null);
    const [selectedPaymentAccount, setSelectedPaymentAccount] = useState<{
        accountName: string;
        paymentGroupPaymentAccountId: string;
    }>({
        accountName: '',
        paymentGroupPaymentAccountId: '',
    });
    const [deletedPaymentAccountCurrency, setDeletedPaymentAccountCurrency] =
        useState({});
    const [completedPaymentApprovalSteps, setCompletedPaymentApprovalSteps] =
        useState<any>([]);
    const [isFiltered, setIsFiltered] = useState(false);

    const [paymentAccountId, setPaymentAccountId] = useState<string | null>(
        null
    );
    const { paymentGroupPaymentId } = useParams<{
        paymentGroupPaymentId: string;
    }>();

    const [requestParams, setRequestParams] = useState({
        limit: pageSize,
        offset: page * pageSize,
        paymentGroupPaymentId,
        sortBy: 'account_name',
        sortOrder: 'asc',
        searchTerm: '',
    });
    const { data, loading } = usePaymentGroupPaymentAccounts(requestParams);
    const { data: unfilteredData, loading: unfilteredDataLoading } =
        usePaymentGroupPaymentAccounts({
            limit: 1,
            paymentGroupPaymentId,
            searchTerm: '',
        });

    const arePaymentsSent =
        isActionComplete(
            actionStates,
            PAYMENT_GROUP_PAYMENT_ACTIONS.SEND_PAYMENTS
        ) ||
        isActionRunning(
            actionStates,
            PAYMENT_GROUP_PAYMENT_ACTIONS.SEND_PAYMENTS
        );
    const isCreateAndApprovePaymentsFFEnabled = useFeatureFlag(
        USER_FEATURES.ABACUS_CREATE_AND_APPROVE_PAYMENTS
    );

    useEffect(() => {
        setRequestParams({
            ...requestParams,
            limit: pageSize,
            offset: page * pageSize,
            paymentGroupPaymentId: paymentGroupPaymentId,
        });
    }, [page, pageSize, paymentGroupPaymentId]);

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

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

    const formatList = (items: AbacusPaymentGroupPaymentAccountsItem[]) => {
        const formattedItems = items?.map(item => {
            return {
                accountName: item?.account?.accountName,
                accountId: item?.account?.accountId,
                currencyCode: item?.currencyCode,
                lastPayment: item?.lastPayment,
                currentBalance: item?.currentBalance,
                taxWithholding: item?.taxWithholding,
                vatAmount: item?.vatAmount,
                lastStatementPeriodName:
                    item?.lastStatementPeriod?.statementPeriodName,
                lastStatementPeriodId:
                    item?.lastStatementPeriod?.statementPeriodId,
                closingBalanceStatementPeriodName:
                    item?.closingBalanceStatementPeriod?.statementPeriodName,
                balanceAfterTax: item?.balanceAfterTax,
                paymentDifference: item?.paymentDifference,
                percentDifference: item?.percentDifference,
                note: item?.note,
                paymentStatus: item?.paymentStatus,
                paymentErrorCode: item?.paymentErrorCode,
                statementPeriodName: statementPeriod?.statementPeriodName,
                paymentGroupPaymentAccountId:
                    item?.paymentGroupPaymentAccountId,
            };
        });
        setList(formattedItems);
    };

    const unfilteredItemsCount =
        unfilteredData?.abacusPaymentGroupPaymentAccounts?.totalCount || 0;

    const deletePaymentGroupPaymentAccount =
        useDeletePaymentGroupPaymentAccount(
            requestParams,
            deletedPaymentAccountCurrency
        );
    const { updatePaymentGroupPaymentAccount } =
        useUpdatePaymentGroupPaymentAccount(requestParams);
    const deleteHandler = (
        accountName: string,
        paymentGroupPaymentAccountId: string
    ) => {
        const variables = { paymentGroupPaymentAccountId };

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

    const updateHandler = (note: string) => {
        const variables = {
            note,
            paymentGroupPaymentAccountId: paymentAccountId || '',
        };

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

    useEffect(() => {
        if (data && data.abacusPaymentGroupPaymentAccounts) {
            const { abacusPaymentGroupPaymentAccounts } = data;
            if (abacusPaymentGroupPaymentAccounts.items) {
                // @ts-expect-error: ignore null
                formatList(abacusPaymentGroupPaymentAccounts.items);
            }
            setTotalCount(abacusPaymentGroupPaymentAccounts.totalCount || 0);
        }
    }, [data, loading, requestParams, shouldResetApproval, isFiltered]);

    interface IAddNoteButton {
        accountName: string;
        paymentGroupPaymentAccountId: string;
    }

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

    const queryParams: QueryParamsConfig = {
        searchTerm: {
            name: 'searchTerm',
            type: 'string',
        },
    };

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

    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 } =
                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.includes(step)
            );

            if (
                isEmpty(disallowResetApprovals) &&
                !isEmpty(paymentApprovalEventsArray)
            )
                setShouldResetApproval(true);
            else setShouldResetApproval(false);
        }
    }, [abacusEvents]);

    const deleteRowBtnEnabled = unfilteredItemsCount > 1 && !arePaymentsSent;
    const deleteTooltip =
        unfilteredItemsCount <= 1
            ? 'Unable to delete the last item in the list.'
            : 'Payment(s) sent';

    const changeHandler = (e: { target: { name: string; value: string } }) => {
        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, searchTerm: '' });
        updateQueryParam(location, history, queryParams, null, null);
    };

    const onExportHandler = () => {
        // @ts-expect-error: list could have nulls in it and this function doesn't like that.
        exportCsv(list, filename);
    };

    return (
        <div
            className="PaymentGroupPaymentAccountsTable"
            data-testid="PaymentGroupPaymentAccountsTable"
        >
            <div data-testid="AccountFiltersWrapper">
                <AccountFilters
                    changeHandler={changeHandler}
                    clearFilters={clearFilter}
                    isFiltered={isFiltered}
                    filterValues={requestParams}
                    setFilterValues={setRequestParams}
                    hideClearFilterBtn
                />
            </div>
            <GridTable
                totalCount={totalCount}
                page={page}
                pageSize={pageSize}
                paginated
                onPageChange={setPage}
                onPageSizeChange={setPageSize}
                showUpdateIndicator
                showClearFilters={isFiltered}
                bordered
                name="sticky"
                stickyColumnHeaders
                loading={loading || unfilteredDataLoading}
                onSort={e => {
                    setRequestParams({
                        ...requestParams,
                        sortBy: snakeCase(e[0].key),
                        sortOrder: e[0].direction,
                    });
                }}
                onClearFilters={() => {
                    clearFilter();
                }}
                // @ts-expect-error: list could have nulls in it and this prop doesn't like that.
                data={list}
                loadingRows={DEFAULT_ITEMS_PER_PAGE}
                maxHeight="650px"
                columnDefs={
                    PaymentGroupPaymentAccountsTableColumns({
                        statementPeriod,
                        addNoteButton,
                    }) as
                        | ColumnDefinition<{
                              accountName: string;
                              paymentGroupPaymentAccountId: string;
                              currencyCode: string;
                              balanceAfterTax: string;
                          }>[]
                        | undefined
                }
                stickyColumnHeadersOffset={0.1}
                defaultColumnDefs={{
                    sortable: true,
                    defaultSortDirection: 'desc',
                }}
                rowKey="acountId"
                rowActions={
                    isCreateAndApprovePaymentsFFEnabled
                        ? {
                              delete: {
                                  icon: <GlyphIcon name="trash" size={16} />,
                                  variant: 'danger',
                                  tooltip: !deleteRowBtnEnabled
                                      ? deleteTooltip
                                      : 'Delete?',
                                  disabled: () => !deleteRowBtnEnabled,
                                  onClick: (row: {
                                      accountName: string;
                                      paymentGroupPaymentAccountId: string;
                                      currencyCode: string;
                                      balanceAfterTax: string;
                                  }) => {
                                      const {
                                          accountName,
                                          paymentGroupPaymentAccountId,
                                          currencyCode,
                                          balanceAfterTax,
                                      } = row;
                                      setSelectedPaymentAccount({
                                          accountName,
                                          paymentGroupPaymentAccountId,
                                      });
                                      setDeletedPaymentAccountCurrency({
                                          currencyCode: currencyCode,
                                          amount: balanceAfterTax,
                                      });
                                      setResetWarningModalPopupName('delete');
                                  },
                              },
                          }
                        : undefined
                }
                emptyStateTitle={NO_PAYMENT_ACCOUNT_RESULTS}
                exportable
                onExport={onExportHandler}
            />
            {isCreateAndApprovePaymentsFFEnabled && (
                <PopupModal
                    className="PaymentGroupDetails-accounts-delete-account-warning-popup"
                    closeHandler={() => {
                        setResetWarningModalPopupName('');
                    }}
                    headerLabel={
                        <div>
                            {PAYMENT_ACCOUNT_DELETE_MSG}{' '}
                            <b>
                                &nbsp; &quot;
                                {selectedPaymentAccount.accountName}
                                &quot;
                            </b>{' '}
                            ?
                        </div>
                    }
                    isOpen={resetWarningModalPopupName === 'delete'}
                    modalContent={<>{PAYMENT_ACCOUNT_DELETE_MSG_WARN}</>}
                    saveHandler={() =>
                        deleteHandler(
                            selectedPaymentAccount.accountName,
                            selectedPaymentAccount.paymentGroupPaymentAccountId
                        )
                    }
                    saveButtonText="Delete"
                />
            )}
            <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"
                />
            )}
        </div>
    );
}
