import React from 'react';
import { screen } from '@testing-library/react';
import { createIdentity, renderInAppContext } from '@theorchard/suite-testing';
import { contractAdvancesPendingList } from 'src/__fixtures__/graphql/contract-advances';
import { contractAdvancesPaidList } from 'src/__fixtures__/graphql/contract-advances';
import { contractAdvancesQueuedList } from 'src/__fixtures__/graphql/contract-advances';
import {
    historicalContractAdvancesEmptyList,
    historicalContractAdvancesList,
} from 'src/__fixtures__/graphql/contract-advances';
import * as contractAdvanceQuery from 'src/apollo/queries/contract-advance';
import * as featureFlag from 'src/utils/feature-flag';
import { NO_ADVANCE_RESULTS } from 'src/apollo/type-constants/advance';
import {
    ContractAdvances,
    ContractAdvancesProps,
} from 'src/components/contract-advance-list/contract-advances';
import { ABACUS_PROFILE } from 'src/constants';
import type { GetContractAdvancesPaidQuery } from 'src/apollo/queries/contract-advance/__generated__/get-contract-advances-paid-list';
import type { GetContractAdvancesPendingQuery } from 'src/apollo/queries/contract-advance/__generated__/get-contract-advances-pending-list';
import type { GetHistoricalContractAdvancesQuery } from 'src/apollo/queries/contract-advance/__generated__/get-historical-contract-advances';

jest.mock('react-router-dom', () => ({
    ...jest.requireActual('react-router-dom'),
    useParams: jest.fn().mockReturnValue({ contractId: 123 }),
}));

