import React from 'react';
import { fireEvent, screen } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import {
    AbacusContractLifecycleSchedulePeriodType,
    AbacusContractLifecycleScheduleRenewalType,
} from 'src/apollo/definitions/globalTypes';
import { CONTRACT_INTERVAL_TYPES } from 'src/apollo/type-constants/contract';
import {
    CollectionPeriodPropTypes,
    CollectionPeriod,
} from 'src/components/contract-lifecycle-shared/collection-period';

describe('<CollectionPeriod/>', () => {
    const collectionPeriodDetailInterval = 6;

    const defaultProps: CollectionPeriodPropTypes = {
        contractLifecycleSchedule: {
            renewalType: `${AbacusContractLifecycleScheduleRenewalType.CONTINUOUSLY_ACTIVE}`,
            collectionPeriodDetailInterval,
            collectionPeriodDetailType:
                AbacusContractLifecycleSchedulePeriodType.MONTH,
        },
        errors: {},
        handleFormChange: jest.fn(),
        isCollectionPeriodVisible: true,
        isDisabled: false,
        setIsCollectionPeriodVisible: jest.fn(),
    };

    const renderComponent = (props: CollectionPeriodPropTypes = defaultProps) =>
        renderInAppContext(<CollectionPeriod {...props} />);

    it('renders a switch component', () => {
        renderComponent({ ...defaultProps, isCollectionPeriodVisible: false });

        const collectionPeriodSwitch = screen.getByTestId(
            'collection-period-switch'
        );

        expect(collectionPeriodSwitch).toBeInTheDocument();
        expect(collectionPeriodSwitch.nextSibling?.textContent).toEqual(
            'There is a collection period'
        );
    });

    it('renders switch component as unchecked when there is no collection period', () => {
        const contractLifecycleSchedule = {
            renewalType: `${AbacusContractLifecycleScheduleRenewalType.CONTINUOUSLY_ACTIVE}`,
            collectionPeriodDetailInterval: null,
        };

        renderComponent({
            ...defaultProps,
            contractLifecycleSchedule,
            isCollectionPeriodVisible: false,
        });

        const collectionPeriodSwitch = screen.getByTestId(
            'collection-period-switch'
        );

        expect(collectionPeriodSwitch).not.toBeChecked();
    });

    it('does not render the collection period form when the switch component is unchecked', () => {
        const contractLifecycleSchedule = {
            renewalType: `${AbacusContractLifecycleScheduleRenewalType.CONTINUOUSLY_ACTIVE}`,
            collectionPeriodDetailInterval: null,
        };

        renderComponent({
            ...defaultProps,
            contractLifecycleSchedule,
            isCollectionPeriodVisible: false,
        });

        const collectionPeriodInput = screen.queryByTestId(
            'collection-period-interval'
        );
        const collectionPeriodType = screen.queryByTestId(
            'collection-period-type'
        );

        expect(collectionPeriodInput).not.toBeInTheDocument();
        expect(collectionPeriodType).not.toBeInTheDocument();
    });

    it('renders switch component as checked when there is a collection period', () => {
        renderComponent();

        const collectionPeriodSwitch = screen.getByTestId(
            'collection-period-switch'
        );

        expect(collectionPeriodSwitch).toBeChecked();
    });

    it('renders the collection period form when switch component is checked', () => {
        renderComponent();

        const collectionPeriodInput = screen.getByTestId(
            'collection-period-interval'
        );
        const collectionPeriodType = screen.getByTestId(
            'collection-period-type'
        );

        expect(collectionPeriodInput).toBeInTheDocument();
        expect(collectionPeriodType).toBeInTheDocument();
    });

    it('renders collection period form with placeholder text when user checks switch', () => {
        const contractLifecycleSchedule = {
            renewalType: `${AbacusContractLifecycleScheduleRenewalType.CONTINUOUSLY_ACTIVE}`,
            collectionPeriodDetailInterval: null,
            collectionPeriodDetailType:
                AbacusContractLifecycleSchedulePeriodType.DAY,
        };

        renderComponent({ ...defaultProps, contractLifecycleSchedule });

        const collectionPeriodSwitch = screen.getByTestId(
            'collection-period-switch'
        );
        fireEvent.click(collectionPeriodSwitch);

        const collectionPeriodInput = screen.queryByTestId(
            'collection-period-interval'
        );
        const collectionPeriodType = screen.queryByTestId(
            'collection-period-type'
        );
        const collectionPeriodTypeDay = screen.getByText(
            CONTRACT_INTERVAL_TYPES.DAYS.label
        );

        expect(collectionPeriodInput!.innerHTML).toContain('e.g. 1');
        expect(collectionPeriodType!.textContent).toEqual('DaysMonthsYears');
        expect(collectionPeriodTypeDay.className).toContain('active');
    });

    it('hides the collection period form when user unchecks switch', () => {
        renderComponent();

        const collectionPeriodSwitch = screen.getByTestId(
            'collection-period-switch'
        );
        fireEvent.click(collectionPeriodSwitch);

        expect(defaultProps.handleFormChange).toHaveBeenCalled();
        expect(defaultProps.setIsCollectionPeriodVisible).toHaveBeenCalledWith(
            false
        );
    });

    it('renders form with collection period values if present', () => {
        renderComponent();

        const collectionPeriodInput = screen.getByTestId(
            'collection-period-interval'
        );
        const collectionPeriodType = screen.getByText(
            CONTRACT_INTERVAL_TYPES.MONTHS.label
        );

        expect(collectionPeriodInput).toBeInTheDocument();
        expect(
            screen.getByDisplayValue(collectionPeriodDetailInterval)
        ).toBeInTheDocument();

        expect(collectionPeriodType.className).toContain('active');
    });

    it('handles a collectionPeriodDetailInterval input change', () => {
        renderComponent();

        const collectionPeriodInput = screen
            .getByTestId('collection-period-interval')
            .querySelector('input')!;

        fireEvent.change(collectionPeriodInput, { target: { value: 123 } });

        expect(defaultProps.handleFormChange).toHaveBeenCalledWith(
            'collectionPeriodDetailInterval',
            123
        );
    });

    it('handles a collectionPeriodDetailType button click', () => {
        renderComponent();

        const days = screen.getByText(CONTRACT_INTERVAL_TYPES.DAYS.label);
        fireEvent.click(days);

        expect(defaultProps.handleFormChange).toHaveBeenCalledWith(
            'collectionPeriodDetailType',
            CONTRACT_INTERVAL_TYPES.DAYS.value
        );
    });

    it('renders an error if present', () => {
        const errors = { collectionPeriodDetailInterval: 'i am an error' };

        renderComponent({ ...defaultProps, errors });

        const collectionPeriodInput = screen.getByTestId(
            'collection-period-interval'
        );
        const error = screen.getByText(errors.collectionPeriodDetailInterval);

        expect(collectionPeriodInput.classList).toContain('error');
        expect(error).toBeInTheDocument();
    });

    it('renders a disabled switch and form if specified', () => {
        renderComponent({ ...defaultProps, isDisabled: true });

        const collectionPeriodSwitch = screen.getByTestId(
            'collection-period-switch'
        );
        const collectionPeriodInput = screen
            .getByTestId('collection-period-interval')
            .querySelector('input')!;
        const collectionPeriodTypeDay = screen.getByText(
            CONTRACT_INTERVAL_TYPES.DAYS.label
        );
        const collectionPeriodTypeMonth = screen.getByText(
            CONTRACT_INTERVAL_TYPES.MONTHS.label
        );
        const collectionPeriodTypeYear = screen.getByText(
            CONTRACT_INTERVAL_TYPES.YEARS.label
        );

        expect(collectionPeriodSwitch).toBeDisabled();
        expect(collectionPeriodInput).toBeDisabled();
        expect(collectionPeriodTypeDay).toBeDisabled();
        expect(collectionPeriodTypeMonth).toBeDisabled();
        expect(collectionPeriodTypeYear).toBeDisabled();
    });
});
