import {OrganizationFixture} from 'sentry-fixture/organization';
import {SourceMapArchiveFixture} from 'sentry-fixture/sourceMapArchive';
import {SourceMapArtifactFixture} from 'sentry-fixture/sourceMapArtifact';
import {SourceMapsDebugIDBundlesArtifactsFixture} from 'sentry-fixture/sourceMapsDebugIDBundlesArtifacts';
import {UserFixture} from 'sentry-fixture/user';

import {initializeOrg} from 'sentry-test/initializeOrg';
import {
  render,
  renderGlobalModal,
  screen,
  userEvent,
  waitFor,
} from 'sentry-test/reactTestingLibrary';
import {textWithMarkupMatcher} from 'sentry-test/utils';

import ConfigStore from 'sentry/stores/configStore';
import OrganizationStore from 'sentry/stores/organizationStore';
import {SourceMapsDetails} from 'sentry/views/settings/projectSourceMaps/sourceMapsDetails';

function renderReleaseBundlesMockRequests({
  orgSlug,
  projectSlug,
  empty,
}: {
  orgSlug: string;
  projectSlug: string;
  empty?: boolean;
}) {
  const sourceMaps = MockApiClient.addMockResponse({
    url: `/projects/${orgSlug}/${projectSlug}/files/source-maps/`,
    body: empty
      ? []
      : [
          SourceMapArchiveFixture(),
          SourceMapArchiveFixture({
            id: 2,
            name: 'abc',
            fileCount: 3,
            date: '2023-05-06T13:41:00Z',
          }),
        ],
  });

  const sourceMapsFiles = MockApiClient.addMockResponse({
    url: `/projects/${orgSlug}/${projectSlug}/releases/bea7335dfaebc0ca6e65a057/files/`,
    body: empty ? [] : [SourceMapArtifactFixture()],
  });

  return {sourceMaps, sourceMapsFiles};
}

function renderDebugIdBundlesMockRequests({
  orgSlug,
  projectSlug,
  empty,
}: {
  orgSlug: string;
  projectSlug: string;
  empty?: boolean;
}) {
  const artifactBundlesFiles = MockApiClient.addMockResponse({
    url: `/projects/${orgSlug}/${projectSlug}/artifact-bundles/7227e105-744e-4066-8c69-3e5e344723fc/files/`,
    body: SourceMapsDebugIDBundlesArtifactsFixture(
      empty
        ? {
            fileCount: 0,
            associations: [],
            files: [],
          }
        : {}
    ),
  });

  const artifactBundlesDeletion = MockApiClient.addMockResponse({
    url: `/projects/${orgSlug}/${projectSlug}/files/artifact-bundles/`,
    method: 'DELETE',
  });

  return {artifactBundlesFiles, artifactBundlesDeletion};
}

