import React from 'react';
import { screen } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import * as accountingPeriodDetailResponse from 'src/__fixtures__/graphql/accounting-period-detail-response.json';
import * as accountingPeriodMutations from 'src/apollo/mutations/accounting-period';
import * as accountingRunMutations from 'src/apollo/mutations/accounting-run';
import * as accountingPeriodQuery from 'src/apollo/queries/accounting-period';
import {
    ACCOUNTING_PERIOD_STATUSES as PERIOD_STATUSES,
    CONTRACT_TYPES,
} from 'src/constants';
import { AccountingPeriodDetailView } from 'src/components/accounting-period/accounting-period-detail-view';
import {
    ABACUS_ACTION_STATUSES,
    ABACUS_ACTIONS,
} from '@theorchard/accounting-apps-shared';

const closedPeriodDetailResponse = {
    abacusAccountingPeriod: {
        accountingPeriodId: 34,
        accountingPeriodName: 'Sep 2020',
        accountingPeriodStatus: PERIOD_STATUSES.CLOSED,
        actionStates: [
            {
                abacusStateId: '1',
                actionName: ABACUS_ACTIONS.PREP_MECHANICAL_DEDUCTIONS,
                actionStatus: ABACUS_ACTION_STATUSES.COMPLETE,
            },
        ],
        accountingRuns: {
            items: [],
            totalCount: 0,
        },
        salesFile: [],
        closedDate: '2019-01-01',
        statementPeriod: {
            statementPeriodId: 260,
            actionStates: [
                {
                    abacusStateId: 10,
                    actionName: ABACUS_ACTIONS.UPLOAD_EXCHANGE_RATES,
                    actionStatus: ABACUS_ACTION_STATUSES.COMPLETE,
                },
            ],
        },
        contractType: CONTRACT_TYPES.DISTRIBUTION,
    },
};

const deliveredPeriodDetailResponse = {
    abacusAccountingPeriod: {
        accountingPeriodId: 34,
        accountingPeriodName: 'Sep 2020',
        accountingPeriodStatus: PERIOD_STATUSES.CLOSED,
        accountingRuns: {
            items: [
                {
                    accountingRunId: '1347',
                    accountingRunStatus: 'No Action Taken',
                    contractCount: 0,
                    runControllerId: '2722',
                    runControllerName: 'Priority 1',
                    startDate: null,
                },
            ],
            totalCount: 1,
        },
        salesFile: [],
        actionStates: [
            {
                abacusStateId: '1',
                actionName: ABACUS_ACTIONS.DELIVER_SALES_FILES,
                actionStatus: ABACUS_ACTION_STATUSES.COMPLETE,
            },
        ],
        closedDate: null,
        statementPeriod: {
            statementPeriodId: 260,
            actionStates: [
                {
                    abacusStateId: 10,
                    actionName: ABACUS_ACTIONS.UPLOAD_EXCHANGE_RATES,
                    actionStatus: ABACUS_ACTION_STATUSES.COMPLETE,
                },
            ],
        },
        contractType: CONTRACT_TYPES.DISTRIBUTION,
    },
};

const render = () => renderInAppContext(<AccountingPeriodDetailView />);

