import React from 'react';
import { screen, fireEvent } from '@testing-library/react';
import { createIdentity, renderInAppContext } from '@theorchard/suite-testing';

import { ContractDetailHeader } from 'src/components/contract-detail/contract-detail-header';
import { getContractDetail as getMoneyhubContractDetail } from 'src/urls/externals/moneyhub';
import { getAccountDetail as getOAAccountDetail } from 'src/urls/externals/oa';
import {
    ACCOUNT_PAYMENT_ENTITY_DOES_NOT_MATCH_CONTRACT_PAYMENT_ENTITY_TOOLTIP_MSG,
    TOOLTIP_DELETE_BUTTON_DISABLED,
} from 'src/apollo/type-constants/contract';
import { ABACUS_PROFILE, USER_FEATURES } from 'src/constants';
import {
    contractDetails,
    contractDetailsKNR,
} from 'src/__fixtures__/graphql/contract-details';

import type { ContractDetailHeaderPropsTypes } from 'src/components/contract-detail/contract-detail-header';
import type { AbacusContract } from 'src/types/abacus-contract';

describe('<ContractDetailHeader />', () => {
    const contractMock = contractDetails.abacusContract as AbacusContract;

    const defaultProps: ContractDetailHeaderPropsTypes = {
        contract: { ...contractMock, isPrimaryContract: true },
        loading: false,
        setIsEditingContractRenewalRules: jest.fn(),
        setIsTerminatingContract: jest.fn(),
    };

    const mockFeatures = {
        [USER_FEATURES.ABACUS_PRIMARY_CONTRACT]: false,
    };

    const render = (
        props: ContractDetailHeaderPropsTypes = defaultProps,
        features: { [x: number]: boolean } = mockFeatures
    ) => {
        return renderInAppContext(<ContractDetailHeader {...props} />, {
            identity: createIdentity({
                features,
                profileType: ABACUS_PROFILE,
                id: 'Jane User',
            }),
        });
    };

    it('renders "View in application" links', () => {
        render(defaultProps);

        const links = new Set(
            screen.getAllByRole('link').map(elem => elem.getAttribute('href'))
        );

        expect(
            links.has(
                getOAAccountDetail(contractMock.account?.accountId as string)
            )
        ).toBe(true);

        expect(
            links.has(
                getMoneyhubContractDetail(
                    contractMock.account?.accountId as string,
                    contractMock.contractId
                )
            )
        ).toBe(true);
    });

    it('renders contract name', () => {
        render(defaultProps);

        const contractName = screen.getByText(contractMock.contractName);
        expect(contractName).toBeDefined();
    });

    it('renders contract id', () => {
        render(defaultProps);

        expect(screen.getByTestId('contractId')).toHaveTextContent(
            contractMock.contractId
        );
    });

    it('renders active contract status', () => {
        render(defaultProps);

        const contractStatus = screen.getByTestId('Status');
        expect(contractStatus).toHaveTextContent('Active');
    });

    it('renders only contract tag if ff is disabled', () => {
        render(defaultProps);
        expect(screen.getByTestId('SuiteBadgeText')).toHaveTextContent(
            'Contract'
        );
    });

    it('renders primary contract tag if ff is enabled', () => {
        const enabledFeatures = {
            [USER_FEATURES.ABACUS_PRIMARY_CONTRACT]: true,
        };
        render(defaultProps, enabledFeatures);
        expect(screen.getByTestId('SuiteBadgeText')).toHaveTextContent(
            'Primary Contract'
        );
    });

    it('renders not yet active contract status', () => {
        const contract = {
            ...contractMock,
            lifecycle: {
                ...contractMock.lifecycle,
                lifecycleStatus: 'INIT',
            },
        } as AbacusContract;

        const props = {
            ...defaultProps,
            contract,
        };

        render(props);

        const contractStatus = screen.getByTestId('Status');
        expect(contractStatus).toHaveTextContent('Not Yet Active');
    });

    it('renders to be terminated contract status', () => {
        const contract = {
            ...contractMock,
            lifecycle: {
                ...contractMock.lifecycle,
                lifecycleStatus: 'TO_BE_TERMINATED',
            },
        } as AbacusContract;

        const props = {
            ...defaultProps,
            contract,
        };

        render(props);

        const contractStatus = screen.getByTestId('Status');
        expect(contractStatus).toHaveTextContent('To Be Terminated');
    });

    it('renders terminated contract status', () => {
        const contract = {
            ...contractMock,
            lifecycle: {
                ...contractMock.lifecycle,
                lifecycleStatus: 'TERMINATED',
            },
        } as AbacusContract;

        const props = {
            ...defaultProps,
            contract,
        };

        render(props);

        const contractStatus = screen.getByTestId('Status');
        expect(contractStatus).toHaveTextContent('Terminated');
    });

    it('renders collection period contract status', () => {
        const contract = {
            ...contractMock,
            lifecycle: {
                ...contractMock.lifecycle,
                lifecycleStatus: 'IN_COLLECTION_PERIOD',
            },
        } as AbacusContract;

        const props = {
            ...defaultProps,
            contract,
        };

        render(props);

        const contractStatus = screen.getByTestId('Status');
        expect(contractStatus).toHaveTextContent('Collection Period');
    });

    it('renders Terminate button', () => {
        render(defaultProps);
        expect(screen.getByTestId('contractTerminateButton')).toBeDefined();
    });

    describe('Reactivate button', () => {
        const renderWithTerminatedStatus = () => {
            const contract = {
                ...contractMock,
                lifecycle: {
                    ...contractMock.lifecycle,
                    lifecycleStatus: 'TERMINATED',
                },
            } as AbacusContract;

            const props = {
                ...defaultProps,
                contract,
            };

            return render(props);
        };

        const renderWithMismatchingPaymentEntities = () => {
            const contract = {
                ...contractMock,
                lifecycle: {
                    ...contractMock.lifecycle,
                    lifecycleStatus: 'TERMINATED',
                },
                referenceSigningEntity: {
                    ...contractMock.referenceSigningEntity,
                    referencePaymentEntity: {
                        referencePaymentEntityId: '123',
                    },
                },
            } as AbacusContract;

            const props = {
                ...defaultProps,
                contract,
            };

            return render(props);
        };

        it('renders Reactivate button', () => {
            renderWithTerminatedStatus();

            const contractReactivateButton = screen.getByTestId(
                'contractReactivateButton'
            );

            expect(contractReactivateButton).toBeDefined();
            expect(contractReactivateButton).not.toBeDisabled();
        });

        it("reactivate button is disabled if contract's signing entity does not belong to account's payment entity", () => {
            renderWithMismatchingPaymentEntities();

            const contractReactivateButton = screen.getByTestId(
                'contractReactivateButton'
            );

            expect(contractReactivateButton).toBeDisabled();
        });

        it('renders a tooltip on hover of disabled reactivate button', async () => {
            renderWithMismatchingPaymentEntities();

            const contractReactivateButton = screen.getByTestId(
                'contractReactivateButton'
            );

            fireEvent.mouseOver(contractReactivateButton);

            const tooltip = await screen.findByText(
                ACCOUNT_PAYMENT_ENTITY_DOES_NOT_MATCH_CONTRACT_PAYMENT_ENTITY_TOOLTIP_MSG
            );

            expect(tooltip).toBeInTheDocument();
        });

        it('does not render a tooltip on hover of enabled reactivate button', async () => {
            renderWithTerminatedStatus();

            const contractReactivateButton = screen.getByTestId(
                'contractReactivateButton'
            );

            fireEvent.mouseOver(contractReactivateButton);

            const tooltip = screen.queryByText(
                ACCOUNT_PAYMENT_ENTITY_DOES_NOT_MATCH_CONTRACT_PAYMENT_ENTITY_TOOLTIP_MSG
            );

            expect(tooltip).not.toBeInTheDocument();
        });

        it('opens a contract reactivate modal on click of Reactivate button', () => {
            renderWithTerminatedStatus();

            const contractReactivateButton = screen.getByTestId(
                'contractReactivateButton'
            );

            fireEvent.click(contractReactivateButton);

            expect(screen.getByTestId('ContractReactivateModal')).toBeDefined();
        });
    });

    describe('History Reports', () => {
        it('opens modal upon click', () => {
            render(defaultProps);

            const historyReportLink = screen.getByTestId(
                'contractHistoryReportsLink'
            );

            fireEvent.click(historyReportLink);

            expect(
                screen.getByText(
                    'History reports will be generated outside of Abacus in Looker.'
                )
            ).toBeDefined();
        });

        it('renders links to Looker reports for Distribution type contracts', () => {
            render(defaultProps);

            const historyReportLink = screen.getByTestId(
                'contractHistoryReportsLink'
            );

            fireEvent.click(historyReportLink);

            const generalReportLink = screen.getByRole('link', {
                name: 'General Report',
            });

            expect(generalReportLink).toHaveAttribute(
                'href',
                'https://theorchard.looker.com/looks/21866?f[royalty_accounting_prod_vw_fact_contract_history.contract_id]=30'
            );

            const termsAndConditionsReportLink = screen.getByRole('link', {
                name: 'Terms & Conditions Report',
            });

            expect(termsAndConditionsReportLink).toHaveAttribute(
                'href',
                'https://theorchard.looker.com/looks/21868?f[royalty_accounting_prod_vw_fact_contract_history.contract_id]=30'
            );
        });

        it('renders links to Looker reports for KNR/neighbouring rights contracts', () => {
            const knrContractMock =
                contractDetailsKNR.abacusContract as any as AbacusContract;

            const props = {
                ...defaultProps,
                contract: knrContractMock,
            };

            render(props);

            const historyReportLink = screen.getByTestId(
                'contractHistoryReportsLink'
            );

            fireEvent.click(historyReportLink);

            const generalReportLink = screen.getByRole('link', {
                name: 'General Report',
            });

            expect(generalReportLink).toHaveAttribute(
                'href',
                'https://theorchard.looker.com/looks/21866?f[royalty_accounting_prod_vw_fact_contract_history.contract_id]=35'
            );

            const termsAndConditionsReportLink = screen.getByRole('link', {
                name: 'Terms & Conditions Report',
            });

            expect(termsAndConditionsReportLink).toHaveAttribute(
                'href',
                'https://theorchard.looker.com/looks/21867?f[royalty_accounting_prod_vw_fact_contract_history.contract_id]=35'
            );
        });
    });

    describe('Delete button', () => {
        const renderWithCanBeDeleted = () => {
            const contract = {
                ...contractMock,
                canBeDeleted: true,
            } as AbacusContract;

            const props = {
                ...defaultProps,
                contract,
            };

            return render(props);
        };

        it('renders the delete button as disabled with a tooltip when the contract can not be deleted', async () => {
            render(defaultProps);

            const contractDeleteButton = screen.getByTestId(
                'contractDeleteButton'
            );

            expect(contractDeleteButton).toBeDisabled();

            fireEvent.mouseOver(contractDeleteButton);

            const tooltip = await screen.findByText(
                TOOLTIP_DELETE_BUTTON_DISABLED
            );

            expect(tooltip).toBeInTheDocument();
        });

        it('renders the delete button as enabled when the contract can be deleted', () => {
            renderWithCanBeDeleted();

            const contractDeleteButton = screen.getByTestId(
                'contractDeleteButton'
            );

            expect(contractDeleteButton).not.toBeDisabled();

            fireEvent.mouseOver(contractDeleteButton);

            expect(
                screen.queryByTestId('contractDeleteButtonTooltip')
            ).toBeNull();
        });

        it('opens the delete modal when clicking the delete button', () => {
            renderWithCanBeDeleted();

            const contractDeleteButton = screen.getByTestId(
                'contractDeleteButton'
            );

            fireEvent.click(contractDeleteButton);

            expect(screen.getByTestId('ContractDeleteModal')).toBeDefined();
        });
    });
});
