import React, { useState } from 'react';
import { ABACUS_ACTION_STATUSES } from '@theorchard/accounting-apps-shared';
import {
    Field,
    Form,
    GlyphButton,
    GridTable,
    MultiSelect,
    SearchInput,
    Section,
    Sidecar,
    Status,
    type SelectOption,
    useFullscreenModal,
    useToast,
} from '@theorchard/suite-components';
import { useUpdateAbacusState } from 'src/apollo/mutations/abacus-state';
import { useDeletePayeeKycNotificationMutation } from 'src/apollo/mutations/delete-payee-kyc-notification';
import { useReleaseAbacusPayee } from 'src/apollo/mutations/payee';
import { useBaseAccountsSearchQuery } from 'src/apollo/queries/account';
import {
    useGetPayeesList,
    type Payee,
    type AbacusState,
} from 'src/apollo/queries/payees';
import { selectCollaboratorLabel } from 'src/apollo/selectors/collaborator';
import CopyButton from '../shared/copy-button';
import PayeeDetailsModal from './payee-details-modal';
import './styles.scss';

const CLASS_NAME = 'PayeeManagement';

const ABACUS_STATE_LABELS: Record<string, string> = {
    [ABACUS_ACTION_STATUSES.INIT]: 'Details not submitted',
    [ABACUS_ACTION_STATUSES.RUNNING]: 'In review',
    [ABACUS_ACTION_STATUSES.COMPLETE]: 'Eligible for payment',
    [ABACUS_ACTION_STATUSES.REJECTED]: 'Rejected',
};

const ABACUS_STATE_OPTIONS = Object.values(ABACUS_ACTION_STATUSES)
    .filter(status => status in ABACUS_STATE_LABELS)
    .map(status => ({ label: ABACUS_STATE_LABELS[status], value: status }));

export const determinePayeeStatus = (
    bankingState: Pick<AbacusState, 'actionStatus' | 'message'>,
    kycNotification: { fileUploadLink: string | null } | null = null
) => {
    type Variant = React.ComponentProps<typeof Status>['variant'];
    // eslint-disable-next-line prefer-const
    let [variant, message] = ((): [Variant, string | null] => {
        switch (bankingState.actionStatus) {
            case ABACUS_ACTION_STATUSES.INIT:
                return [
                    'neutral',
                    ABACUS_STATE_LABELS[ABACUS_ACTION_STATUSES.INIT],
                ];
            case ABACUS_ACTION_STATUSES.RUNNING:
                return ['warning', bankingState.message];
            case ABACUS_ACTION_STATUSES.COMPLETE:
                return [
                    'success',
                    ABACUS_STATE_LABELS[ABACUS_ACTION_STATUSES.COMPLETE],
                ];
            case ABACUS_ACTION_STATUSES.REJECTED:
                return [
                    'error',
                    ABACUS_STATE_LABELS[ABACUS_ACTION_STATUSES.REJECTED],
                ];
            default:
                return ['neutral', null];
        }
    })();

    if (kycNotification && kycNotification.fileUploadLink) message = '';

    return (
        <Status
            className={`${CLASS_NAME}-payee-status`}
            text={message ?? 'Unknown'}
            variant={variant}
            filled
        >
            {kycNotification && bankingState.message}
        </Status>
    );
};

