import React from 'react';
import {
    screen,
    fireEvent,
    waitForElementToBeRemoved,
    waitFor,
} from '@testing-library/react';
import { createIdentity, renderInAppContext } from '@theorchard/suite-testing';
import { createVatInvoice } from 'lib/factories/statementPeriod';
import * as statementPeriodResponse from 'src/__fixtures__/graphql/statement-period-response.json';
import * as statementPeriodMutations from 'src/apollo/mutations/statement-periods';
import * as paymentEntityVatQuery from 'src/apollo/queries/payment-entity-vat';
import * as referencePaymentEntityQuery from 'src/apollo/queries/reference-payment-entity/index';
import * as getVatQuery from 'src/apollo/queries/statement-periods';
import {
    TERM_COMPLETED_VAT_DOCUMENTS,
    TERM_FAILED_VAT_DOCUMENTS,
    TERM_RETRY_FAILED_VAT_DOCUMENTS,
} from 'src/components/statement-period-detail/vat-docs-status';
import { USER_FEATURES, VAT_INVOICES_POLLING_INTERVAL } from 'src/constants';
import { INVOICE_STATUS } from 'src/enum';
import {
    TERM_RETRY_BUTTON,
    TEST_ID_FAILED_DOCS_MODAL,
} from '../failed-vat-docs-modal';
import {
    TERM_GENERATE_DOCS_BUTTON,
    TERM_MODAL_CONFIRM,
} from '../generate-vat-docs';
import {
    PaymentEntityItem,
    TERM_GENERATION_FAILED,
    TERM_GENERATION_IN_PROGRESS,
    TERM_RETRY_IN_PROGRESS,
    TERM_NO_VAT_DATA_ALERT_TEXT,
    TERM_NO_VAT_DATA_ALERT_TITLE,
    Props,
} from '../payment-entity-item';

