import React from 'react';
import { fireEvent, screen } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import * as statementPeriodResponse from 'src/__fixtures__/graphql/statement-period-response.json';
import * as createCloseBalanceEventMutation from 'src/apollo/mutations/close-balance';
import Balance, {
    BalanceProps,
    TERM_CLOSE_BALANCE_ERR_ALERT_TITLE,
    TERM_PENDING_ADJUSTMENTS_ALERT,
    TERM_RELEASE_RESERVES_ALERT,
    TERM_ADJUSTMENTS_LINK_TEXT,
    TERM_BODY_MESSAGE_INIT,
    TERM_BODY_MESSAGE_RUNNING,
    TERM_BODY_MESSAGE_COMPLETE,
} from '../balance';

describe('<Balance>', () => {
    const defaultProps = {
        paymentEntity: statementPeriodResponse.abacusStatementPeriod
            .paymentEntities[0] as BalanceProps['paymentEntity'],
        statementPeriod:
            statementPeriodResponse.abacusStatementPeriod as BalanceProps['statementPeriod'],
        setCloseBalanceStatus: jest.fn(),
    };
    const releaseResrvesCompleted = {
        abacusStateId: '3',
        actionName: 'release_reserves',
        actionStatus: 'complete',
        message: null,
    };

    const createCloseBalanceEvent = jest.fn().mockResolvedValue({});

    afterEach(jest.restoreAllMocks);
    beforeEach(() => {
        jest.spyOn(
            createCloseBalanceEventMutation,
            'useCreateCloseBalanceEvent'
        ).mockReturnValue({ createCloseBalanceEvent, loading: false });
    });

    const render = (props: BalanceProps) =>
        renderInAppContext(<Balance {...props} />);

    it('renders "The balance cannot be closed" state', () => {
        render(defaultProps);

        expect(screen.getByText('Balance')).toBeDefined();
        expect(screen.getByText('Close')).toBeDefined();
        expect(screen.getByTestId('StepIndicator')).toBeDefined();
        expect(screen.getByTestId('closeBalanceButton')).toHaveAttribute(
            'disabled'
        );

        expect(
            screen.getAllByText(TERM_CLOSE_BALANCE_ERR_ALERT_TITLE)
        ).toHaveLength(2);
        expect(screen.getByText(TERM_PENDING_ADJUSTMENTS_ALERT)).toBeDefined();
        expect(screen.getByText(TERM_RELEASE_RESERVES_ALERT)).toBeDefined();
        expect(screen.getByText(TERM_ADJUSTMENTS_LINK_TEXT)).toBeDefined();
    });

    it('renders "The balance is ready to be closed" state and calls the mutation on btn click', () => {
        const props = {
            ...defaultProps,
            paymentEntity: statementPeriodResponse.abacusStatementPeriod
                .paymentEntities[1] as BalanceProps['paymentEntity'],
            statementPeriod:
                statementPeriodResponse.abacusStatementPeriod as BalanceProps['statementPeriod'],
        };
        //delete item with pendingAdjustments > 0
        delete props.statementPeriod.paymentEntities[0];

        props.statementPeriod.actionStates = [releaseResrvesCompleted];

        render(props);

        expect(screen.getByText('Balance')).toBeDefined();
        expect(screen.getByText('Close')).toBeDefined();
        expect(screen.getByTestId('StepIndicator')).toBeDefined();

        expect(screen.getByTestId('CheckGlyphIcon')).toBeDefined();

        expect(
            screen.queryByText(TERM_CLOSE_BALANCE_ERR_ALERT_TITLE)
        ).not.toBeInTheDocument();
        expect(
            screen.queryByText(TERM_PENDING_ADJUSTMENTS_ALERT)
        ).not.toBeInTheDocument();
        expect(
            screen.queryByText(TERM_RELEASE_RESERVES_ALERT)
        ).not.toBeInTheDocument();
        expect(
            screen.queryByText(TERM_ADJUSTMENTS_LINK_TEXT)
        ).not.toBeInTheDocument();

        expect(screen.getByText(TERM_BODY_MESSAGE_INIT)).toBeDefined();

        const closeBalanceButton = screen.getByTestId('closeBalanceButton');
        expect(closeBalanceButton).not.toHaveAttribute('disabled');

        fireEvent.click(closeBalanceButton);
        expect(createCloseBalanceEvent).toHaveBeenCalledWith({
            variables: {
                statementPeriodId: '1',
                statementPeriodPaymentEntityId: '2',
            },
        });
    });

    it('renders init state with disabled button if statement period is closed', () => {
        const props = {
            ...defaultProps,
            paymentEntity: statementPeriodResponse.abacusStatementPeriod
                .paymentEntities[1] as BalanceProps['paymentEntity'],
            statementPeriod: {
                ...statementPeriodResponse.abacusStatementPeriod,
                actionStates: [
                    {
                        abacusStateId: '5',
                        actionName: 'statement_period_close',
                        actionStatus: 'complete',
                        message: null,
                    },
                ],
            } as BalanceProps['statementPeriod'],
        };
        render(props);
        expect(screen.getByText('Balance')).toBeDefined();
        expect(screen.getByTestId('StepIndicator')).toBeDefined();
        expect(screen.getByTestId('CheckGlyphIcon')).toBeDefined();
        expect(screen.getByText('Close')).toBeDisabled();
    });

    it('renders "Close balance is RUNNING" state', () => {
        const props = {
            ...defaultProps,
            paymentEntity: statementPeriodResponse.abacusStatementPeriod
                .paymentEntities[2] as BalanceProps['paymentEntity'],
            statementPeriod:
                statementPeriodResponse.abacusStatementPeriod as BalanceProps['statementPeriod'],
        };
        //delete item with pendingAdjustments > 0
        delete props.statementPeriod.paymentEntities[0];

        props.statementPeriod.actionStates = [releaseResrvesCompleted];

        render(props);

        expect(screen.getByText('Balance')).toBeDefined();
        expect(screen.getByText('Close')).toBeDefined();
        expect(screen.getByTestId('StepIndicator')).toBeDefined();

        expect(screen.getByTestId('CheckGlyphIcon')).toBeDefined();
        expect(screen.getByTestId('closeBalanceButton')).toHaveAttribute(
            'disabled'
        );

        expect(
            screen.queryByText(TERM_CLOSE_BALANCE_ERR_ALERT_TITLE)
        ).not.toBeInTheDocument();
        expect(
            screen.queryByText(TERM_PENDING_ADJUSTMENTS_ALERT)
        ).not.toBeInTheDocument();
        expect(
            screen.queryByText(TERM_RELEASE_RESERVES_ALERT)
        ).not.toBeInTheDocument();
        expect(
            screen.queryByText(TERM_ADJUSTMENTS_LINK_TEXT)
        ).not.toBeInTheDocument();

        expect(screen.getByText(TERM_BODY_MESSAGE_RUNNING)).toBeDefined();
    });

    it('renders "Close balance is COMPLETE" state', () => {
        const props = {
            ...defaultProps,
            paymentEntity: {
                ...(statementPeriodResponse.abacusStatementPeriod
                    .paymentEntities[2] as BalanceProps['paymentEntity']),
                actionStates: [
                    {
                        abacusStateId: '304637',
                        actionName: 'close_balance',
                        actionStatus: 'complete',
                    },
                ],
            },
            statementPeriod:
                statementPeriodResponse.abacusStatementPeriod as BalanceProps['statementPeriod'],
        };
        //delete item with pendingAdjustments > 0
        delete props.statementPeriod.paymentEntities[0];

        props.statementPeriod.actionStates = [releaseResrvesCompleted];

        render(props);

        expect(screen.getByText('Balance')).toBeDefined();
        expect(screen.getByText('Close')).toBeDefined();
        expect(screen.getByTestId('StepIndicator')).toBeDefined();

        expect(screen.getByTestId('CheckGlyphIcon')).toBeDefined();
        expect(screen.getByTestId('closeBalanceButton')).toHaveAttribute(
            'disabled'
        );

        expect(
            screen.queryByText(TERM_CLOSE_BALANCE_ERR_ALERT_TITLE)
        ).not.toBeInTheDocument();
        expect(
            screen.queryByText(TERM_PENDING_ADJUSTMENTS_ALERT)
        ).not.toBeInTheDocument();
        expect(
            screen.queryByText(TERM_RELEASE_RESERVES_ALERT)
        ).not.toBeInTheDocument();
        expect(
            screen.queryByText(TERM_ADJUSTMENTS_LINK_TEXT)
        ).not.toBeInTheDocument();

        expect(screen.getByText(TERM_BODY_MESSAGE_COMPLETE)).toBeDefined();
    });
});