describe('<AccountingPeriodDetailView>', () => {
    const updateAccountingPeriod = jest.fn().mockResolvedValue({});
    const updateAccountingPeriodState = jest.fn().mockResolvedValue({});
    const updateAccountingRun = jest.fn().mockResolvedValue({});

    beforeEach(() => {
        jest.spyOn(
            accountingPeriodQuery,
            'useAccountingPeriodFullDetail'
        ).mockReturnValue({
            data: accountingPeriodDetailResponse,
            loading: false,
            refetch: jest.fn(),
        });
        jest.spyOn(
            accountingPeriodMutations,
            'useUpdateAccountingPeriod'
        ).mockReturnValue(updateAccountingPeriod);
        jest.spyOn(
            accountingPeriodMutations,
            'useUpdateAccountingPeriodState'
        ).mockReturnValue(updateAccountingPeriodState);
        jest.spyOn(
            accountingRunMutations,
            'useUpdateAccountingRun'
        ).mockReturnValue(updateAccountingRun);
    });

    afterEach(jest.restoreAllMocks);

    describe('Accounting period page title', () => {
        const periodName =
            accountingPeriodDetailResponse.abacusAccountingPeriod
                .accountingPeriodName;

        it('when statement period id is present, concat period id and name', () => {
            jest.spyOn(
                accountingPeriodQuery,
                'useAccountingPeriodFullDetail'
            ).mockReturnValue({
                data: {
                    abacusAccountingPeriod: {
                        ...accountingPeriodDetailResponse.abacusAccountingPeriod,
                    },
                },
                loading: false,
                refetch: jest.fn(),
            });
            render();
            expect(screen.getByText(periodName)).toBeDefined();
        });
    });

    describe('Add Sales Form', () => {
        it('displays when period is open without delivered sales', () => {
            render();
            expect(
                screen.getAllByText('GET ELIGIBLE SALES').length
            ).toBeGreaterThan(0);
            expect(
                screen.getByPlaceholderText('File Display Name')
            ).toBeDefined();
            expect(screen.getByTestId('getEligibleSalesBtn')).toBeDefined();
        });

        it('does not display when period is closed', () => {
            jest.spyOn(
                accountingPeriodQuery,
                'useAccountingPeriodFullDetail'
            ).mockReturnValue({
                data: closedPeriodDetailResponse,
                loading: false,
                refetch: jest.fn(),
            });
            render();
            expect(screen.queryByTestId('getEligibleSalesBtn')).toBeNull();
        });

        it('does not display when an action status is "All Sales Delivered"', () => {
            jest.spyOn(
                accountingPeriodQuery,
                'useAccountingPeriodFullDetail'
            ).mockReturnValue({
                data: deliveredPeriodDetailResponse,
                loading: false,
                refetch: jest.fn(),
            });
            render();
            expect(screen.queryByTestId('getEligibleSalesBtn')).toBeNull();
        });
    });

    describe('Mark Runs as Complete', () => {
        it('renders "Mark as complete" action', () => {
            render();
            expect(screen.getByTestId('markRunsAsCompleteBtn')).toBeTruthy();
        });
    });

    describe('Close Period', () => {
        it('renders disabled if period is closed', () => {
            jest.spyOn(
                accountingPeriodQuery,
                'useAccountingPeriodFullDetail'
            ).mockReturnValue({
                data: closedPeriodDetailResponse,
                loading: false,
                refetch: jest.fn(),
            });
            render();
            expect(screen.getByTestId('closePeriodBtn').disabled).toBeTruthy();
        });

        it(`shows the closedDate if the period is ${PERIOD_STATUSES.CLOSED}`, async () => {
            jest.spyOn(
                accountingPeriodQuery,
                'useAccountingPeriodFullDetail'
            ).mockReturnValue({
                data: closedPeriodDetailResponse,
                loading: false,
                refetch: jest.fn(),
            });
            const { container } = render();
            const closedMessageSpan = await screen.findByTestId('close-date');
            const [closedDate] =
                closedPeriodDetailResponse.abacusAccountingPeriod.closedDate;

            expect(closedMessageSpan).toBeTruthy();
            expect(closedMessageSpan.textContent.includes(closedDate)).toBe(
                true
            );
            expect(container.querySelector('.ClosePeriod.btn')).toBeNull();
        });
    });

    describe('Eligible Sales', () => {
        it('shows the eligible sales table', () => {
            render();
            expect(
                screen.getByTestId('EligibleSalesTableTestId')
            ).toBeDefined();
        });
    });

    describe('All Sales Delivered', () => {
        it('renders the Deliver All Sales Files button', () => {
            render();
            const deliverSalesBtn = screen.getAllByTestId('deliverSalesBtn');
            expect(deliverSalesBtn).toBeDefined();
        });
    });

    describe('Manage Accounting Runs', () => {
        it('shows the accounting runs table', () => {
            render();
            const parent = screen.getByTestId('AccountingRunsTestId');
            const innerDiv = parent.querySelectorAll('.GridTable-row');
            expect(innerDiv.length).toBe(5);
        });
    });

    describe('Upload Exchange Rates', () => {
        it('shows upload exchange rates section', () => {
            render();
            expect(screen.getByText('Exchange Rates')).toBeDefined();
        });
    });

    describe('Closed period actions list', () => {
        it('renders closed period actions list', () => {
            jest.spyOn(
                accountingPeriodQuery,
                'useAccountingPeriodFullDetail'
            ).mockReturnValue({
                data: {
                    abacusAccountingPeriod: {
                        ...deliveredPeriodDetailResponse.abacusAccountingPeriod,
                        accountingPeriodStatus: PERIOD_STATUSES.LOCKED,
                        actionStates: [
                            {
                                abacusStateId: '1',
                                actionName: ABACUS_ACTIONS.CLOSE_PERIOD,
                                actionStatus: ABACUS_ACTION_STATUSES.RUNNING,
                            },
                            {
                                abacusStateId: '2',
                                actionName: ABACUS_ACTIONS.RELEASE_RESERVES,
                                actionStatus: ABACUS_ACTION_STATUSES.RUNNING,
                            },
                        ],
                    },
                },
                loading: false,
                refetch: jest.fn(),
            });
            render();
            expect(screen.queryByText('Taking Reserves')).toBeNull();
        });
    });

    describe('Mech Deductions', () => {
        it('shows "PREP MECH DEDUCTIONS" action link for distribution accounting period', () => {
            render();
            expect(screen.getByText('PREP MECH DEDUCTIONS')).toBeDefined();
        });

        it('hides "PREP MECH DEDUCTIONS" action link for neighbouring_rights accounting period', () => {
            jest.spyOn(
                accountingPeriodQuery,
                'useAccountingPeriodFullDetail'
            ).mockReturnValue({
                data: {
                    abacusAccountingPeriod: {
                        ...deliveredPeriodDetailResponse.abacusAccountingPeriod,
                        contractType: CONTRACT_TYPES.NEIGHBOURING_RIGHTS,
                    },
                },
                loading: false,
                refetch: jest.fn(),
            });
            render();
            expect(screen.queryByText('PREP MECH DEDUCTIONS')).toBeNull();
        });
    });

    describe('NR accounting period', () => {
        it('disables accounting runs actions when approve_sales_files action is not complete', () => {
            jest.spyOn(
                accountingPeriodQuery,
                'useAccountingPeriodFullDetail'
            ).mockReturnValue({
                data: {
                    abacusAccountingPeriod: {
                        ...deliveredPeriodDetailResponse.abacusAccountingPeriod,
                        accountingPeriodStatus: PERIOD_STATUSES.LOCKED,
                        contractType: CONTRACT_TYPES.NEIGHBOURING_RIGHTS,
                        actionStates: [
                            {
                                abacusStateId: '1',
                                actionName: ABACUS_ACTIONS.DELIVER_SALES_FILES,
                                actionStatus: ABACUS_ACTION_STATUSES.COMPLETE,
                            },
                            {
                                abacusStateId: '2',
                                actionName: ABACUS_ACTIONS.APPROVE_SALES_FILES,
                                actionStatus: ABACUS_ACTION_STATUSES.INIT,
                            },
                        ],
                    },
                    loading: false,
                    refetch: jest.fn(),
                },
            });
            render();
            const createButton = screen.getByTestId(`createAccountingRun-1347`);
            expect(createButton.disabled).toBeTruthy();
        });

        it('enables accounting runs actions when approve_sales_files action is complete', () => {
            jest.spyOn(
                accountingPeriodQuery,
                'useAccountingPeriodFullDetail'
            ).mockReturnValue({
                data: {
                    abacusAccountingPeriod: {
                        ...deliveredPeriodDetailResponse.abacusAccountingPeriod,
                        accountingPeriodStatus: PERIOD_STATUSES.LOCKED,
                        contractType: CONTRACT_TYPES.NEIGHBOURING_RIGHTS,
                        actionStates: [
                            {
                                abacusStateId: '1',
                                actionName: ABACUS_ACTIONS.DELIVER_SALES_FILES,
                                actionStatus: ABACUS_ACTION_STATUSES.COMPLETE,
                            },
                            {
                                abacusStateId: '2',
                                actionName: ABACUS_ACTIONS.APPROVE_SALES_FILES,
                                actionStatus: ABACUS_ACTION_STATUSES.COMPLETE,
                            },
                        ],
                    },
                    loading: false,
                    refetch: jest.fn(),
                },
            });
            render();
            const createButton = screen.getByTestId(`createAccountingRun-1347`);
            expect(createButton.disabled).toBeFalsy();
        });
    });
});
