import React from 'react';
import * as apollo from '@apollo/client';
import { screen } from '@testing-library/react';
import { createIdentity, renderInAppContext } from '@theorchard/suite-testing';
import { WorksheetAdjustmentsAndDetailsList } from 'src/__fixtures__/graphql/worksheet-adjustments-and-details-list';
import * as adjustmentQuery from 'src/apollo/queries/adjustment';
import { BATCH_LIST_ERROR_MESSAGE } from 'src/apollo/type-constants/adjustment';
import { AdjustmentsBatchList } from 'src/components/adjustments/adjustments-batch-list';
import { NO_BATCH_DATA, USER_FEATURES } from 'src/constants';
import type { GetAbacusWorksheetAdjustmentsAndDetailsQuery } from 'src/apollo/queries/adjustment/__generated__/get-abacus-worksheet-adjustment-and-details';
import { cloneDeep } from 'lodash-es';

describe('<AdjustmentsBatchList>', () => {
    const features = {
        [USER_FEATURES.ABACUS_ADJUSTMENTS_BATCH_PAGE_NEW_COLUMNS]: false,
        [USER_FEATURES.ABACUS_ADJUSTMENTS_BATCH_PAGE_FILTERS]: false,
    };
    let requestSpy: any;

    beforeEach(() => {
        requestSpy = jest
            .spyOn(adjustmentQuery, 'useAbacusWorksheetAdjustmentsAndDetails')
            .mockReturnValue({
                data: WorksheetAdjustmentsAndDetailsList as GetAbacusWorksheetAdjustmentsAndDetailsQuery,
                error: undefined,
                loading: false,
                refetch: jest.fn(),
            });
    });

    afterEach(jest.restoreAllMocks);

    const render = (features: { [x: number]: boolean }) =>
        renderInAppContext(<AdjustmentsBatchList />, {
            identity: createIdentity({ features }),
        });

    it('requests a list of adjustments on render', () => {
        render(features);
        expect(requestSpy).toHaveBeenCalled();
    });

    it('renders a link to the looker report for an individual batch', () => {
        render(features);
        const batchLink = screen.getByTestId(
            'lookerReportLink'
        ) as HTMLLinkElement;
        expect(batchLink).toBeDefined();
        expect(batchLink.textContent).toContain('View batch in looker');
        expect(batchLink.href).toContain(
            `https://theorchard.looker.com/looks/22123?f[dt_abacus_batch_adjustments_expenses_qa.batch_id]=`
        );
    });

    it('renders the UAT looker link when ENV is UAT', () => {
        const originalEnv = process.env.ENV;
        process.env.ENV = 'UAT';
        render(features);
        const batchLink = screen.getByTestId(
            'lookerReportLink'
        ) as HTMLLinkElement;
        expect(batchLink.href).toContain(
            'https://theorchard.looker.com/looks/26858'
        );
        process.env.ENV = originalEnv;
    });

    it('renders a table headers', () => {
        render(features);
        const tableHeaders = [
            'Account Name',
            'Account ID',
            'Contract Name',
            'Contract ID',
            'UPC',
            'Amount',
            'Currency',
            'Apply To Flowthrough Payment',
        ];
        tableHeaders.forEach((header: any) =>
            expect(screen.getAllByText(header)).toBeDefined()
        );
    });

    it('renders a list of adjustment files', async () => {
        const bodyText: any = [];
        render(features);
        document
            .querySelectorAll('div.GridTable-cell')
            .forEach((body: any) => bodyText.push(body.textContent));

        expect(bodyText).toEqual([
            'TEST 1',
            '11111',
            'TEST CONTRACT 1',
            '99999',
            '123456',
            '1.00',
            'EUR',
            'Y',
            'TEST 2',
            '22222',
            WorksheetAdjustmentsAndDetailsList
                .abacusWorksheetAdjustmentsAndDetails.items[1].contract
                .contractName,
            '99992',
            '89101112',
            '2.00',
            'EUR',
            'N',
        ]);
    });

    it('shows message when there are no adjustments', async () => {
        jest.spyOn(
            adjustmentQuery,
            'useAbacusWorksheetAdjustmentsAndDetails'
        ).mockReturnValue({
            data: {
                abacusWorksheetAdjustmentsAndDetails: {
                    items: [],
                    totalCount: 0,
                },
            },
            error: undefined,
            loading: false,
            refetch: jest.fn(),
        });
        render(features);
        expect(screen.getByText(NO_BATCH_DATA)).toBeDefined();
    });

    it('renders error message', async () => {
        const graphQLError = new apollo.ApolloError({
            graphQLErrors: undefined,
            networkError: null,
            errorMessage: 'GraphQL error',
        });
        jest.spyOn(
            adjustmentQuery,
            'useAbacusWorksheetAdjustmentsAndDetails'
        ).mockReturnValue({
            data: {
                abacusWorksheetAdjustmentsAndDetails: {
                    items: [],
                    totalCount: 0,
                },
            },
            error: graphQLError,
            loading: false,
            refetch: jest.fn(),
        });
        render(features);
        expect(screen.getByText(BATCH_LIST_ERROR_MESSAGE)).toBeDefined();
        expect(screen.getByText(NO_BATCH_DATA)).toBeDefined();
    });

    describe('when the abacus_adjustments_batch_page_new_columns feature flag is enabled', () => {
        const enabled_features = cloneDeep(features);
        enabled_features[
            USER_FEATURES.ABACUS_ADJUSTMENTS_BATCH_PAGE_NEW_COLUMNS
        ] = true;

        it('renders the new headers including Apply To Flowthrough Payment', () => {
            render(enabled_features);
            const tableHeaders = [
                'Account Name',
                'Account ID',
                'Contract Name',
                'Contract ID',
                'UPC',
                'Amount',
                'Currency',
                'Apply To Flowthrough Payment',
                'Adjustment Type',
                'Comment',
            ];
            tableHeaders.forEach((header: any) =>
                expect(screen.getAllByText(header)).toBeDefined()
            );
        });

        it('renders a list of adjustment files', () => {
            const bodyText: any = [];
            render(enabled_features);
            document
                .querySelectorAll('div.GridTable-cell')
                .forEach((body: any) => bodyText.push(body.textContent));

            expect(bodyText).toEqual([
                'TEST 1',
                '11111',
                'TEST CONTRACT 1',
                '99999',
                '123456',
                '1.00',
                'EUR',
                'Yes',
                'TEST ADJUSTMENT TYPE 1',
                'TEST NOTE 1',
                'TEST 2',
                '22222',
                WorksheetAdjustmentsAndDetailsList
                    .abacusWorksheetAdjustmentsAndDetails.items[1].contract
                    .contractName,
                '99992',
                '89101112',
                '2.00',
                'EUR',
                'No',
                'TEST ADJUSTMENT TYPE 2',
                WorksheetAdjustmentsAndDetailsList
                    .abacusWorksheetAdjustmentsAndDetails.items[1].note,
            ]);
        });

        it('should render a truncated text component for contract names and comments longer than 150 characters', async () => {
            render(enabled_features);
            const truncatedTextContractName: HTMLElement[] =
                screen.getAllByTestId('contractNameTruncatedText');
            const truncatedTextComment: HTMLElement[] = screen.getAllByTestId(
                'commentTruncatedText'
            );
            expect(truncatedTextContractName.length).toBe(1);
            expect(truncatedTextComment.length).toBe(1);
        });
    });

    describe('render filters', () => {
        it('hides contract filter dropdown when FF is disabled', () => {
            render(features);
            expect(screen.queryByText('Contract')).toBeNull();
        });

        it('renders contract filter when FF is enabled', () => {
            const features = {
                [USER_FEATURES.ABACUS_ADJUSTMENTS_BATCH_PAGE_FILTERS]: true,
            };
            render(features);
            expect(screen.getByText('Contract')).toBeDefined();
        });

        it('hides account filter when FF is disabled', () => {
            render(features);
            expect(screen.queryByText('Account')).toBeNull();
        });

        it('renders account filter when FF is enabled', () => {
            const features = {
                [USER_FEATURES.ABACUS_ADJUSTMENTS_BATCH_PAGE_FILTERS]: true,
            };
            render(features);
            expect(screen.getByText('Account')).toBeDefined();
        });
    });
});
