import React from 'react';
import {
    ApolloCache,
    ApolloError,
    DefaultContext,
    FetchResult,
    MutationFunctionOptions,
} from '@apollo/client';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import { Identity } from '@theorchard/suite-frontend';
import { createIdentity, renderInAppContext } from '@theorchard/suite-testing';
import { Route } from 'react-router-dom';
import {
    StatementPeriodAdjustmentFile,
    StatementPeriodAdjustmentFileApproved,
    StatementPeriodAdjustmentFileApplied,
    StatementPeriodAdjustmentFileAppliedError,
    StatementPeriodAdjustmentFileRunning,
} from 'src/__fixtures__/graphql/statement-period-adjustment-file';
import * as abacusEventMutations from 'src/apollo/mutations/abacus-event';
import * as abacusStateMutation from 'src/apollo/mutations/abacus-state';
import * as abacusSoftDeleteStatementPeriodAdjustmentFileMutation from 'src/apollo/mutations/statement-period-adjustment-file';
import * as adjustmentQuery from 'src/apollo/queries/adjustment';
import * as abacusDagRunTimesQuery from 'src/apollo/queries/dag-run-times';
import { ADJUSTMENT_ERROR_MESSAGE } from 'src/apollo/type-constants/adjustment';
import { AdjustmentsBatch } from 'src/components/adjustments/adjustments-batch';
import { USER_FEATURES } from 'src/constants';
import { getAdjustmentsBatchPage } from 'src/urls/frontend-royalties';
import type {
    CreateAbacusEventMutation,
    CreateAbacusEventMutationVariables,
} from 'src/apollo/mutations/__generated__/abacus-event';
import type {
    UpdateAbacusStateMutation,
    UpdateAbacusStateMutationVariables,
} from 'src/apollo/mutations/__generated__/abacus-state';
import type {
    SoftDeleteStatementPeriodAdjustmentFileMutation,
    SoftDeleteStatementPeriodAdjustmentFileMutationVariables,
} from 'src/apollo/mutations/statement-period-adjustment-file/__generated__/soft-delete-statement-period-adjustment-file';
import type { GetStatementPeriodAdjustmentFileAndStatusQuery } from 'src/apollo/queries/adjustment/__generated__/get-statement-period-adjustment-file-and-status';
import { AbacusDag } from 'src/apollo/definitions/globalTypes';

let mockLocationState: { autoGenerated?: boolean } | undefined;

jest.mock('react-router-dom', () => {
    const actual = jest.requireActual('react-router-dom');
    return {
        ...actual,
        useLocation: () => {
            const location = actual.useLocation();
            return mockLocationState
                ? { ...location, state: mockLocationState }
                : location;
        },
    };
});