export const PayeeActions: React.FC<{
    payee: Payee;
    refetchPayeeList: () => Promise<any>;
}> = ({ payee, refetchPayeeList }) => {
    const { payeeId, payeeKycNotification, payeeCollaborator } = payee;
    const hasKycNotification = payee.payeeKycNotification?.fileUploadLink;
    const bankingState = payee.actionStates[0];
    const maxNotesLength = 180;

    const [isRejecting, setIsRejecting] = useState(false);
    const [isModalOpen, setIsModalOpen] = useState(false);
    const [isSidecarOpen, setIsSidecarOpen] = useState(false);
    const [rejectionNotes, setRejectionNotes] = useState('');
    const toast = useToast();
    const { open: openModal, close: closeModal } = useFullscreenModal();

    const { releaseAbacusPayee } = useReleaseAbacusPayee({ payeeId });
    const { deletePayeeKycNotification } =
        useDeletePayeeKycNotificationMutation({ payeeId });
    const { updateAbacusState } = useUpdateAbacusState();

    const rejectPayee = async () => {
        setIsRejecting(true);
        try {
            await releaseAbacusPayee();
            await deletePayeeKycNotification();
            await updateAbacusState({
                variables: {
                    ...bankingState,
                    actionStatus: ABACUS_ACTION_STATUSES.REJECTED,
                    message: rejectionNotes,
                },
            });
            await refetchPayeeList();
            toast('Rejected payee', { variant: 'success' });
        } catch (e) {
            console.error(e);
            toast('Unable to reject payee', { variant: 'error' });
        } finally {
            setIsRejecting(false);
            setIsSidecarOpen(false);
        }
    };

    const renderFileUploadLink = () => {
        if (!payeeKycNotification?.fileUploadLink) return null;

        return (
            <GlyphButton
                name="externalLink"
                tooltip="Payoneer KYC Link"
                onClick={() =>
                    window.open(payeeKycNotification.fileUploadLink, '_blank')
                }
            />
        );
    };

    return (
        <div className={`${CLASS_NAME}-actions`}>
            {renderFileUploadLink()}
            {bankingState.actionStatus !== ABACUS_ACTION_STATUSES.INIT && (
                <GlyphButton
                    name={hasKycNotification ? 'warning' : 'moreDetails'}
                    tooltip="View Payee Details"
                    onClick={() => openModal(() => setIsModalOpen(true))}
                    variant={
                        hasKycNotification ? 'danger-secondary' : 'secondary'
                    }
                />
            )}
            {isModalOpen && (
                <PayeeDetailsModal
                    isOpen={isModalOpen}
                    onRequestClose={() =>
                        closeModal(() => setIsModalOpen(false))
                    }
                    collaboratorId={payeeCollaborator!.collaborator.id}
                    payeeId={payeeId}
                    onReject={() => setIsSidecarOpen(true)}
                    showReject={[
                        ABACUS_ACTION_STATUSES.RUNNING,
                        ABACUS_ACTION_STATUSES.COMPLETE,
                    ].includes(bankingState.actionStatus)}
                />
            )}
            <Sidecar
                isOpen={isSidecarOpen}
                onRequestClose={() => setIsSidecarOpen(false)}
                title="Reject Payee Details"
                onConfirm={rejectPayee}
                confirmButtonProps={{
                    title: 'Confirm Rejection',
                    loading: isRejecting,
                }}
            >
                <Form>
                    <Field
                        controlId="RejectionNotes"
                        labelText="Rejection Notes"
                        note="Notes will be visible to client"
                        isOptional
                    >
                        <Form.Control
                            as="textarea"
                            value={rejectionNotes}
                            placeholder="Add notes here to inform client why their payment details were rejected"
                            onChange={e =>
                                setRejectionNotes(e.currentTarget.value)
                            }
                            maxLength={maxNotesLength}
                        />
                        <div>
                            {`${rejectionNotes.length}/${maxNotesLength}`}
                        </div>
                    </Field>
                </Form>
            </Sidecar>
        </div>
    );
};