// TODO: remove all brand specific tests after ABACUS_AWAL_VAT_DOCS_TRIGGER
// vat docs generation will be available for both AWAL and KNR
describe('<PaymentEntityItem>', () => {
    const defaultProps = {
        // KNR payment entity
        paymentEntity: statementPeriodResponse.abacusStatementPeriod
            .paymentEntities[2] as Props['paymentEntity'],
        statementPeriod:
            statementPeriodResponse.abacusStatementPeriod as Props['statementPeriod'],
    };
    const statementPeriodId =
        statementPeriodResponse.abacusStatementPeriod.statementPeriodId;
    const awalEntity = statementPeriodResponse.abacusStatementPeriod
        .paymentEntities[1] as Props['paymentEntity'];

    const createVatDocs = jest.fn().mockResolvedValue({});
    const startPollingInvoicesMock = jest.fn();
    const stopPollingInvoicesMock = jest.fn();

    const invoice1 = createVatInvoice({
        statementPeriodId: statementPeriodId,
        statementAttachmentStatus: INVOICE_STATUS.IN_PROGRESS,
    });
    const invoice2 = createVatInvoice({
        statementPeriodId: statementPeriodId,
        statementAttachmentStatus: INVOICE_STATUS.COMPLETED,
    });
    const invoice3 = createVatInvoice({
        statementPeriodId: statementPeriodId,
        statementAttachmentStatus: INVOICE_STATUS.ERROR,
    });

    const invoice4 = createVatInvoice({
        statementPeriodId: statementPeriodId,
        statementAttachmentStatus: INVOICE_STATUS.RETRY,
    });

    beforeEach(() => {
        jest.spyOn(
            statementPeriodMutations,
            'useCreateVatDocs'
        ).mockReturnValue(createVatDocs);

        jest.spyOn(
            paymentEntityVatQuery,
            'usePaymentEntityVat'
        ).mockReturnValue({
            data: { vatData: true },
            loading: false,
            error: undefined,
        });

        jest.spyOn(getVatQuery, 'useGetVatInvoices').mockReturnValue({
            data: [invoice2, invoice3],
            loading: false,
            error: undefined,
            startPolling: startPollingInvoicesMock,
            stopPolling: stopPollingInvoicesMock,
        });

        jest.spyOn(
            referencePaymentEntityQuery,
            'useReferencePaymentEntityFragment'
        ).mockReturnValue({
            referencePaymentEntityId: '2',
            paymentEntityName: 'knr',
        });
    });

    afterEach(() => jest.restoreAllMocks);

    it('renders redesign-specific container', () => {
        const { container } = renderInAppContext(
            <PaymentEntityItem
                {...{
                    ...defaultProps,
                    paymentEntity: awalEntity,
                }}
            />
        );

        expect(
            container.getElementsByClassName('PaymentEntityItem-redesign')
                .length
        ).toBe(1);
    });

    it('does not render vat actions for AWAL clients', () => {
        jest.spyOn(
            referencePaymentEntityQuery,
            'useReferencePaymentEntityFragment'
        ).mockReturnValue({
            referencePaymentEntityId: '1',
            paymentEntityName: 'awal',
        });

        renderInAppContext(
            <PaymentEntityItem
                {...{
                    ...defaultProps,
                    paymentEntity: awalEntity,
                }}
            />
        );

        expect(
            screen.queryByText(TERM_GENERATE_DOCS_BUTTON)
        ).not.toBeInTheDocument();
        expect(screen.queryByTestId('vat-status')).not.toBeInTheDocument();
    });

    it('renders vat actions for AWAL clients if ABACUS_AWAL_VAT_DOCS_TRIGGER is ON', () => {
        jest.spyOn(
            referencePaymentEntityQuery,
            'useReferencePaymentEntityFragment'
        ).mockReturnValue({
            referencePaymentEntityId: '1',
            paymentEntityName: 'awal',
        });

        jest.spyOn(getVatQuery, 'useGetVatInvoices').mockReturnValue({
            data: [],
            loading: false,
            error: undefined,
            startPolling: startPollingInvoicesMock,
            stopPolling: stopPollingInvoicesMock,
        });

        renderInAppContext(
            <PaymentEntityItem
                {...{
                    ...defaultProps,
                    paymentEntity: awalEntity,
                }}
            />,
            {
                identity: createIdentity({
                    features: {
                        [USER_FEATURES.ABACUS_AWAL_VAT_DOCS_TRIGGER]: true,
                    },
                }),
            }
        );

        expect(screen.getByText(TERM_GENERATE_DOCS_BUTTON)).toBeInTheDocument();
        expect(screen.queryByTestId('vat-status')).not.toBeInTheDocument();
    });

    it('A vat action is rendered for a KNR client', () => {
        jest.spyOn(getVatQuery, 'useGetVatInvoices').mockReturnValue({
            data: [],
            loading: false,
            error: undefined,
            startPolling: startPollingInvoicesMock,
            stopPolling: stopPollingInvoicesMock,
        });

        renderInAppContext(<PaymentEntityItem {...defaultProps} />);

        expect(screen.getByText(TERM_GENERATE_DOCS_BUTTON)).toBeInTheDocument();
        expect(screen.queryByTestId('vat-status')).not.toBeInTheDocument();
    });

    describe('vat docs generation', () => {
        beforeEach(() => {
            jest.spyOn(getVatQuery, 'useGetVatInvoices').mockReturnValue({
                data: [],
                loading: false,
                error: undefined,
                startPolling: startPollingInvoicesMock,
                stopPolling: stopPollingInvoicesMock,
            });
        });

        it('triggers vat generation', async () => {
            renderInAppContext(
                <PaymentEntityItem
                    {...{
                        ...defaultProps,
                    }}
                />
            );

            const generateVatDocsButton = screen.getByText(
                TERM_GENERATE_DOCS_BUTTON
            );

            fireEvent.click(generateVatDocsButton);

            const confirmGenerateVatDocsButton =
                await screen.findByText(TERM_MODAL_CONFIRM);

            fireEvent.click(confirmGenerateVatDocsButton);

            expect(createVatDocs).toHaveBeenCalled();

            await waitFor(() => {
                expect(startPollingInvoicesMock).toHaveBeenCalledWith(
                    VAT_INVOICES_POLLING_INTERVAL
                );
            });
        });

        it('does NOT render warning alert if there is no vat data but it`s AWAL client and ABACUS_AWAL_VAT_DOCS_TRIGGER is OFF', () => {
            jest.spyOn(
                referencePaymentEntityQuery,
                'useReferencePaymentEntityFragment'
            ).mockReturnValue({
                referencePaymentEntityId: '1',
                paymentEntityName: 'awal',
            });

            jest.spyOn(
                paymentEntityVatQuery,
                'usePaymentEntityVat'
            ).mockReturnValue({
                data: { vatData: false },
                loading: false,
                error: undefined,
            });

            renderInAppContext(
                <PaymentEntityItem
                    {...{
                        ...defaultProps,
                        paymentEntity: awalEntity,
                    }}
                />
            );

            expect(
                screen.queryByText(TERM_NO_VAT_DATA_ALERT_TITLE)
            ).toBeFalsy();
        });
    });

    it('renders warning alert if there is no vat data but it`s AWAL client and ABACUS_AWAL_VAT_DOCS_TRIGGER is ON', () => {
        jest.spyOn(
            referencePaymentEntityQuery,
            'useReferencePaymentEntityFragment'
        ).mockReturnValue({
            referencePaymentEntityId: '1',
            paymentEntityName: 'awal',
        });

        jest.spyOn(
            paymentEntityVatQuery,
            'usePaymentEntityVat'
        ).mockReturnValue({
            data: { vatData: false },
            loading: false,
            error: undefined,
        });

        renderInAppContext(
            <PaymentEntityItem
                {...{
                    ...defaultProps,
                    paymentEntity: awalEntity,
                }}
            />,
            {
                identity: createIdentity({
                    features: {
                        [USER_FEATURES.ABACUS_AWAL_VAT_DOCS_TRIGGER]: true,
                    },
                }),
            }
        );

        expect(
            screen.getByText(TERM_NO_VAT_DATA_ALERT_TITLE)
        ).toBeInTheDocument();
    });

    describe('vat alerts', () => {
        it('render vat generation in progress', async () => {
            jest.spyOn(getVatQuery, 'useGetVatInvoices').mockReturnValue({
                data: [invoice1],
                loading: false,
                error: undefined,
                startPolling: startPollingInvoicesMock,
                stopPolling: stopPollingInvoicesMock,
            });
            renderInAppContext(
                <PaymentEntityItem
                    {...{
                        ...defaultProps,
                    }}
                />
            );

            const generationInProgressAlert = screen.getByText(
                TERM_GENERATION_IN_PROGRESS
            );

            expect(generationInProgressAlert).toBeInTheDocument();
        });

        it('render vat re-generation in progress', async () => {
            jest.spyOn(getVatQuery, 'useGetVatInvoices').mockReturnValue({
                data: [invoice4],
                loading: false,
                error: undefined,
                startPolling: startPollingInvoicesMock,
                stopPolling: stopPollingInvoicesMock,
            });
            renderInAppContext(
                <PaymentEntityItem
                    {...{
                        ...defaultProps,
                    }}
                />
            );

            const generationInProgressAlert = screen.getByText(
                TERM_RETRY_IN_PROGRESS
            );

            expect(generationInProgressAlert).toBeInTheDocument();
        });

        it('renders generation error alert if vat generation failed', async () => {
            const createVatDocsWithFailure = jest
                .fn()
                .mockRejectedValue('Generation failed');

            jest.spyOn(
                statementPeriodMutations,
                'useCreateVatDocs'
            ).mockReturnValue(createVatDocsWithFailure);

            jest.spyOn(
                paymentEntityVatQuery,
                'usePaymentEntityVat'
            ).mockReturnValue({
                data: { vatData: true },
                loading: false,
                error: undefined,
            });

            jest.spyOn(getVatQuery, 'useGetVatInvoices').mockReturnValue({
                data: [],
                loading: false,
                error: undefined,
                startPolling: startPollingInvoicesMock,
                stopPolling: stopPollingInvoicesMock,
            });

            renderInAppContext(
                <PaymentEntityItem
                    {...{
                        ...defaultProps,
                    }}
                />
            );

            const generateVatDocsButton = screen.getByText(
                TERM_GENERATE_DOCS_BUTTON
            );

            fireEvent.click(generateVatDocsButton);

            const confirmGenerateVatDocsButton =
                await screen.findByText(TERM_MODAL_CONFIRM);

            fireEvent.click(confirmGenerateVatDocsButton);

            expect(createVatDocsWithFailure).toHaveBeenCalled();

            const errorAlert = await screen.findByText(TERM_GENERATION_FAILED);

            expect(errorAlert).toBeInTheDocument();
            expect(stopPollingInvoicesMock).toHaveBeenCalled();
        });

        it('renders warning alert if there is no vat data', () => {
            jest.spyOn(
                paymentEntityVatQuery,
                'usePaymentEntityVat'
            ).mockReturnValue({
                data: { vatData: false },
                loading: false,
                error: undefined,
            });

            renderInAppContext(
                <PaymentEntityItem
                    {...{
                        ...defaultProps,
                    }}
                />
            );

            expect(
                screen.getByText(TERM_NO_VAT_DATA_ALERT_TITLE)
            ).toBeInTheDocument();
            expect(
                screen.getByText(TERM_NO_VAT_DATA_ALERT_TEXT)
            ).toBeInTheDocument();
        });

        it('does NOT render warning alert if there is no vat data but it`s AWAL client', () => {
            jest.spyOn(
                referencePaymentEntityQuery,
                'useReferencePaymentEntityFragment'
            ).mockReturnValue({
                referencePaymentEntityId: '1',
                paymentEntityName: 'awal',
            });

            jest.spyOn(
                paymentEntityVatQuery,
                'usePaymentEntityVat'
            ).mockReturnValue({
                data: { vatData: false },
                loading: false,
                error: undefined,
            });

            renderInAppContext(
                <PaymentEntityItem
                    {...{
                        ...defaultProps,
                        paymentEntity: awalEntity,
                    }}
                />
            );

            expect(
                screen.queryByText(TERM_NO_VAT_DATA_ALERT_TITLE)
            ).toBeFalsy();
        });
    });

    describe('vat document statuses', () => {
        it('render completed and failed statuses', () => {
            jest.spyOn(getVatQuery, 'useGetVatInvoices').mockReturnValue({
                data: [invoice2, invoice3],
                loading: false,
                error: undefined,
                startPolling: startPollingInvoicesMock,
                stopPolling: stopPollingInvoicesMock,
            });
            renderInAppContext(
                <PaymentEntityItem
                    {...{
                        ...defaultProps,
                    }}
                />
            );

            const completed = screen.getByTestId('vat-completed-status');
            const failed = screen.getByTestId('vat-failed-status');

            expect(completed).toHaveTextContent(
                `1${TERM_COMPLETED_VAT_DOCUMENTS}`
            );
            expect(failed).toHaveTextContent(`1${TERM_FAILED_VAT_DOCUMENTS}`);
        });

        it('render completed status while retrying', () => {
            jest.spyOn(getVatQuery, 'useGetVatInvoices').mockReturnValue({
                data: [invoice2, invoice3, invoice4],
                loading: false,
                error: undefined,
                startPolling: startPollingInvoicesMock,
                stopPolling: stopPollingInvoicesMock,
            });
            renderInAppContext(
                <PaymentEntityItem
                    {...{
                        ...defaultProps,
                    }}
                />
            );

            const completed = screen.getByTestId('vat-completed-status');
            const retry = screen.getByTestId('vat-retry-status');

            expect(completed).toHaveTextContent(
                `1${TERM_COMPLETED_VAT_DOCUMENTS}`
            );
            expect(retry).toHaveTextContent(TERM_RETRY_FAILED_VAT_DOCUMENTS);
        });

        it('renders neither completed nor failed while generating for the first time', () => {
            jest.spyOn(getVatQuery, 'useGetVatInvoices').mockReturnValue({
                data: [invoice1, invoice2, invoice3],
                loading: false,
                error: undefined,
                startPolling: startPollingInvoicesMock,
                stopPolling: stopPollingInvoicesMock,
            });

            renderInAppContext(
                <PaymentEntityItem
                    {...{
                        ...defaultProps,
                    }}
                />
            );

            expect(
                screen.queryByTestId('vat-completed-status')
            ).not.toBeInTheDocument();
            expect(
                screen.queryByTestId('vat-failed-status')
            ).not.toBeInTheDocument();
            expect(
                screen.queryByTestId('vat-retry-status')
            ).not.toBeInTheDocument();
        });
    });

    it('opens a modal on failed docs status click', async () => {
        renderInAppContext(
            <PaymentEntityItem
                {...{
                    ...defaultProps,
                }}
            />
        );

        const failedStatus = screen.getByTestId('vat-failed-status-btn');

        fireEvent.click(failedStatus);

        const failedVatDocsModal = await screen.findByTestId(
            TEST_ID_FAILED_DOCS_MODAL
        );

        expect(failedVatDocsModal).toBeInTheDocument();
    });

    it('triggers retrying process on "retry to generate" button click', async () => {
        renderInAppContext(
            <PaymentEntityItem
                {...{
                    ...defaultProps,
                }}
            />
        );

        const failedStatus = screen.getByTestId('vat-failed-status-btn');

        fireEvent.click(failedStatus);

        const failedVatDocsModal = await screen.findByTestId(
            TEST_ID_FAILED_DOCS_MODAL
        );
        const retryButton = screen.getByText(TERM_RETRY_BUTTON);

        fireEvent.click(retryButton);

        await waitForElementToBeRemoved(failedVatDocsModal);

        const retryingStatus = screen.getByText(
            TERM_RETRY_FAILED_VAT_DOCUMENTS
        );
        const retryingAlert = screen.getByText(TERM_RETRY_IN_PROGRESS);

        expect(retryingStatus).toBeInTheDocument();
        expect(retryingAlert).toBeInTheDocument();
    });
});
