import React from 'react';
import * as apolloClient from '@apollo/client';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import * as suiteComponents from '@theorchard/suite-components';
import { renderInAppContext } from '@theorchard/suite-testing';
import * as profitCenterMutations from 'src/apollo/mutations/reference-sap-profit-center';
import {
    ConfirmDeletePopoverIcon,
    ConfirmDeletePopoverIconPropTypes,
} from 'src/components/reference-sap-profit-center-edit/confirm-delete-popover-icon';
import * as sidecarActivityContext from 'src/components/reference-sap-profit-center-edit/sidecar-activity-context';

describe('<ConfirmDeletePopoverIcon />', () => {
    afterEach(jest.restoreAllMocks);

    const defaultProps: ConfirmDeletePopoverIconPropTypes = {
        id: 'sep-1',
        legalName: 'AWAL Digital Limited',
        setError: jest.fn(),
    };

    let addToastMock: jest.Mock;
    let mockEvict: jest.Mock;
    let deleteMappedSigningEntity: jest.Mock;
    let setIsDeletingEntity: jest.Mock;
    let pendingResolve: () => void;

    beforeEach(() => {
        addToastMock = jest.fn();
        mockEvict = jest.fn();
        deleteMappedSigningEntity = jest.fn().mockResolvedValue(undefined);
        setIsDeletingEntity = jest.fn();

        jest.spyOn(
            profitCenterMutations,
            'useDeleteMappedSigningEntity'
        ).mockReturnValue(deleteMappedSigningEntity);
        jest.spyOn(
            sidecarActivityContext,
            'useSidecarActivity'
        ).mockReturnValue({
            isDeletingEntity: false,
            isSavingFormData: false,
            deleteError: null,
            setDeleteError: jest.fn(),
            setIsDeletingEntity,
        });
        jest.spyOn(suiteComponents, 'useToast').mockReturnValue(addToastMock);
        jest.spyOn(apolloClient, 'useApolloClient').mockReturnValue({
            cache: { evict: mockEvict },
        } as unknown as apolloClient.ApolloClient<object>);
    });

    const renderComponent = (props = defaultProps) =>
        renderInAppContext(<ConfirmDeletePopoverIcon {...props} />);

    const openPopover = () =>
        fireEvent.click(screen.getByTestId('TrashGlyphIcon'));

    const confirmationText = 'Are you sure you want to delete this item?';

    it('renders the delete trigger icon', () => {
        renderComponent();
        expect(screen.getByTestId('TrashGlyphIcon')).toBeDefined();
    });

    it('opens the confirmation popover when the icon is clicked', () => {
        renderComponent();
        openPopover();

        expect(screen.getByText(confirmationText)).toBeInTheDocument();
    });

    it('does not open the popover while another entity is already being deleted', () => {
        jest.spyOn(
            sidecarActivityContext,
            'useSidecarActivity'
        ).mockReturnValue({
            isDeletingEntity: true,
            isSavingFormData: false,
            deleteError: null,
            setDeleteError: jest.fn(),
            setIsDeletingEntity,
        });
        renderComponent();
        openPopover();

        expect(screen.queryByText(confirmationText)).not.toBeInTheDocument();
    });

    it('closes the popover when Cancel is clicked', async () => {
        renderComponent();
        openPopover();
        fireEvent.click(screen.getByText('Cancel'));

        await waitFor(() =>
            expect(screen.queryByText(confirmationText)).not.toBeInTheDocument()
        );
    });

    it('clears the error, marks the deletion in progress, and calls the mutation with the row id when Confirm is clicked', async () => {
        renderComponent();
        openPopover();
        fireEvent.click(screen.getByText('Confirm'));

        expect(defaultProps.setError).toHaveBeenCalledWith('');
        expect(setIsDeletingEntity).toHaveBeenCalledWith(true);
        expect(deleteMappedSigningEntity).toHaveBeenCalledWith({
            variables: { signingEntitySapProfitCenterId: 'sep-1' },
        });

        await waitFor(() => expect(addToastMock).toHaveBeenCalled());
    });

    it('shows a deleting label and disables actions while the mutation is in flight', async () => {
        deleteMappedSigningEntity.mockReturnValue(
            new Promise<void>(resolve => {
                pendingResolve = resolve;
            })
        );
        renderComponent();
        openPopover();
        fireEvent.click(screen.getByText('Confirm'));

        expect(screen.getByText('Deleting...')).toBeDisabled();
        expect(screen.getByText('Cancel')).toBeDisabled();

        pendingResolve();
        await waitFor(() => expect(addToastMock).toHaveBeenCalled());
    });

    it('shows a success toast, closes the popover, and evicts cached lists on success', async () => {
        renderComponent();
        openPopover();
        fireEvent.click(screen.getByText('Confirm'));

        await waitFor(() =>
            expect(addToastMock).toHaveBeenCalledWith(
                'The signing entity AWAL Digital Limited has been deleted successfully.'
            )
        );

        await waitFor(() =>
            expect(screen.queryByText(confirmationText)).not.toBeInTheDocument()
        );
        expect(mockEvict).toHaveBeenCalledWith({
            id: 'ROOT_QUERY',
            fieldName: 'abacusReferenceSapProfitCenterList',
        });
        expect(mockEvict).toHaveBeenCalledWith({
            id: 'ROOT_QUERY',
            fieldName: 'abacusSigningEntitiesBySapProfitCenter',
        });
        expect(setIsDeletingEntity).toHaveBeenLastCalledWith(false);
    });

    it('calls onDeleteSuccess when the deletion succeeds', async () => {
        const onDeleteSuccess = jest.fn();
        renderComponent({ ...defaultProps, onDeleteSuccess });
        openPopover();
        fireEvent.click(screen.getByText('Confirm'));

        await waitFor(() => expect(onDeleteSuccess).toHaveBeenCalled());
    });

    it('reports an error via setError and stops the in-progress state when the mutation fails', async () => {
        deleteMappedSigningEntity.mockRejectedValueOnce(new Error('failed'));
        renderComponent();
        openPopover();
        fireEvent.click(screen.getByText('Confirm'));

        await waitFor(() =>
            expect(defaultProps.setError).toHaveBeenCalledWith(
                'Error: Failed to delete mapped signing entity. ' +
                    'The signing entity AWAL Digital Limited is already assigned to active contract, or an unexpected error occurred. Please try again. If the issue persists, please contact support for assistance.'
            )
        );
        expect(addToastMock).not.toHaveBeenCalled();
        expect(mockEvict).not.toHaveBeenCalled();
        expect(setIsDeletingEntity).toHaveBeenLastCalledWith(false);
    });

    it('does not call onDeleteSuccess when the deletion fails', async () => {
        deleteMappedSigningEntity.mockRejectedValueOnce(new Error('failed'));
        const onDeleteSuccess = jest.fn();
        renderComponent({ ...defaultProps, onDeleteSuccess });
        openPopover();
        fireEvent.click(screen.getByText('Confirm'));

        await waitFor(() => expect(defaultProps.setError).toHaveBeenCalled());
        expect(onDeleteSuccess).not.toHaveBeenCalled();
    });
});
