import React from 'react';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import { ToastProvider } from '@theorchard/suite-components';
import { renderInAppContext } from '@theorchard/suite-testing';
import { contractPartyList } from 'src/__fixtures__/graphql/contract-party';
import { contributorList } from 'src/__fixtures__/graphql/contributors';
import * as contractPartyMutation from 'src/apollo/mutations/contract-party';
import * as contributorQuery from 'src/apollo/queries/nr-contributors';
import {
    CONTRIBUTORS_HEADERS,
    SEARCH_TEXT,
} from 'src/apollo/type-constants/contract';
import {
    ContributorsSearch,
    ContributorsSearchPropType,
} from 'src/components/contract-contributors-form/contributors-search';
import type { NrContributorsSearchQuery } from 'src/apollo/queries/nr-contributors/__generated__/nr-contributor-search';

describe('<ContributorsSearch>', () => {
    const addedContractContributors = [
        contractPartyList.abacusContractParties.items[2],
    ] as ContributorsSearchPropType['addedContractContributors'];

    const render = (props: ContributorsSearchPropType) =>
        renderInAppContext(
            <ToastProvider>
                <ContributorsSearch {...props} />
            </ToastProvider>
        );
    let searchRequestSpy: any;
    let createContractPartyRequestSpy: any;
    const props: ContributorsSearchPropType = {
        addedContractContributors,
        addingContributorId: '',
        isClearFilter: false,
        setAddingContributorId: jest.fn(),
        setIsClearFilter: jest.fn(),
    };
    const addContractParty = jest.fn().mockResolvedValue({
        data: {
            abacusCreateContractParty:
                contractPartyList.abacusContractParties.items[0],
        },
        loading: false,
    });
    const searchResults = {
        nrContributorSearch: {
            contributors: [
                contributorList.nrContributors.contributors[0],
                contributorList.nrContributors.contributors[1],
            ],
            totalCount: 2,
        },
    };
    afterEach(jest.restoreAllMocks);

    beforeEach(() => {
        const getNRContributorSearchResult = jest
            .fn()
            .mockReturnValue(searchResults);
        searchRequestSpy = jest
            .spyOn(contributorQuery, 'useNRContributorSearch')
            .mockReturnValue({
                data: searchResults as NrContributorsSearchQuery,
                loading: false,
                error: undefined,
                getNRContributorSearchResult: getNRContributorSearchResult,
            });
        createContractPartyRequestSpy = jest
            .spyOn(contractPartyMutation, 'useCreateParty')
            .mockReturnValue(addContractParty);
    });

    it('renders', () => {
        render(props);
        expect(screen.getByText(SEARCH_TEXT)).toBeDefined();
    });

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

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

    it('on search, search request has been called', () => {
        render(props);
        const input = screen.getByTestId('searchFieldInput');
        fireEvent.change(input, { target: { value: 'Thomas' } });
        expect(searchRequestSpy).toHaveBeenCalled();
    });

    it('renders search results', async () => {
        render(props);
        const input = screen.getByTestId('searchFieldInput');
        fireEvent.change(input, { target: { value: 'Thomas' } });

        await waitFor(() => {
            const bodyText = screen
                .getAllByTestId('tableBasicBodyCellTestId')
                .map(td => td.textContent);
            expect(bodyText).toEqual([
                'Abbott, Judith1ec7c1bf-2318-4052-9406-a3e35a620bd3',
                'alt something - (2)Auto add newsomething - (3)',
                'Add to this Contract',
                'Thomas Edward Yorke3be31516-bde0-4968-9fcf-421ebfc40a8f',
                'something - (1)',
                'Add to this Contract',
            ]);
        });
    });

    it('clears filters when clicked', async () => {
        render(props);
        const input = screen.getByTestId('searchFieldInput');
        fireEvent.change(input, { target: { value: 'Thomas' } });
        const clearFilters = await screen.findByText('Clear Filters');
        fireEvent.click(clearFilters);

        const bodyText = screen.queryAllByTestId('tableBasicBodyCellTestId');
        expect(bodyText).toEqual([]);
        expect(input).toHaveDisplayValue('');
    });

    it('adds contributor to contract upon clicking "Add to this Contract"', async () => {
        render(props);
        const input = screen.getByTestId('searchFieldInput');
        fireEvent.change(input, { target: { value: 'Thomas' } });

        const addToContractLinks = await screen.findAllByText(
            'Add to this Contract'
        );
        fireEvent.click(addToContractLinks[1]);

        expect(createContractPartyRequestSpy).toHaveBeenCalled();

        await waitFor(() => {
            const bodyText = screen
                .queryAllByTestId('tableBasicBodyCellTestId')
                .map(td => td.textContent);
            expect(bodyText).toEqual([
                'Abbott, Judith1ec7c1bf-2318-4052-9406-a3e35a620bd3',
                'alt something - (2)Auto add newsomething - (3)',
                'Add to this Contract',
            ]);
            expect(
                screen.getByText(
                    'Contributor "Thomas Edward Yorke" successfully added to this contract.'
                )
            ).toBeDefined();
        });
    });
});