export const PayeeManagement: React.FC = () => {
    const [pageSize, setPageSize] = useState<number>(100);
    const [page, setPage] = useState<number>(0);
    const [searchTerm, setSearchTerm] = useState('');
    const [abacusStateFilter, setAbacusStateFilter] = useState<SelectOption[]>(
        []
    );
    const [accountFilter, setAccountFilter] = useState<SelectOption[]>([]);

    const { data, loading, refetch } = useGetPayeesList({
        limit: pageSize,
        offset: page * pageSize,
        requiresReview: false,
        searchTerm,
        abacusStates: abacusStateFilter.map(f => ({ actionStatus: f.value })),
        accountIds: accountFilter.map(f => f.value),
    });

    const searchBaseAccounts = useBaseAccountsSearchQuery();

    const loadAccountOptions = async (term?: string) => {
        const data = await searchBaseAccounts(term, undefined, 20);
        const results =
            data?.abacusAccounts?.items?.map(account => ({
                label: account.accountName,
                subtitle: account.accountId,
                value: account.accountId,
            })) ?? [];
        return { data: results };
    };

    return (
        <Section className={CLASS_NAME}>
            <Section.Body>
                <Section.Filters className={`${CLASS_NAME}-filters`}>
                    <SearchInput
                        expanded
                        placeholder="Search by Payee Name or ID"
                        onChange={setSearchTerm}
                        width={228}
                    />
                    <MultiSelect
                        variant="compact"
                        menuMaxWidth={350}
                        placeholder="Bank Eligibility"
                        testId="BankEligibilityFilter"
                        options={ABACUS_STATE_OPTIONS}
                        onChange={setAbacusStateFilter}
                        components={{
                            OptionLabel: ({ option }) =>
                                determinePayeeStatus({
                                    actionStatus: option.value,
                                    message: option.label,
                                }),
                        }}
                    />
                    <MultiSelect
                        variant="compact"
                        menuMaxWidth={350}
                        placeholder="Account Name & ID"
                        testId="AccountFilter"
                        onLoadOptions={loadAccountOptions}
                        onChange={setAccountFilter}
                    />
                </Section.Filters>
                <Section.Table testId="collaboratorsPeriodsTable">
                    <GridTable
                        page={page}
                        pageSize={pageSize}
                        paginated
                        variant="zebra"
                        onPageChange={setPage}
                        onPageSizeChange={setPageSize}
                        loading={loading}
                        data={loading ? [] : data?.abacusPayees.items || []}
                        totalCount={data?.abacusPayees.totalCount || 0}
                        rowKey="payeeId"
                        columnDefs={[
                            {
                                name: 'actionStates',
                                title: 'Bank Eligibility',
                                Cell: ({
                                    data: {
                                        actionStates,
                                        payeeKycNotification,
                                    },
                                }) => {
                                    return (
                                        <>
                                            {determinePayeeStatus(
                                                actionStates[0],
                                                payeeKycNotification
                                            )}
                                        </>
                                    );
                                },
                            },
                            {
                                name: 'payeeName',
                                title: 'Payee Name & ID',
                                Cell: ({ data: { payeeName, payeeId } }) => {
                                    return (
                                        <span>
                                            <span>{payeeName}</span>
                                            <span
                                                className={`${CLASS_NAME}-secondary-text`}
                                            >
                                                {payeeId}
                                            </span>
                                        </span>
                                    );
                                },
                            },
                            {
                                name: 'accountName',
                                title: 'Account Name & ID',
                                Cell: ({ data: { payeeCollaborator } }) => {
                                    const label = selectCollaboratorLabel(
                                        payeeCollaborator!.collaborator
                                    );

                                    return (
                                        <span>
                                            <span>{label?.name}</span>
                                            <span
                                                className={`${CLASS_NAME}-secondary-text`}
                                            >
                                                {label?.id?.vendorId}
                                            </span>
                                        </span>
                                    );
                                },
                            },
                            {
                                name: 'payoneerProgramName',
                                title: 'Payoneer Program Name & ID',
                                Cell: ({ data: { payoneerProgram } }) => {
                                    return (
                                        <span>
                                            <span>
                                                {
                                                    payoneerProgram?.payoneerProgramName
                                                }
                                            </span>
                                            <span
                                                className={`${CLASS_NAME}-secondary-text`}
                                            >
                                                {
                                                    payoneerProgram?.payoneerProgramId
                                                }
                                            </span>
                                        </span>
                                    );
                                },
                            },
                            {
                                name: 'payoneerClientReferenceId',
                                title: 'Payoneer External ID',
                                Cell: ({
                                    data: { payoneerClientReferenceId },
                                }) => {
                                    return (
                                        <span>
                                            {payoneerClientReferenceId}
                                            <CopyButton
                                                content={
                                                    payoneerClientReferenceId
                                                }
                                            />
                                        </span>
                                    );
                                },
                            },
                            {
                                name: 'actions',
                                title: 'Actions',
                                Cell: ({ data }) => {
                                    return (
                                        <PayeeActions
                                            payee={data}
                                            refetchPayeeList={refetch}
                                        />
                                    );
                                },
                            },
                        ]}
                    />
                </Section.Table>
            </Section.Body>
        </Section>
    );
};

export default PayeeManagement;
