import React from 'react';
import { fireEvent, screen } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import { Route } from 'react-router-dom';
import {
    contributorDetail,
    formattedContributorSchedules,
} from 'src/__fixtures__/graphql/contributors';
import * as nrContributorQuery from 'src/apollo/queries/nr-contributors';
import ContributorDetail from 'src/components/contributor-detail/contributor-detail';
import {
    editContributorSchedule,
    getContributorScheduleDetail,
    getContributorDetail,
} from 'src/urls/frontend-royalties';
import * as scheduleUtils from 'src/utils/schedules';

describe('<ContributorDetail>', () => {
    let useNRContributorSpy: any;
    const contributorId = contributorDetail.nrContributorById.id;

    afterEach(jest.restoreAllMocks);

    beforeEach(() => {
        useNRContributorSpy = jest
            .spyOn(nrContributorQuery, 'useNRContributor')
            .mockReturnValue({
                data: contributorDetail,
                error: undefined,
                loading: false,
            });
        jest.spyOn(scheduleUtils, 'formatSchedulesList').mockReturnValue(
            formattedContributorSchedules
        );
        jest.spyOn(scheduleUtils, 'reorderSchedulesList').mockReturnValue(
            contributorDetail.nrContributorById.abacusSchedules
        );
    });

    const render = () =>
        renderInAppContext(
            <Route path="/contributor/:contributorId">
                <ContributorDetail />
            </Route>,
            { pathname: getContributorDetail(contributorId) }
        );

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

    it('requests contributor detail on render', () => {
        render();
        expect(useNRContributorSpy).toHaveBeenCalledWith(contributorId);
    });

    it('displays the contributor name', () => {
        render();
        expect(
            screen.getByText(contributorDetail.nrContributorById.name, {
                ignore: '.breadcrumb-item',
            })
        ).toBeDefined();
    });

    it('opens a modal with an add schedule form when Add Schedule button is clicked', () => {
        render();

        const addScheduleBtn = screen.getByTestId('addScheduleBtn');
        fireEvent.click(addScheduleBtn);

        expect(screen.getByText('New Schedule')).toBeDefined();
        expect(screen.getByText('Create')).toBeDefined();
        expect(screen.getByText('Cancel')).toBeDefined();
    });

    describe('Unassigned Contributions', () => {
        it('renders a section to display unassigned contributions', () => {
            render();
            expect(screen.getByText('Unassigned Contributions')).toBeDefined();
        });
    });

    describe('Contribution Schedules', () => {
        it('renders a section to display contributor schedules', () => {
            render();
            expect(
                screen.getByText('Schedules (# Of Contributions)')
            ).toBeDefined();
        });

        it('displays a list of schedules by name (with number of assigned contributions)', () => {
            render();
            const { abacusSchedules } = contributorDetail.nrContributorById;

            const firstScheduleText = `${abacusSchedules[0].scheduleName} (${abacusSchedules[0].scheduleAttachments.totalCount})`;
            const secondScheduleText = `${abacusSchedules[1].scheduleName} (${abacusSchedules[1].scheduleAttachments.totalCount})`;

            expect(screen.getByText(firstScheduleText)).toBeDefined();
            expect(screen.getByText(secondScheduleText)).toBeDefined();
        });

        it('renders links to the schedule detail view page', () => {
            render();
            const { abacusSchedules } = contributorDetail.nrContributorById;

            const firstScheduleText = `${abacusSchedules[0].scheduleName} (${abacusSchedules[0].scheduleAttachments.totalCount})`;
            const secondScheduleText = `${abacusSchedules[1].scheduleName} (${abacusSchedules[1].scheduleAttachments.totalCount})`;

            const firstSchedule = screen.getByText(firstScheduleText);
            const secondSchedule = screen.getByText(secondScheduleText);

            expect(firstSchedule.getAttribute('href')).toContain(
                getContributorScheduleDetail(
                    contributorId,
                    abacusSchedules[0].scheduleId
                )
            );
            expect(secondSchedule.getAttribute('href')).toContain(
                getContributorScheduleDetail(
                    contributorId,
                    abacusSchedules[1].scheduleId
                )
            );
        });

        it('displays an auto-add indicator for auto-add schedules', () => {
            render();
            expect(screen.getByText('Auto add new')).toBeDefined();
        });

        it('renders an edit icon for each schedule', () => {
            const { container } = render();
            const editButtons =
                container.getElementsByClassName('EditSchedule');

            expect(editButtons.length).toEqual(
                contributorDetail.nrContributorById.abacusSchedules.length
            );
        });

        it('renders links to schedule edit page', () => {
            render();
            const editButtons = screen.getAllByRole('link');
            const { abacusSchedules } = contributorDetail.nrContributorById;

            expect(editButtons[3].getAttribute('href')).toContain(
                editContributorSchedule(
                    contributorId,
                    abacusSchedules[0].scheduleId
                )
            );
            expect(editButtons[5].getAttribute('href')).toContain(
                editContributorSchedule(
                    contributorId,
                    abacusSchedules[1].scheduleId
                )
            );
        });

        it('displays a message when contributor has no schedules', () => {
            const contributorWithNoSchedule = contributorDetail;
            contributorWithNoSchedule.nrContributorById.abacusSchedules = [];

            jest.spyOn(nrContributorQuery, 'useNRContributor').mockReturnValue({
                data: contributorWithNoSchedule,
                error: undefined,
                loading: false,
            });
            jest.spyOn(scheduleUtils, 'formatSchedulesList').mockReturnValue(
                []
            );
            jest.spyOn(scheduleUtils, 'reorderSchedulesList').mockReturnValue(
                []
            );

            render();
            expect(screen.getByText('No Schedules')).toBeDefined();
        });
    });
});
