import React from 'react';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import { contractPartyList } from 'src/__fixtures__/graphql/contract-party';
import * as contractPartyMutation from 'src/apollo/mutations/contract-party';
import * as contractQuery from 'src/apollo/queries/contract';
import * as contractPartyQuery from 'src/apollo/queries/contract-party';
import {
    noContributors,
    CONTRIBUTORS_HEADERS,
    SEARCH_TEXT,
} from 'src/apollo/type-constants/contract';
import { ContractContributorsForm } from 'src/components/contract-contributors-form/contract-contributors-form';
import { CONTRACT_TYPES } from 'src/constants';
import { getContractDetail } from 'src/urls/frontend-royalties';
import type { GetContractPartyListQuery } from 'src/apollo/queries/contract-party/__generated__/get-contract-party-list';

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

describe('<ContractContributorsForm>', () => {
    let useContractSpy: any;
    let useContractPartyDeleteSpy: any;
    const contractMock = {
        abacusContract: {
            contractId: '123',
            contractType: CONTRACT_TYPES.NEIGHBOURING_RIGHTS,
            contractName: 'Test contract',
            account: {
                accountId: '123',
                accountName: 'test name',
                accountPaymentTerm: {
                    accountPaymentTermId: '321',
                    currencyCode: 'AUD',
                    paymentEntity: {
                        paymentEntityName: 'AWAL-UK',
                        referencePaymentEntityId: '1',
                    },
                },
                accountPayee: {
                    accountPayeeId: '123',
                    payoneerPayeeId: null,
                    payoneerPayeeName: null,
                },
            },
        },
    };
    const deleteMock = jest.fn().mockResolvedValue({
        data: { abacusSoftDeleteContractParty: { deleted: true } },
    });

    const render = () => renderInAppContext(<ContractContributorsForm />);
    afterEach(jest.restoreAllMocks);

    beforeEach(() => {
        useContractSpy = jest
            .spyOn(contractQuery, 'useContractById')
            .mockReturnValue({
                data: contractMock,
                error: undefined,
                loading: false,
            });
    });

    it('renders', () => {
        render();
        expect(screen.getAllByText('Contributors')).toBeDefined();
        expect(useContractSpy).toHaveBeenCalled();
    });

    it('renders "Back to Contract" button', () => {
        render();
        const backButton = screen.getByRole('link');
        expect(backButton).toHaveTextContent('Back to Contract');
        expect(backButton.getAttribute('href')).toEqual(getContractDetail(123));
    });

    it('renders search input', () => {
        render();
        expect(screen.getByText(SEARCH_TEXT)).toBeDefined();
        expect(
            screen.getByPlaceholderText('Search by Contributor Name or ID')
        ).toBeDefined();
    });

    it('renders table headers', () => {
        render();
        const headersText = screen
            .getAllByTestId('tableBasicHeaderCellTestId')
            .map((th: any) => th.textContent);
        expect(headersText).toEqual([
            ...CONTRIBUTORS_HEADERS,
            ...CONTRIBUTORS_HEADERS,
        ]);
    });

    it('shows a message when contract is not a NR contract', () => {
        jest.spyOn(contractQuery, 'useContractById').mockReturnValue({
            data: {
                abacusContract: {
                    ...contractMock.abacusContract,
                    contractType: CONTRACT_TYPES.DISTRIBUTION,
                },
            },
            error: undefined,
            loading: false,
        });
        render();
        expect(
            screen.getByText(noContributors(CONTRACT_TYPES.DISTRIBUTION))
        ).toBeDefined();
    });

    it('calls delete mutation on click of delete icon', async () => {
        useContractPartyDeleteSpy = jest
            .spyOn(contractPartyMutation, 'useSoftDeleteContractParty')
            .mockReturnValue(deleteMock);

        jest.spyOn(contractPartyQuery, 'useContractPartyList').mockReturnValue({
            data: contractPartyList as GetContractPartyListQuery,
            error: undefined,
            loading: false,
        });
        render();
        const bodyText = screen
            .getAllByTestId('tableBasicBodyCellTestId')
            .map(td => td.textContent);

        expect(bodyText).toEqual([
            'Thomas Edward Yorke3be31516-bde0-4968-9fcf-421ebfc40a8f',
            'Test Schedule - (1)',
            '',
            'Bell, Robert E582f9577-73cb-4885-b8eb-c2ce70ac9ecb',
            'Test Schedule 3 - (2)Auto add newTest Schedule 2 - (1)',
            '',
            'Haim, Este Arielle9ad6e907-ce55-4429-ba7e-70fb90391f8f',
            'No Schedules',
            '',
        ]);

        const deleteIcons = screen.getAllByTestId('TrashGlyphIcon');
        fireEvent.click(deleteIcons[0]);
        await waitFor(() => {
            expect(useContractPartyDeleteSpy).toHaveBeenCalled();
            expect(
                screen.getByText(
                    'Contributor "Thomas Edward Yorke" removed from this contract.'
                )
            ).toBeDefined();
        });
    });
});