describe('SourceMapsDetails', function () {
  beforeEach(function () {
    OrganizationStore.init();
  });

  describe('Release Bundles', function () {
    it('renders default state', async function () {
      const {organization, router, project, routerProps} = initializeOrg({
        organization: OrganizationFixture({
          access: ['org:superuser'],
        }),
        router: {
          location: {
            query: {},
          },
          params: {},
        },
      });

      OrganizationStore.onUpdate(organization, {replace: true});

      ConfigStore.set('user', UserFixture({isSuperuser: true}));

      renderReleaseBundlesMockRequests({
        orgSlug: organization.slug,
        projectSlug: project.slug,
      });

      render(
        <SourceMapsDetails
          {...routerProps}
          project={project}
          params={{
            orgId: organization.slug,
            projectId: project.slug,
            bundleId: 'bea7335dfaebc0ca6e65a057',
          }}
        />,
        {router, organization}
      );

      // Title
      expect(screen.getByRole('heading')).toHaveTextContent('Release Bundle');
      // Subtitle
      expect(screen.getByText('bea7335dfaebc0ca6e65a057')).toBeInTheDocument();

      // Search bar
      expect(screen.getByPlaceholderText('Filter by Path')).toBeInTheDocument();

      // Path
      expect(
        await screen.findByText('https://example.com/AcceptOrganizationInvite.js')
      ).toBeInTheDocument();
      // Time
      expect(screen.getByText(/in 3 year/)).toBeInTheDocument();
      // File size
      expect(screen.getByText('8.1 KiB')).toBeInTheDocument();

      // Download button
      expect(screen.getByRole('button', {name: 'Download Artifact'})).toHaveAttribute(
        'href',
        '/projects/org-slug/project-slug/releases/bea7335dfaebc0ca6e65a057/files/5678/?download=1'
      );
    });

    it('renders empty state', async function () {
      const {organization, routerProps, project, router} = initializeOrg({
        router: {
          location: {
            query: {},
          },
          params: {},
        },
      });

      renderReleaseBundlesMockRequests({
        orgSlug: organization.slug,
        projectSlug: project.slug,
        empty: true,
      });

      render(
        <SourceMapsDetails
          {...routerProps}
          project={project}
          params={{
            orgId: organization.slug,
            projectId: project.slug,
            bundleId: 'bea7335dfaebc0ca6e65a057',
          }}
        />,
        {router, organization}
      );

      expect(
        await screen.findByText('There are no artifacts in this upload.')
      ).toBeInTheDocument();
    });
  });

  describe('Artifact Bundles', function () {
    it('renders default state', async function () {
      const {organization, project, routerProps, router} = initializeOrg({
        organization: OrganizationFixture({
          access: ['org:superuser', 'project:releases'],
        }),
        router: {
          location: {
            pathname: `/settings/${initializeOrg().organization.slug}/projects/${
              initializeOrg().project.slug
            }/source-maps/7227e105-744e-4066-8c69-3e5e344723fc/`,
            query: {},
          },
          params: {},
        },
      });

      OrganizationStore.onUpdate(organization, {replace: true});

      ConfigStore.set('user', UserFixture({isSuperuser: true}));

      const mockRequests = renderDebugIdBundlesMockRequests({
        orgSlug: organization.slug,
        projectSlug: project.slug,
      });

      render(
        <SourceMapsDetails
          {...routerProps}
          project={project}
          params={{
            orgId: organization.slug,
            projectId: project.slug,
            bundleId: '7227e105-744e-4066-8c69-3e5e344723fc',
          }}
        />,
        {router, organization}
      );

      // Title
      expect(screen.getByRole('heading')).toHaveTextContent(
        '7227e105-744e-4066-8c69-3e5e344723fc'
      );

      // Details
      // Artifacts
      expect(await screen.findByText('Artifacts')).toBeInTheDocument();
      expect(await screen.findByText('22')).toBeInTheDocument();
      // Release information
      expect(await screen.findByText('Associated Releases')).toBeInTheDocument();
      expect(
        await screen.findByText(textWithMarkupMatcher('v2.0 (Dist: none)'))
      ).toBeInTheDocument();
      expect(
        await screen.findByText(
          textWithMarkupMatcher(
            'frontend@2e318148eac9298ec04a662ae32b4b093b027f0a (Dist: android, iOS)'
          )
        )
      ).toBeInTheDocument();
      // Date Uploaded
      expect(await screen.findByText('Date Uploaded')).toBeInTheDocument();
      expect(await screen.findByText('Mar 8, 2023 9:53 AM UTC')).toBeInTheDocument();

      // Search bar
      expect(screen.getByPlaceholderText('Filter by Path or ID')).toBeInTheDocument();

      // Path
      expect(await screen.findByText('files/_/_/main.js')).toBeInTheDocument();
      // Debug Id
      expect(
        screen.getByText('69ac68eb-cc62-44c0-a5dc-b67f219a3696')
      ).toBeInTheDocument();
      // Type
      expect(screen.getByText('Minified')).toBeInTheDocument();
      // Download Button
      expect(screen.getByRole('button', {name: 'Download Artifact'})).toHaveAttribute(
        'href',
        '/projects/org-slug/project-slug/artifact-bundles/7227e105-744e-4066-8c69-3e5e344723fc/files/ZmlsZXMvXy9fL21haW4uanM=/?download=1'
      );

      renderGlobalModal();

      // Delete item displays a confirmation modal
      await userEvent.click(screen.getByRole('button', {name: 'Delete Source Maps'}));
      expect(
        await screen.findByText('Are you sure you want to delete these source maps?')
      ).toBeInTheDocument();
      // Close modal
      await userEvent.click(screen.getByRole('button', {name: 'Confirm'}));
      await waitFor(() => {
        expect(mockRequests.artifactBundlesDeletion).toHaveBeenLastCalledWith(
          '/projects/org-slug/project-slug/files/artifact-bundles/',
          expect.objectContaining({
            query: expect.objectContaining({
              bundleId: '7227e105-744e-4066-8c69-3e5e344723fc',
            }),
          })
        );
      });
    });

    it('renders empty state', async function () {
      const {organization, project, routerProps, router} = initializeOrg({
        router: {
          location: {
            pathname: `/settings/${initializeOrg().organization.slug}/projects/${
              initializeOrg().project.slug
            }/source-maps/7227e105-744e-4066-8c69-3e5e344723fc/`,
            query: {},
          },
          params: {},
        },
      });

      renderDebugIdBundlesMockRequests({
        orgSlug: organization.slug,
        projectSlug: project.slug,
        empty: true,
      });

      render(
        <SourceMapsDetails
          {...routerProps}
          project={project}
          params={{
            orgId: organization.slug,
            projectId: project.slug,
            bundleId: '7227e105-744e-4066-8c69-3e5e344723fc',
          }}
        />,
        {router, organization}
      );

      expect(
        await screen.findByText('There are no artifacts in this upload.')
      ).toBeInTheDocument();

      expect(
        screen.getByText('No releases associated with this upload.')
      ).toBeInTheDocument();
    });
  });
});
