import React from 'react';
import * as apollo from '@apollo/client';
import { screen, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import { renderInAppContext } from '@theorchard/suite-testing';
import { mockIdentity } from 'lib/test-utils/mockIdentity';
import {
    PERMISSIONS_ACTIONS,
    PERMISSIONS_DECISIONS,
    PERMISSIONS_RESOURCE_TYPES,
} from 'src/constants';
import { useContentModToolPPEnabledFF } from 'src/utils/features';
import AllCards from '../allCards';

jest.mock('src/utils/features', () => ({
    useArtistMergeFF: jest.fn(),
    useContentModToolPPEnabledFF: jest.fn(),
}));

const mockContentModToolPPEnabledFF = useContentModToolPPEnabledFF as jest.Mock;

const mockPPDecision = (decision: string, loading = false) => {
    jest.spyOn(apollo, 'useQuery').mockReturnValue({
        data: loading
            ? undefined
            : {
                  identityById: {
                      canPerform: [
                          {
                              action: PERMISSIONS_ACTIONS.VIEW,
                              resourceType:
                                  PERMISSIONS_RESOURCE_TYPES.CONTENT_MODERATION,
                              decision,
                          },
                      ],
                  },
              },
        loading,
        error: undefined,
    } as apollo.QueryResult);
};

describe('<AllCards>', () => {
    const renderComponent = () => renderInAppContext(<AllCards />);

    afterEach(() => {
        jest.resetAllMocks();
    });

    describe('Artist Name Change card', () => {
        beforeEach(() => {
            mockIdentity(['tools_artist_name_change']);
            mockPPDecision(PERMISSIONS_DECISIONS.DENY);
        });

        test('renders the card title', async () => {
            renderComponent();
            await waitFor(() =>
                expect(screen.getByText('Artist Name Change')).toBeVisible()
            );
        });

        test('renders the card subtitle', async () => {
            renderComponent();
            await waitFor(() =>
                expect(
                    screen.getByText(
                        'Rename or Consolidate Distribution Artists'
                    )
                ).toBeVisible()
            );
        });

        test('does not render cards for other roles', () => {
            renderComponent();
            expect(screen.queryByText('Composition Changes')).toBeNull();
            expect(
                screen.queryByText('Catalog Metadata Spreadsheets')
            ).toBeNull();
            expect(screen.queryByText('Content Moderation')).toBeNull();
        });
    });

    describe('Catalog Metadata Spreadsheets card', () => {
        beforeEach(() => {
            mockIdentity(['tools_catalog_metadata_spreadsheets']);
            mockPPDecision(PERMISSIONS_DECISIONS.DENY);
        });

        test('renders the card title', async () => {
            renderComponent();
            await waitFor(() =>
                expect(
                    screen.getByText('Catalog Metadata Spreadsheets')
                ).toBeVisible()
            );
        });

        test('renders the card subtitle', async () => {
            renderComponent();
            await waitFor(() =>
                expect(
                    screen.getByText(
                        'Download catalog metadata into a bulk spreadsheet'
                    )
                ).toBeVisible()
            );
        });
    });

    describe('Composition Changes card', () => {
        beforeEach(() => {
            mockIdentity(['publishing_compositions_changelog']);
            mockPPDecision(PERMISSIONS_DECISIONS.DENY);
        });

        test('renders the card title', async () => {
            renderComponent();
            await waitFor(() =>
                expect(screen.getByText('Composition Changes')).toBeVisible()
            );
        });

        test('renders the card subtitle', async () => {
            renderComponent();
            await waitFor(() =>
                expect(
                    screen.getByText(
                        'Generate Reports for New and Updated Composition Deliveries'
                    )
                ).toBeVisible()
            );
        });

        test('does not render Artist Name Change card', () => {
            renderComponent();
            expect(screen.queryByText('Artist Name Change')).toBeNull();
        });
    });

    describe('Content Moderation card', () => {
        beforeEach(() => {
            mockContentModToolPPEnabledFF.mockReturnValue(true);
        });

        test('is visible when PP grants access', async () => {
            mockIdentity([]);
            mockPPDecision(PERMISSIONS_DECISIONS.ALLOW);

            renderComponent();

            await waitFor(() =>
                expect(screen.getByText('Content Moderation')).toBeVisible()
            );
        });

        test('renders the card subtitle when PP grants access', async () => {
            mockIdentity([]);
            mockPPDecision(PERMISSIONS_DECISIONS.ALLOW);

            renderComponent();

            await waitFor(() =>
                expect(
                    screen.getByText(
                        'Update and manage content moderation watchlists'
                    )
                ).toBeVisible()
            );
        });

        test('is not visible when PP denies access', () => {
            mockIdentity([]);
            mockPPDecision(PERMISSIONS_DECISIONS.DENY);

            renderComponent();

            expect(screen.queryByText('Content Moderation')).toBeNull();
        });
    });

    describe('while PP query is loading', () => {
        test('shows role-based cards for a user with a role', async () => {
            mockIdentity(['tools_artist_name_change']);
            mockPPDecision(PERMISSIONS_DECISIONS.DENY, true);

            renderComponent();

            await waitFor(() =>
                expect(screen.getByText('Artist Name Change')).toBeVisible()
            );
        });

        test('does not show Content Moderation card until PP resolves', () => {
            mockIdentity([]);
            mockPPDecision(PERMISSIONS_DECISIONS.ALLOW, true);

            renderComponent();

            expect(screen.queryByText('Content Moderation')).toBeNull();
        });
    });

    describe('when user has no roles and no PP access', () => {
        beforeEach(() => {
            mockIdentity([]);
            mockPPDecision(PERMISSIONS_DECISIONS.DENY);
        });

        test('renders no cards', () => {
            renderComponent();
            expect(screen.queryByText('Artist Name Change')).toBeNull();
            expect(
                screen.queryByText('Catalog Metadata Spreadsheets')
            ).toBeNull();
            expect(screen.queryByText('Composition Changes')).toBeNull();
            expect(screen.queryByText('Content Moderation')).toBeNull();
        });
    });
});
