import { expect, test } from '@/e2e/helper';
import { loadFixtures } from '@crates-io/msw/fixtures';
import { http, HttpResponse } from 'msw';

test.describe('Acceptance | crates page', { tag: '@acceptance' }, () => {
  test('visiting the crates page', async ({ page, msw, percy, a11y }) => {
    await loadFixtures(msw.db);

    await page.goto('/crates');

    await expect(page).toHaveURL('/crates');
    await expect(page).toHaveTitle('Crates - crates.io: Rust Package Registry');

    await percy.snapshot();
    await expect(page).toMatchAriaSnapshot({ name: 'aria.yml' });
    await a11y.audit();
  });

  test('listing crates', async ({ page, msw }) => {
    let per_page = 50;
    for (let i = 1; i <= per_page; i++) {
      let crate = await msw.db.crate.create({});
      await msw.db.version.create({ crate });
    }

    await page.goto('/crates');

    await expect(page.locator('[data-test-crates-nav] [data-test-current-rows]')).toHaveText(`1-${per_page}`);
    await expect(page.locator('[data-test-crates-nav] [data-test-total-rows]')).toHaveText(`${per_page}`);
  });

  test('navigating to next page of crates', async ({ page, msw }) => {
    let per_page = 50;
    for (let i = 1; i <= per_page + 2; i++) {
      let crate = await msw.db.crate.create({});
      await msw.db.version.create({ crate });
    }
    let page_start = per_page + 1;
    let total = per_page + 2;

    await page.goto('/crates');
    await page.click('[data-test-pagination-next]');

    await expect(page).toHaveURL('/crates?page=2');
    await expect(page.locator('[data-test-crates-nav] [data-test-current-rows]')).toHaveText(`${page_start}-${total}`);
    await expect(page.locator('[data-test-crates-nav] [data-test-total-rows]')).toHaveText(`${total}`);
  });

  test('crates default sort is alphabetical', async ({ page, msw }) => {
    await loadFixtures(msw.db);

    await page.goto('/crates');

    await expect(page.locator('[data-test-crates-sort] [data-test-current-order]')).toHaveText('Recent Downloads');
  });

  test('downloads appears for each crate on crate list', async ({ page, msw }) => {
    await loadFixtures(msw.db);

    await page.goto('/crates');
    await expect(page.locator('[data-test-crate-row="0"] [data-test-downloads]')).toHaveText(
      /All-Time\s*Downloads:\s*21,573/,
    );
  });

  test('recent downloads appears for each crate on crate list', async ({ page, msw }) => {
    await loadFixtures(msw.db);

    await page.goto('/crates');
    await expect(page.locator('[data-test-crate-row="0"] [data-test-recent-downloads]')).toHaveText(
      /Recent\s*Downloads:\s*2,000/,
    );
  });

  test('shows error message screen', async ({ page, msw }) => {
    await loadFixtures(msw.db);

    let detail =
      'Page 1 is unavailable for performance reasons. Please take a look at https://crates.io/data-access for alternatives.';
    let error = HttpResponse.json({ errors: [{ detail }] }, { status: 400 });
    msw.worker.use(http.get('/api/v1/crates', () => error));

    await page.goto('/crates');
    await expect(page.locator('[data-test-404-page]')).toBeVisible();
    await expect(page.locator('[data-test-title]')).toHaveText('Failed to load crate list');
    await expect(page.locator('[data-test-details]')).toHaveText(detail);
    await expect(page.locator('[data-test-try-again]')).toBeVisible();
    await expect(page.locator('[data-test-go-back]')).not.toBeVisible();

    await msw.worker.resetHandlers();
    await page.click('[data-test-try-again]');
    await expect(page.locator('[data-test-404-page]')).not.toBeVisible();
    await expect(page.locator('[data-test-crate-row]')).toHaveCount(23);
  });
});