describe('<ContractAdvances>', () => {
    beforeEach(() => {
        jest.spyOn(featureFlag, 'isFeatureFlagEnabled').mockReturnValue(true);
    });

    afterEach(() => {
        jest.clearAllMocks();
    });

    it('renders', () => {
        const props: ContractAdvancesProps = {
            accountPaymentCurrency: 'USD',
            contractType: 'distribution',
            runControllerName: 'AWAL',
        };
        renderInAppContext(<ContractAdvances {...props} />, {
            identity: createIdentity({ profileType: ABACUS_PROFILE }),
        });

        const newAdvanceButton = screen.getByTestId('add-contract-advance');
        expect(newAdvanceButton).not.toHaveAttribute('disabled');
    });

    it('disables "Add" button when accountPaymentCurrency is missing', () => {
        renderInAppContext(<ContractAdvances />, {
            identity: createIdentity({ profileType: ABACUS_PROFILE }),
        });
        const newAdvanceButton = screen.getByTestId('add-contract-advance');
        expect(newAdvanceButton).toHaveAttribute('disabled');
    });

    it('button link when there is no advance & recoupment', () => {
        const props: any = {
            accountPaymentCurrency: 'USD',
        };
        renderInAppContext(<ContractAdvances {...props} />, {
            identity: createIdentity({ profileType: ABACUS_PROFILE }),
        });
        const link = screen.getByRole('link');
        expect(link.getAttribute('href')).toEqual('/contract/123/advance/new');
    });

    it('show message when there are no pending, queued and paid advances', async () => {
        jest.spyOn(
            contractAdvanceQuery,
            'useContractAdvancesPendingList'
        ).mockReturnValue({
            data: {
                abacusContractAdvancesPending: { items: [], totalCount: 0 },
            },
            loading: false,
            error: undefined,
        });
        jest.spyOn(
            contractAdvanceQuery,
            'useContractAdvancesPaidList'
        ).mockReturnValue({
            data: { abacusContractAdvancesPaid: { items: [], totalCount: 0 } },
            loading: false,
            error: undefined,
        });
        jest.spyOn(
            contractAdvanceQuery,
            'useContractAdvancesByStatusList'
        ).mockReturnValue({
            data: {
                abacusContract: {
                    contractId: '1',
                    contractAdvances: { items: [], totalCount: 0 },
                },
            },
            loading: false,
            error: undefined,
        });
        jest.spyOn(
            contractAdvanceQuery,
            'useHistoricalContractAdvances'
        ).mockReturnValue({
            data: {
                abacusContract: {
                    contractId: '1',
                    historicalContractAdvances: { items: [], totalCount: 0 },
                },
            },
            loading: false,
            error: undefined,
        });
        const props: any = {
            accountPaymentCurrency: 'USD',
            contractType: 'distribution',
            runControllerName: 'AWAL',
        };
        renderInAppContext(<ContractAdvances {...props} />);

        const noFoundMsg = await screen.findByText(NO_ADVANCE_RESULTS);
        expect(noFoundMsg).toBeDefined();
    });

    it('renders tables', async () => {
        jest.spyOn(
            contractAdvanceQuery,
            'useContractAdvancesPendingList'
        ).mockReturnValue({
            data: contractAdvancesPendingList as GetContractAdvancesPendingQuery,
            loading: false,
            error: undefined,
        });
        jest.spyOn(
            contractAdvanceQuery,
            'useContractAdvancesPaidList'
        ).mockReturnValue({
            data: contractAdvancesPaidList as GetContractAdvancesPaidQuery,
            loading: false,
            error: undefined,
        });
        jest.spyOn(
            contractAdvanceQuery,
            'useContractAdvancesByStatusList'
        ).mockReturnValue({
            data: contractAdvancesQueuedList,
            loading: false,
            error: undefined,
        });
        jest.spyOn(
            contractAdvanceQuery,
            'useHistoricalContractAdvances'
        ).mockReturnValue({
            data: historicalContractAdvancesList as GetHistoricalContractAdvancesQuery,
            loading: false,
            error: undefined,
        });
        const props: any = {
            accountPaymentCurrency: 'USD',
            contractType: 'distribution',
            runControllerName: 'AWAL',
        };
        renderInAppContext(<ContractAdvances {...props} />);
        expect(await screen.findByText('Not Paid')).toBeDefined();
        expect(await screen.findByText('Queued')).toBeDefined();
        expect(await screen.findByText('Paid')).toBeDefined();
        expect(
            await screen.findByText('Historical Advances Paid via OA')
        ).toBeDefined();
    });

    it('renders tables error', async () => {
        jest.spyOn(
            contractAdvanceQuery,
            'useContractAdvancesPendingList'
        ).mockReturnValue({
            data: undefined,
            loading: false,
            error: { message: 'pending_error' } as any,
        });
        jest.spyOn(
            contractAdvanceQuery,
            'useContractAdvancesPaidList'
        ).mockReturnValue({
            data: undefined,
            loading: false,
            error: { message: 'paid_error' } as any,
        });
        jest.spyOn(
            contractAdvanceQuery,
            'useContractAdvancesByStatusList'
        ).mockReturnValue({
            data: undefined,
            loading: false,
            error: { message: 'queued_error' } as any,
        });
        jest.spyOn(
            contractAdvanceQuery,
            'useHistoricalContractAdvances'
        ).mockReturnValue({
            data: undefined,
            loading: false,
            error: { message: 'historical_error' } as any,
        });
        const props: any = {
            accountPaymentCurrency: 'USD',
            contractType: 'distribution',
            runControllerName: 'AWAL',
        };
        renderInAppContext(<ContractAdvances {...props} />);
        expect(await screen.findByText('pending_error')).toBeDefined();
        expect(await screen.findByText('queued_error')).toBeDefined();
        expect(await screen.findByText('paid_error')).toBeDefined();
        expect(await screen.findByText('historical_error')).toBeDefined();
    });

    it('hides the historical advances table when no historical advances are available', () => {
        jest.spyOn(
            contractAdvanceQuery,
            'useHistoricalContractAdvances'
        ).mockReturnValue({
            data: historicalContractAdvancesEmptyList as GetHistoricalContractAdvancesQuery,
            loading: false,
            error: undefined,
        });
        const props: any = {
            accountPaymentCurrency: 'USD',
            contractType: 'distribution',
            runControllerName: 'AWAL',
        };
        renderInAppContext(<ContractAdvances {...props} />);
        expect(
            screen.queryByText('Historical Advances Paid via OA')
        ).toBeNull();
    });

    it('hides the historical advances table for NR contracts', () => {
        jest.spyOn(
            contractAdvanceQuery,
            'useHistoricalContractAdvances'
        ).mockReturnValue({
            data: historicalContractAdvancesList as GetHistoricalContractAdvancesQuery,
            loading: false,
            error: undefined,
        });
        const props: any = {
            accountPaymentCurrency: 'USD',
            contractType: 'neighbouring_rights',
            runControllerName: 'AWAL',
        };
        renderInAppContext(<ContractAdvances {...props} />);
        expect(
            screen.queryByText('Historical Advances Paid via OA')
        ).toBeNull();
    });

    it('hides the historical advances table for the "KNR Label" run controller contract', () => {
        jest.spyOn(
            contractAdvanceQuery,
            'useHistoricalContractAdvances'
        ).mockReturnValue({
            data: historicalContractAdvancesList as GetHistoricalContractAdvancesQuery,
            loading: false,
            error: undefined,
        });
        const props: any = {
            accountPaymentCurrency: 'USD',
            contractType: 'distribution',
            runControllerName: 'KNR Label',
        };
        renderInAppContext(<ContractAdvances {...props} />);
        expect(
            screen.queryByText('Historical Advances Paid via OA')
        ).toBeNull();
    });
});
