import React from 'react';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import { Route } from 'react-router-dom';
import { contributorSchedule } from 'src/__fixtures__/graphql/schedule';
import * as scheduleMuatations from 'src/apollo/mutations/schedule';
import * as contributionsQuery from 'src/apollo/queries/nr-contributions';
import * as scheduleQuery from 'src/apollo/queries/schedule';
import EditScheduleForm from 'src/components/schedule-form/edit-schedule-form';
import { AUTO_ADD_TEXT } from 'src/constants';
import {
    editContributorSchedule,
    getContributorScheduleDetail,
} from 'src/urls/frontend-royalties';

describe('<EditScheduleForm>', () => {
    let requestSpy: any;
    let updateScheduleRequestSpy: any;
    const updateScheduleMock = jest.fn().mockResolvedValue({});
    const response = {
        data: { nrContributions: { totalCount: 0, items: [] } },
        error: undefined,
        loading: false,
        fetchMore: jest.fn(),
        fetchNextExistingPage: jest.fn(),
    };
    const contributorId = '1ec7c1bf-2318-4052-9406-a3e35a620bd3';
    const scheduleId = '1';

    const render = () =>
        renderInAppContext(
            <Route path="/contributor/:contributorId/schedule/:scheduleId/edit">
                <EditScheduleForm />
            </Route>,
            { pathname: editContributorSchedule(contributorId, scheduleId) }
        );

    afterEach(jest.restoreAllMocks);
    beforeEach(() => {
        requestSpy = jest
            .spyOn(scheduleQuery, 'useScheduleById')
            .mockReturnValue({
                data: contributorSchedule,
                error: undefined,
                loading: false,
            });
        updateScheduleRequestSpy = jest
            .spyOn(scheduleMuatations, 'useUpdateSchedule')
            .mockReturnValue(updateScheduleMock);

        jest.spyOn(
            contributionsQuery,
            'useNRContributionsList'
        ).mockReturnValue(response);
    });

    it('renders', async () => {
        const { container } = render();
        await waitFor(() => expect(container).toBeDefined());
    });

    it('requests schedule details on render', async () => {
        render();
        await waitFor(() => expect(requestSpy).toHaveBeenCalled());
    });

    it('renders schedule name and autoschedule checkbox', async () => {
        render();
        const input = screen.getByTestId('scheduleName');
        await waitFor(() => {
            expect(input).toHaveDisplayValue(
                contributorSchedule.abacusSchedule.scheduleName
            );
            expect(screen.getByText(AUTO_ADD_TEXT)).toBeDefined();
        });
    });

    it('renders unassigned and assigned contributions containers', async () => {
        render();
        await waitFor(() => {
            expect(screen.getByText('Unassigned Contributions')).toBeDefined();
            expect(screen.getByText('Assigned Contributions')).toBeDefined();
            expect(
                screen.getAllByText('Sorry, no results found.')
            ).toBeDefined();
        });
    });

    it('renders message when there is no contributor schedule', async () => {
        jest.spyOn(scheduleQuery, 'useScheduleById').mockReturnValue({
            data: undefined,
            error: undefined,
            loading: false,
        });
        render();
        await waitFor(() => {
            expect(
                screen.getByText('There is no data available')
            ).toBeDefined();
        });
    });

    it('updates data when save button is clicked', async () => {
        render();

        const saveButton = screen.getByRole('button', { name: 'Save' });
        fireEvent.click(saveButton);
        await waitFor(() => {
            expect(updateScheduleRequestSpy).toHaveBeenCalled();
        });
    });

    it('redirects to schedule detail page when cancel button is clicked', async () => {
        render();
        const cancelButton = screen.getByRole('link', { name: 'Cancel' });
        await waitFor(() => {
            expect(cancelButton.getAttribute('href')).toEqual(
                getContributorScheduleDetail(contributorId, scheduleId)
            );
        });
    });

    it('shows error when schedule name input is blank', async () => {
        render();
        const input = screen.getByTestId('scheduleName');
        const saveButton = screen.getByRole('button', { name: 'Save' });
        fireEvent.change(input, { target: { value: '' } });
        fireEvent.click(saveButton);
        await waitFor(() => {
            expect(screen.getByText('Name cannot be blank')).toBeDefined();
        });
    });
});
