﻿import React from 'react';
import { fireEvent, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import { Segment } from '@theorchard/suite-frontend';
import { renderInAppContext } from '@theorchard/suite-testing';
import { getMergedProduct } from 'lib/mockProductData';
import {
    CR_CATEGORY,
    ESCALATION_QUEUE_ID,
    INITIAL_QUEUE_ID,
} from 'src/constants';
import * as reviewEscalationGroups from 'src/data/queries/reviewEscalationGroups/reviewEscalationGroups';
import ProductModalQueueMoveSidecar, {
    CLASS_NAME,
    Props,
} from '../productModalQueueMoveSidecar';

const mockReviewEscalationGroups = [
    {
        targetGroupId: 1,
        displayName: 'default_group',
        targets: [
            {
                movedToTargetId: 10,
                targetGroupId: 1,
                email: null,
                escalationType: 'option-1',
                showInUI: true,
            },
            {
                movedToTargetId: 11,
                targetGroupId: 1,
                email: null,
                escalationType: 'option-2',
                showInUI: true,
            },
        ],
    },
    {
        targetGroupId: 2,
        displayName: 'escalation_group',
        targets: [
            {
                movedToTargetId: 12,
                targetGroupId: 2,
                email: null,
                escalationType: 'option-3',
                showInUI: true,
            },
        ],
    },
    {
        targetGroupId: 3,
        displayName: 'group-3',
        targets: [
            {
                movedToTargetId: 13,
                targetGroupId: 3,
                email: null,
                escalationType: 'option-4',
                showInUI: true,
            },
        ],
    },
];

const defaultProps = {
    isOpen: true,
    closeModal: jest.fn(),
    currentQueueName: INITIAL_QUEUE_ID,
    product: getMergedProduct({ productId: 10 }),
    onQueueMove: jest.fn(),
};

describe('ProductModalQueueMoveSidecar', () => {
    beforeEach(() => {
        jest.spyOn(
            reviewEscalationGroups,
            'useReviewEscalationGroupsQuery'
        ).mockReturnValue({
            data: { reviewEscalationGroups: mockReviewEscalationGroups },
            loading: false,
            error: undefined,
        });
    });

    afterEach(() => {
        jest.clearAllMocks();
        jest.restoreAllMocks();
    });

    const renderComponent = (props: Partial<Props> = {}) =>
        renderInAppContext(
            <ProductModalQueueMoveSidecar {...defaultProps} {...props} />
        );

    test('render sidecar and form', () => {
        const { getByTestId, queryByTestId } = renderComponent();
        expect(getByTestId('ProductModalQueueMoveSidecar')).toBeInTheDocument();
        expect(
            getByTestId('ProductModalQueueMoveSidecar-Form')
        ).toBeInTheDocument();
        expect(getByTestId('form-group-move')).toBeInTheDocument();
        expect(
            queryByTestId('form-group-target-group')
        ).not.toBeInTheDocument();
        expect(
            queryByTestId('form-group-escalation-type')
        ).not.toBeInTheDocument();
        expect(getByTestId('form-group-note')).toBeInTheDocument();
    });

    test('target group form control', async () => {
        const { getByTestId } = renderComponent({
            productTargetGroup: { displayName: '', id: '1' },
            currentQueueName: INITIAL_QUEUE_ID,
        });

        const selectInput = getByTestId('SuiteSelectInput');
        fireEvent.click(selectInput);

        const group = getByTestId('form-control-move');
        expect(group).toBeInTheDocument();
    });

    test('escalation type form control', async () => {
        const { getByTestId, findByText } = renderComponent({
            productTargetGroup: { displayName: '', id: '1' },
            currentQueueName: ESCALATION_QUEUE_ID,
        });

        const escalationForm = getByTestId('form-group-target-group');
        expect(escalationForm).toBeInTheDocument();

        const selectInput = getByTestId('SuiteSelectInput');
        fireEvent.click(selectInput);

        const escalationGroupOption = await findByText('escalation_group');
        expect(escalationGroupOption).toBeInTheDocument();
    });

    test('renders escalation type definitions note', async () => {
        const { getByTestId, findByText } = renderComponent({
            productTargetGroup: { displayName: '', id: '1' },
            currentQueueName: ESCALATION_QUEUE_ID,
        });

        const selectInput = getByTestId('SuiteSelectInput');
        fireEvent.click(selectInput);

        const escalationGroupOption = await findByText('escalation_group');
        fireEvent.click(escalationGroupOption);

        const formGroup = getByTestId('form-group-escalation-type');
        const typeDefinitions = formGroup.querySelector(
            `.${CLASS_NAME}-type-definitions`
        );

        expect(typeDefinitions).toBeVisible();
    });

    test('note form control', async () => {
        const { getByTestId } = renderComponent({
            productTargetGroup: { displayName: '', id: '1' },
            currentQueueName: INITIAL_QUEUE_ID,
        });

        const noteFormControl = getByTestId('form-control-note');
        fireEvent.change(noteFormControl, {
            target: { value: 'You have to move!' },
        });

        expect(noteFormControl).toHaveValue('You have to move!');
    });

    test('default move save & confirm', async () => {
        const { getByTestId, getByRole, findByText } = renderComponent({
            productTargetGroup: { displayName: '', id: '1' },
            currentQueueName: INITIAL_QUEUE_ID,
        });

        // Select target group
        const moveSelectInput = getByTestId('SuiteSelectInput');
        fireEvent.click(moveSelectInput);

        const underInvestigationOption = await findByText(
            'Under Investigation'
        );
        fireEvent.click(underInvestigationOption);

        // Fill the note
        const noteFormControl = getByTestId('form-control-note');
        fireEvent.change(noteFormControl, {
            target: { value: 'You have to move!' },
        });

        // Click save button
        const saveButton = getByRole('button', { name: 'save' });
        fireEvent.click(saveButton);

        await waitFor(() => {
            expect(defaultProps.onQueueMove).toHaveBeenCalled();
        });
    });

    test('escalation save & confirm', async () => {
        const { getByTestId, getByRole, findByText } = renderComponent({
            productTargetGroup: { displayName: '', id: '1' },
            currentQueueName: ESCALATION_QUEUE_ID,
        });

        // Select target group
        const targetGroupSelectInput = getByTestId('SuiteSelectInput');
        fireEvent.click(targetGroupSelectInput);

        const escalationGroupOption = await findByText('escalation_group');
        fireEvent.click(escalationGroupOption);

        // Select escalation type
        const escalationTypeSelectInput = getByTestId(
            'form-control-escalation-type'
        ).querySelector('[data-testid="SuiteSelectInput"]') as HTMLElement;
        fireEvent.click(escalationTypeSelectInput);

        const escalationTypeOption = await findByText('option-3');
        fireEvent.click(escalationTypeOption);

        // Type in Escalation Note
        const noteFormControl = getByTestId('form-control-note');
        fireEvent.change(noteFormControl, {
            target: { value: 'You have to move!' },
        });

        const saveButton = getByRole('button', { name: 'save' });
        fireEvent.click(saveButton);

        await waitFor(() => {
            expect(defaultProps.onQueueMove).toHaveBeenCalled();
        });
    });

    test('return & close', async () => {
        const { getByRole } = renderComponent();
        const cancelButton = getByRole('button', { name: 'Return' });
        fireEvent.click(cancelButton);
        await waitFor(() => {
            expect(defaultProps.closeModal).toHaveBeenCalled();
        });
    });

    describe('tracks dropdown event', () => {
        test('track click - queue move', async () => {
            const segmentTrack = jest.spyOn(Segment, 'trackEvent');
            const timestamp = Date.now();
            jest.useFakeTimers().setSystemTime(timestamp);

            const { getByTestId, findByText } = renderComponent();

            const moveSelectInput = getByTestId('SuiteSelectInput');
            fireEvent.click(moveSelectInput);

            const selectOption = await findByText('Under Investigation');
            fireEvent.click(selectOption);

            const eventLabel =
                'Where would you like to send this product to? - In Revision';
            expect(segmentTrack).toHaveBeenCalledWith(
                'Click',
                {
                    category: CR_CATEGORY,
                    value: timestamp,
                    label: eventLabel,
                    accountId: 123,
                    subaccountId: 333,
                    productId: 10,
                },
                eventLabel
            );
        });

        test('track click - target group', async () => {
            const segmentTrack = jest.spyOn(Segment, 'trackEvent');
            const timestamp = Date.now();
            jest.useFakeTimers().setSystemTime(timestamp);

            const { getAllByTestId, findByText } = renderComponent({
                currentQueueName: ESCALATION_QUEUE_ID,
                productTargetGroup: { displayName: '', id: '1' },
            });

            const allSelectInputs = getAllByTestId('SuiteSelectInput');
            expect(allSelectInputs).toHaveLength(1);
            const targetGroupFormControl = allSelectInputs[0];
            fireEvent.click(targetGroupFormControl);

            const selectOption = await findByText('escalation_group');
            fireEvent.click(selectOption);

            const eventLabel =
                'Who would you like to send this product to? - In Revision';
            expect(segmentTrack).toHaveBeenCalledWith(
                'Click',
                {
                    category: CR_CATEGORY,
                    value: timestamp,
                    label: eventLabel,
                    accountId: 123,
                    subaccountId: 333,
                    productId: 10,
                },
                eventLabel
            );
        });

        test('track click - escalation type', async () => {
            const segmentTrack = jest.spyOn(Segment, 'trackEvent');
            const timestamp = Date.now();
            jest.useFakeTimers().setSystemTime(timestamp);

            const { getAllByTestId, getByTestId, findByText } = renderComponent(
                {
                    currentQueueName: ESCALATION_QUEUE_ID,
                    productTargetGroup: { displayName: '', id: '1' },
                }
            );

            // Select target group
            const [targetGroupSelectInput] = getAllByTestId('SuiteSelectInput');
            fireEvent.click(targetGroupSelectInput);

            const escalationGroupOption = await findByText('escalation_group');
            fireEvent.click(escalationGroupOption);

            // Select escalation type
            const escalationTypeSelectInput = getByTestId(
                'form-control-escalation-type'
            ).querySelector('[data-testid="SuiteSelectInput"]') as HTMLElement;
            fireEvent.click(escalationTypeSelectInput);

            const selectOption = await findByText('option-3');
            fireEvent.click(selectOption);

            const eventLabel = 'Escalation Type - In Revision';
            expect(segmentTrack).toHaveBeenCalledWith(
                'Click',
                {
                    category: CR_CATEGORY,
                    value: timestamp,
                    label: eventLabel,
                    accountId: 123,
                    subaccountId: 333,
                    productId: 10,
                },
                eventLabel
            );
        });
    });
});