describe('<AdjustmentsBatch>', () => {
    let getAdjustmentFileRequestSpy: jest.SpyInstance<
        {
            data: GetStatementPeriodAdjustmentFileAndStatusQuery | undefined;
            error: ApolloError | undefined;
            loading: boolean;
        },
        [statementPeriodAdjustmentFileId: string]
    >;

    let updateAbacusStateRequestSpy: jest.SpyInstance<
        {
            updateAbacusState: (
                options?:
                    | MutationFunctionOptions<
                          UpdateAbacusStateMutation,
                          UpdateAbacusStateMutationVariables,
                          DefaultContext,
                          ApolloCache<any>
                      >
                    | undefined
            ) => Promise<
                FetchResult<
                    UpdateAbacusStateMutation,
                    Record<string, any>,
                    Record<string, any>
                >
            >;
            loading: boolean;
        },
        [queries?: any]
    >;
    let createAbacusEventSpy: jest.SpyInstance<
        (
            options?:
                | MutationFunctionOptions<
                      CreateAbacusEventMutation,
                      CreateAbacusEventMutationVariables,
                      DefaultContext,
                      ApolloCache<any>
                  >
                | undefined
        ) => Promise<FetchResult<CreateAbacusEventMutation>>
    >;

    beforeEach(() => {
        getAdjustmentFileRequestSpy = jest
            .spyOn(
                adjustmentQuery,
                'useStatementPeriodAdjustmentFilesAndStatus'
            )
            .mockReturnValue({
                data: {
                    abacusStatementPeriodAdjustmentFilesList: {
                        items: StatementPeriodAdjustmentFile
                            .abacusStatementPeriodAdjustmentFilesList.items,
                        totalCount: 1,
                    },
                } as GetStatementPeriodAdjustmentFileAndStatusQuery,
                error: undefined,
                loading: false,
                startPolling: jest.fn(),
                stopPolling: jest.fn(),
            });
    });

    afterEach(() => {
        jest.restoreAllMocks();
        mockLocationState = undefined;
    });

    const batchId =
        StatementPeriodAdjustmentFile.abacusStatementPeriodAdjustmentFilesList
            .items[0].statementPeriodAdjustmentFileId;

    const mockIdentityFFOn = {
        features: {
            [USER_FEATURES.ABACUS_MANUAL_ADJUSTMENTS_APPROVED_USERS]: true,
        },
    };
    const mockIdentityFFOff = {
        features: {
            [USER_FEATURES.ABACUS_MANUAL_ADJUSTMENTS_APPROVED_USERS]: false,
        },
    };

    const dagQuery = jest.spyOn(abacusDagRunTimesQuery, 'useDagRunTimesQuery');

    const renderComponent = (mockIdentity?: Partial<Identity>) =>
        renderInAppContext(
            <Route path="/adjustments/:batchId">
                <AdjustmentsBatch />
            </Route>,
            {
                pathname: getAdjustmentsBatchPage(batchId),
                identity: createIdentity(mockIdentity),
            }
        );
    describe('on load', () => {
        it('requests adjustment file on render', () => {
            renderComponent(mockIdentityFFOn);
            expect(getAdjustmentFileRequestSpy).toHaveBeenCalled();
        });

        it('calls dag run times query on render', () => {
            expect(dagQuery).toHaveBeenCalledWith(
                AbacusDag.APPLY_PENDING_ADJUSTMENTS
            );
        });

        it('renders error message if graphql returns error', async () => {
            const graphQLError = new ApolloError({
                graphQLErrors: undefined,
                networkError: null,
                errorMessage: 'GraphQL error',
            });
            jest.spyOn(
                adjustmentQuery,
                'useStatementPeriodAdjustmentFilesAndStatus'
            ).mockReturnValue({
                data: {
                    abacusStatementPeriodAdjustmentFilesList: {
                        items: [],
                        totalCount: 0,
                    },
                },
                error: graphQLError,
                loading: false,
                startPolling: jest.fn(),
                stopPolling: jest.fn(),
            });
            renderComponent(mockIdentityFFOn);
            expect(screen.getByText(ADJUSTMENT_ERROR_MESSAGE)).toBeDefined();
        });

        it('renders error message if graphql results is empty', async () => {
            jest.spyOn(
                adjustmentQuery,
                'useStatementPeriodAdjustmentFilesAndStatus'
            ).mockReturnValue({
                data: {
                    abacusStatementPeriodAdjustmentFilesList: {
                        items: [],
                        totalCount: 0,
                    },
                },
                error: undefined,
                loading: false,
                startPolling: jest.fn(),
                stopPolling: jest.fn(),
            });
            renderComponent(mockIdentityFFOn);
            expect(screen.getByText(ADJUSTMENT_ERROR_MESSAGE)).toBeDefined();
        });
    });

    describe('when batch is loaded', () => {
        it('renders 3 header buttons to delete, approve, or apply adjustments', () => {
            renderComponent(mockIdentityFFOn);
            const deleteHeaderButton = screen.getByTestId('TrashGlyphIcon');
            expect(deleteHeaderButton).toBeDefined();
            const approveHeaderButton = screen.getByRole('button', {
                name: 'Approve',
            });
            expect(approveHeaderButton).toBeDefined();
            const applyHeaderButton = screen.getByRole('button', {
                name: 'Apply',
            });
            expect(applyHeaderButton).toBeDefined();
        });

        it('renders details about batch', () => {
            renderComponent(mockIdentityFFOn);
            expect(screen.getByTestId('totalAdjustments').textContent).toEqual(
                '10'
            );
            expect(screen.getByTestId('totalAmount').textContent).toEqual(
                '1,000.01'
            );
            expect(screen.getAllByText('Batch 268')).toBeDefined();
            expect(screen.getByTestId('Status').textContent).toEqual(
                'Not Approved'
            );
            expect(screen.getByText('test_file_name.xlsx')).toBeDefined();
            expect(screen.getByTestId('uploadedAt').textContent).toContain(
                '2023-11-23'
            );
            expect(screen.getByTestId('uploadedBy').textContent).toContain(
                'Joe User'
            );
            expect(screen.queryByTestId('approvedAt')).toBeNull();
            expect(screen.queryByTestId('approvedBy')).toBeNull();
            expect(screen.queryByTestId('appliedAt')).toBeNull();
            expect(screen.queryByTestId('appliedBy')).toBeNull();
        });

        it('renders an enabled approve button when the user has the feature', () => {
            renderComponent(mockIdentityFFOn);
            const approveButton = screen.getByRole('button', {
                name: 'Approve',
            });
            expect(approveButton).toBeEnabled();
        });

        it('renders an enabled approve button when the user does not have the feature', () => {
            renderComponent(mockIdentityFFOff);
            const approveButton = screen.getByRole('button', {
                name: 'Approve',
            });
            expect(approveButton).toBeEnabled();
        });
    });

    describe('when batch has an error state', () => {
        it('displays the Error status', () => {
            jest.spyOn(
                adjustmentQuery,
                'useStatementPeriodAdjustmentFilesAndStatus'
            ).mockReturnValue({
                data: {
                    abacusStatementPeriodAdjustmentFilesList: {
                        items: StatementPeriodAdjustmentFileAppliedError
                            .abacusStatementPeriodAdjustmentFilesList.items,
                        totalCount: 1,
                    },
                } as GetStatementPeriodAdjustmentFileAndStatusQuery,
                error: undefined,
                loading: false,
                startPolling: jest.fn(),
                stopPolling: jest.fn(),
            });

            renderComponent(mockIdentityFFOn);

            const errorStatus = screen.getByText('Error');
            expect(errorStatus).toBeInTheDocument();

            const errorSymbol = screen.getByTestId('DotGlyphIcon');
            expect(errorSymbol.parentElement).toHaveClass('variant-error');
        });
    });

    describe('when batch loaded is approved', () => {
        beforeEach(() => {
            getAdjustmentFileRequestSpy = jest
                .spyOn(
                    adjustmentQuery,
                    'useStatementPeriodAdjustmentFilesAndStatus'
                )
                .mockReturnValue({
                    data: {
                        abacusStatementPeriodAdjustmentFilesList: {
                            items: StatementPeriodAdjustmentFileApproved
                                .abacusStatementPeriodAdjustmentFilesList.items,
                            totalCount: 1,
                        },
                    } as GetStatementPeriodAdjustmentFileAndStatusQuery,
                    error: undefined,
                    loading: false,
                    startPolling: jest.fn(),
                    stopPolling: jest.fn(),
                });
        });

        it('renders a disabled approved button', async () => {
            renderComponent(mockIdentityFFOn);
            const approvedButton = screen.getByRole('button', {
                name: 'Approved',
            });
            expect(approvedButton).toBeDisabled();
        });

        it('renders details about batch', () => {
            renderComponent(mockIdentityFFOn);
            expect(screen.getByTestId('totalAdjustments').textContent).toEqual(
                '10'
            );
            expect(screen.getByTestId('totalAmount').textContent).toEqual(
                '1,000.01'
            );
            expect(screen.getAllByText('Batch 268')).toBeDefined();
            expect(screen.getByTestId('Status').textContent).toEqual(
                'Approved'
            );
            expect(screen.getByText('test_file_name.xlsx')).toBeDefined();
            expect(screen.getByTestId('uploadedAt').textContent).toContain(
                '2023-11-23'
            );
            expect(screen.getByTestId('uploadedBy').textContent).toContain(
                'Joe User'
            );
            expect(screen.getByTestId('approvedAt').textContent).toContain(
                '2023-11-25'
            );
            expect(screen.getByTestId('approvedBy').textContent).toContain(
                'Jill User'
            );
            expect(screen.queryByTestId('appliedAt')).toBeNull();
            expect(screen.queryByTestId('appliedBy')).toBeNull();
        });
    });

    describe('when batch loaded is applied', () => {
        beforeEach(() => {
            getAdjustmentFileRequestSpy = jest
                .spyOn(
                    adjustmentQuery,
                    'useStatementPeriodAdjustmentFilesAndStatus'
                )
                .mockReturnValue({
                    data: {
                        abacusStatementPeriodAdjustmentFilesList: {
                            items: StatementPeriodAdjustmentFileApplied
                                .abacusStatementPeriodAdjustmentFilesList.items,
                            totalCount:
                                StatementPeriodAdjustmentFile
                                    .abacusStatementPeriodAdjustmentFilesList
                                    .totalCount,
                        },
                    } as GetStatementPeriodAdjustmentFileAndStatusQuery,
                    error: undefined,
                    loading: false,
                    startPolling: jest.fn(),
                    stopPolling: jest.fn(),
                });
        });

        it('renders a disabled approved button', async () => {
            renderComponent(mockIdentityFFOn);
            const approvedButton = screen.getByText('Approved');
            expect(approvedButton).toBeDisabled();
        });

        it('renders the adjustments batch list component', async () => {
            renderComponent(mockIdentityFFOn);
            await waitFor(() => {
                const adjustmentsBatchListComponent = screen.getByTestId(
                    'adjustmentsBatchList'
                );
                expect(adjustmentsBatchListComponent).toBeDefined();
            });
        });

        it('renders details about batch', () => {
            renderComponent(mockIdentityFFOn);
            expect(screen.getByTestId('totalAdjustments').textContent).toEqual(
                '10'
            );
            expect(screen.getByTestId('totalAmount').textContent).toEqual(
                '1,000.01'
            );
            expect(screen.getAllByText('Batch 268')).toBeDefined();
            expect(screen.getByTestId('Status').textContent).toEqual('Applied');
            expect(screen.getByText('test_file_name.xlsx')).toBeDefined();
            expect(screen.getByTestId('uploadedAt').textContent).toContain(
                '2023-11-23'
            );
            expect(screen.getByTestId('uploadedBy').textContent).toContain(
                'Joe User'
            );
            expect(screen.getByTestId('approvedAt').textContent).toContain(
                '2023-11-25'
            );
            expect(screen.getByTestId('approvedBy').textContent).toContain(
                'Jill User'
            );
            expect(screen.getByTestId('appliedAt').textContent).toContain(
                '2023-11-27'
            );
            expect(screen.getByTestId('appliedBy').textContent).toContain(
                'Jacob User'
            );
        });
    });

    describe('when Delete button is clicked', () => {
        let softDeleteStatementPeriodAdjustmentFileRequestSpy: jest.SpyInstance<
            (
                options?:
                    | MutationFunctionOptions<
                          SoftDeleteStatementPeriodAdjustmentFileMutation,
                          SoftDeleteStatementPeriodAdjustmentFileMutationVariables,
                          DefaultContext,
                          ApolloCache<any>
                      >
                    | undefined
            ) => Promise<
                FetchResult<SoftDeleteStatementPeriodAdjustmentFileMutation>
            >,
            []
        >;

        const mockSoftDeleteStatementPeriodAdjustmentFile = jest
            .fn()
            .mockResolvedValue({
                data: {
                    abacusSoftDeleteStatementPeriodAdjustmentFile: {
                        deleted: true,
                    },
                },
            });

        beforeEach(() => {
            softDeleteStatementPeriodAdjustmentFileRequestSpy = jest
                .spyOn(
                    abacusSoftDeleteStatementPeriodAdjustmentFileMutation,
                    'useSoftDeleteStatementPeriodAdjustmentFile'
                )
                .mockReturnValue(mockSoftDeleteStatementPeriodAdjustmentFile);
            renderComponent(mockIdentityFFOn);
            const deleteHeaderButton = screen.getByTestId('TrashGlyphIcon');
            fireEvent.click(deleteHeaderButton);
        });

        it('the modal and buttons are rendered properly', () => {
            const softDeleteModal = screen.getByTestId('softDeleteModal');
            expect(softDeleteModal).toBeDefined();
            const yesDeleteButton = screen.getByText('Yes, Delete');
            expect(yesDeleteButton).toBeDefined();
            const noCancelButton = screen.getByText('No, Cancel');
            expect(noCancelButton).toBeDefined();
            const softDeleteModalTitle = screen.getByTestId('modalTitle');
            expect(softDeleteModalTitle).toHaveTextContent(
                'Are you sure you want to delete batch 268?'
            );
            const softDeleteModalDescription =
                screen.getByTestId('modalDescription');
            expect(softDeleteModalDescription).toHaveTextContent(
                'This action cannot be undone.'
            );
        });

        it('soft deletes the statement period adjustment file when the delete confirmation button is clicked', () => {
            const yesDeleteButton = screen.getByText('Yes, Delete');
            fireEvent.click(yesDeleteButton);
            expect(
                softDeleteStatementPeriodAdjustmentFileRequestSpy
            ).toHaveBeenCalled();
        });

        it('generates a toast after confirming a batch deletion', async () => {
            const yesDeleteButton = screen.getByText('Yes, Delete');
            fireEvent.click(yesDeleteButton);
            await waitFor(() => {
                const toast = screen.getByTestId('Toast-0');
                expect(toast).toHaveTextContent(
                    'Batch 268 has been successfully deleted.'
                );
            });
        });
    });

    describe('when Approve button is clicked', () => {
        const mockUpdateAbacusState = jest.fn().mockResolvedValue({
            data: {
                abacusUpdateState: {
                    abacusStateId: '293846',
                    actionName: 'approve_file',
                    actionStatus: 'complete',
                    __typename: 'AbacusState',
                },
            },
        });

        beforeEach(() => {
            updateAbacusStateRequestSpy = jest
                .spyOn(abacusStateMutation, 'useUpdateAbacusState')
                .mockReturnValue({
                    updateAbacusState: mockUpdateAbacusState,
                    loading: false,
                });
            renderComponent(mockIdentityFFOn);
            const approveButton = screen.getByText('Approve');
            fireEvent.click(approveButton);
        });

        it('update state request is called and renders a toast popup when the user approves the batch', async () => {
            expect(updateAbacusStateRequestSpy).toHaveBeenCalled();
            await waitFor(() => {
                const toast = screen.getByTestId('Toast-0');
                expect(toast).toHaveTextContent(
                    'Batch 268 has been successfully approved.'
                );
            });
        });
    });

    describe('when Apply button is clicked', () => {
        const createAbacusEvent = jest.fn().mockReturnValue({});
        beforeEach(() => {
            createAbacusEventSpy = jest
                .spyOn(abacusEventMutations, 'useCreateAbacusEvent')
                .mockReturnValue(createAbacusEvent);
            getAdjustmentFileRequestSpy = jest
                .spyOn(
                    adjustmentQuery,
                    'useStatementPeriodAdjustmentFilesAndStatus'
                )
                .mockReturnValue({
                    data: {
                        abacusStatementPeriodAdjustmentFilesList: {
                            items: StatementPeriodAdjustmentFileApproved
                                .abacusStatementPeriodAdjustmentFilesList.items,
                            totalCount: 1,
                        },
                    } as GetStatementPeriodAdjustmentFileAndStatusQuery,
                    error: undefined,
                    loading: false,
                    startPolling: jest.fn(),
                    stopPolling: jest.fn(),
                });
        });

        it('renders apply modal and buttons when user clicks apply', async () => {
            renderComponent(mockIdentityFFOn);
            const applyButton = screen.getByText('Apply');
            fireEvent.click(applyButton);
            expect(getAdjustmentFileRequestSpy).toHaveBeenCalled();
            const applyModal = screen.getByTestId('applyModal');
            expect(applyModal).toBeDefined();
            const yesApplyButton = screen.getByText('Yes, Apply');
            expect(yesApplyButton).toBeDefined();
            const noCancelButton = screen.getByText('No, Cancel');
            expect(noCancelButton).toBeDefined();
            const applyModalTitle = screen.getByTestId('applyModalTitle');
            expect(applyModalTitle).toHaveTextContent(
                'Are you sure you want to apply batch 268?'
            );
            const applyModalDescription = screen.getByTestId('applyModalAlert');
            expect(applyModalDescription).toHaveTextContent(
                'This action cannot be undone!All adjustments and expenses for the current statement period will be applied to account ledgers, and you will not be able to take any actions against them.'
            );
        });

        it('Starts applying the adjustment when the user clicks Yes, Apply', async () => {
            renderComponent(mockIdentityFFOn);
            const applyButton = screen.getByText('Apply');
            fireEvent.click(applyButton);
            const yesApplyButton = screen.getByText('Yes, Apply');
            fireEvent.click(yesApplyButton);
            expect(screen.getByTestId('InProgressGlyphIcon')).toBeDefined();
            expect(yesApplyButton).toBeDisabled();

            expect(createAbacusEventSpy).toHaveBeenCalled();
            getAdjustmentFileRequestSpy = jest
                .spyOn(
                    adjustmentQuery,
                    'useStatementPeriodAdjustmentFilesAndStatus'
                )
                .mockReturnValue({
                    data: {
                        abacusStatementPeriodAdjustmentFilesList: {
                            items: StatementPeriodAdjustmentFileRunning
                                .abacusStatementPeriodAdjustmentFilesList.items,
                            totalCount: 1,
                        },
                    } as GetStatementPeriodAdjustmentFileAndStatusQuery,
                    error: undefined,
                    loading: false,
                    startPolling: jest.fn(),
                    stopPolling: jest.fn(),
                });
            expect(getAdjustmentFileRequestSpy).toHaveBeenCalled();
        });

        it('Applies the adjustment when the user clicks Yes, Apply', async () => {
            renderComponent(mockIdentityFFOn);
            const applyButton = screen.getByText('Apply');
            const deleteButton = screen.getByTestId('TrashGlyphIcon');
            fireEvent.click(applyButton);
            const yesApplyButton = screen.getByText('Yes, Apply');
            getAdjustmentFileRequestSpy = jest
                .spyOn(
                    adjustmentQuery,
                    'useStatementPeriodAdjustmentFilesAndStatus'
                )
                .mockReturnValue({
                    data: {
                        abacusStatementPeriodAdjustmentFilesList: {
                            items: StatementPeriodAdjustmentFileApplied
                                .abacusStatementPeriodAdjustmentFilesList.items,
                            totalCount: 1,
                        },
                    } as GetStatementPeriodAdjustmentFileAndStatusQuery,
                    error: undefined,
                    loading: false,
                    startPolling: jest.fn(),
                    stopPolling: jest.fn(),
                });
            fireEvent.click(yesApplyButton);
            await waitFor(() => {
                expect(applyButton).toBeDisabled();
            });
            await waitFor(() => {
                expect(deleteButton).not.toBeVisible();
            });
        });

        it('Renders error alert when user clicks Yes, Apply and a query error occurs', () => {
            renderComponent(mockIdentityFFOn);
            const applyButton = screen.getByText('Apply');
            fireEvent.click(applyButton);

            getAdjustmentFileRequestSpy = jest
                .spyOn(
                    adjustmentQuery,
                    'useStatementPeriodAdjustmentFilesAndStatus'
                )
                .mockReturnValue({
                    data: {
                        abacusStatementPeriodAdjustmentFilesList: {
                            items: StatementPeriodAdjustmentFileAppliedError
                                .abacusStatementPeriodAdjustmentFilesList.items,
                            totalCount: 1,
                        },
                    } as GetStatementPeriodAdjustmentFileAndStatusQuery,
                    error: undefined,
                    loading: false,
                    startPolling: jest.fn(),
                    stopPolling: jest.fn(),
                });

            const yesApplyButton = screen.getByText('Yes, Apply');
            fireEvent.click(yesApplyButton);

            expect(applyButton).toBeInTheDocument();

            const deleteButton = screen.queryByTestId('TrashGlyphIcon');
            expect(deleteButton).toBeInTheDocument();

            const applyAlert = screen.queryByText(
                'Please try again or contact the tech team if error persist.'
            );
            expect(applyAlert).toBeInTheDocument();
        });

        it('Renders retry modal with different text when batch has error status', () => {
            getAdjustmentFileRequestSpy = jest
                .spyOn(
                    adjustmentQuery,
                    'useStatementPeriodAdjustmentFilesAndStatus'
                )
                .mockReturnValue({
                    data: {
                        abacusStatementPeriodAdjustmentFilesList: {
                            items: StatementPeriodAdjustmentFileAppliedError
                                .abacusStatementPeriodAdjustmentFilesList.items,
                            totalCount: 1,
                        },
                    } as GetStatementPeriodAdjustmentFileAndStatusQuery,
                    error: undefined,
                    loading: false,
                    startPolling: jest.fn(),
                    stopPolling: jest.fn(),
                });

            renderComponent(mockIdentityFFOn);
            const applyButton = screen.getByText('Apply');
            fireEvent.click(applyButton);

            const applyModal = screen.getByTestId('applyModal');
            expect(applyModal).toBeDefined();

            const applyModalTitle = screen.getByTestId('applyModalTitle');
            expect(applyModalTitle).toHaveTextContent(
                'Retry applying batch 268?'
            );

            const retryAlert = screen.getByTestId('applyModalRetryAlert');
            expect(retryAlert).toHaveTextContent(
                'Retrying previous apply attempt.'
            );
            expect(retryAlert).toHaveTextContent(
                'The system will safely skip any adjustments that were already applied. No duplicate entries will be created.'
            );

            const warningAlert = screen.queryByTestId('applyModalAlert');
            expect(warningAlert).not.toBeInTheDocument();
        });
    });

    describe('auto-generated batch', () => {
        const mockStartPolling = jest.fn();
        const mockStopPolling = jest.fn();
        const mockIdentityAutoGenFFOn = {
            features: {
                [USER_FEATURES.ABACUS_MANUAL_ADJUSTMENTS_APPROVED_USERS]: true,
                [USER_FEATURES.ABACUS_AUTO_GENERATE_ADJUSTMENTS_FLOWTHROUGH]: true,
            },
        };

        beforeEach(() => {
            mockLocationState = { autoGenerated: true };
            jest.spyOn(
                adjustmentQuery,
                'useStatementPeriodAdjustmentFilesAndStatus'
            ).mockReturnValue({
                data: {
                    abacusStatementPeriodAdjustmentFilesList: {
                        items: [
                            {
                                ...StatementPeriodAdjustmentFile
                                    .abacusStatementPeriodAdjustmentFilesList
                                    .items[0],
                                batchType: 'auto',
                                status: 'generating',
                                actionStates: [
                                    {
                                        abacusStateId: '293845',
                                        actionName: 'upload_file',
                                        actionStatus: 'complete',
                                        __typename: 'AbacusState',
                                    },
                                    {
                                        abacusStateId: '293846',
                                        actionName: 'validate_file',
                                        actionStatus: 'init',
                                        __typename: 'AbacusState',
                                    },
                                    {
                                        abacusStateId: '293847',
                                        actionName: 'import_file',
                                        actionStatus: 'init',
                                        __typename: 'AbacusState',
                                    },
                                    {
                                        abacusStateId: '293848',
                                        actionName: 'approve_file',
                                        actionStatus: 'init',
                                        __typename: 'AbacusState',
                                    },
                                    {
                                        abacusStateId: '293849',
                                        actionName: 'apply_file',
                                        actionStatus: 'init',
                                        __typename: 'AbacusState',
                                    },
                                ],
                            },
                        ],
                        totalCount: 1,
                    },
                } as GetStatementPeriodAdjustmentFileAndStatusQuery,
                error: undefined,
                loading: false,
                startPolling: jest.fn(),
                stopPolling: jest.fn(),
            });
        });

        it('renders the Auto-Generated Batch badge', () => {
            renderComponent(mockIdentityAutoGenFFOn);
            expect(
                screen.getByText('Auto-Generated Batch')
            ).toBeInTheDocument();
        });

        it('does not render Auto-Generated Batch badge when feature flag is disabled', () => {
            renderComponent(mockIdentityFFOn);
            expect(
                screen.queryByText('Auto-Generated Batch')
            ).not.toBeInTheDocument();
        });

        it('renders progress icon if batch status is generating and feature flag is enabled', () => {
            renderComponent(mockIdentityAutoGenFFOn);
            expect(
                screen.getByTestId('InProgressGlyphIcon')
            ).toBeInTheDocument();
            expect(
                screen.queryByTestId('DotGlyphIcon')
            ).not.toBeInTheDocument();
            expect(screen.getByText('Generating')).toBeInTheDocument();
        });

        it('renders dot icon if batch status is generating and feature flag is disabled', () => {
            renderComponent(mockIdentityFFOn);
            expect(screen.getByTestId('DotGlyphIcon')).toBeInTheDocument();
            expect(
                screen.queryByTestId('InProgressGlyphIcon')
            ).not.toBeInTheDocument();
            expect(screen.getByText('Generating')).toBeInTheDocument();
        });

        it('shows in-progress spinner when batch data is not yet available', () => {
            renderComponent(mockIdentityAutoGenFFOn);

            expect(
                screen.getByText('Adjustments in Progress')
            ).toBeInTheDocument();
            expect(
                screen.getByText('Check back in a few minutes.')
            ).toBeInTheDocument();
            expect(
                screen.queryByTestId('adjustmentsBatchList')
            ).not.toBeInTheDocument();
        });

        it('starts polling on mount when auto-generated', () => {
            jest.spyOn(
                adjustmentQuery,
                'useStatementPeriodAdjustmentFilesAndStatus'
            ).mockReturnValue({
                data: undefined,
                error: undefined,
                loading: false,
                startPolling: mockStartPolling,
                stopPolling: mockStopPolling,
            });

            renderComponent(mockIdentityAutoGenFFOn);
            expect(mockStartPolling).toHaveBeenCalledWith(2000);
        });

        it('shows normal batch content when generation completes', () => {
            jest.spyOn(
                adjustmentQuery,
                'useStatementPeriodAdjustmentFilesAndStatus'
            ).mockReturnValue({
                data: {
                    abacusStatementPeriodAdjustmentFilesList: {
                        items: [
                            {
                                ...StatementPeriodAdjustmentFile
                                    .abacusStatementPeriodAdjustmentFilesList
                                    .items[0],
                                batchType: 'auto',
                                actionStates: [
                                    {
                                        abacusStateId: '293845',
                                        actionName: 'upload_file',
                                        actionStatus: 'complete',
                                        __typename: 'AbacusState',
                                    },
                                    {
                                        abacusStateId: '293846',
                                        actionName: 'validate_file',
                                        actionStatus: 'complete',
                                        __typename: 'AbacusState',
                                    },
                                    {
                                        abacusStateId: '293847',
                                        actionName: 'import_file',
                                        actionStatus: 'complete',
                                        __typename: 'AbacusState',
                                    },
                                    {
                                        abacusStateId: '293848',
                                        actionName: 'approve_file',
                                        actionStatus: 'complete',
                                        __typename: 'AbacusState',
                                    },
                                    {
                                        abacusStateId: '293849',
                                        actionName: 'apply_file',
                                        actionStatus: 'complete',
                                        __typename: 'AbacusState',
                                    },
                                ],
                            },
                        ],
                        totalCount: 1,
                    },
                } as GetStatementPeriodAdjustmentFileAndStatusQuery,
                error: undefined,
                loading: false,
                startPolling: jest.fn(),
                stopPolling: jest.fn(),
            });
            renderComponent(mockIdentityAutoGenFFOn);
            expect(
                screen.getByTestId('adjustmentsBatchList')
            ).toBeInTheDocument();
            expect(
                screen.queryByText('Adjustments in Progress')
            ).not.toBeInTheDocument();
        });
    });
});
