import { BrowserContext, test as baseTest } from '@playwright/test'

import { getTestHeaders } from 'fixtures/handle-backend'
import { addCoverageReport } from 'monocart-reporter'
import { TEST_CONFIG } from 'playwright.config'
import { registerContextForStability } from 'support/page-stability'

import { setFixedDate } from './set-fixed-date'

// Re-exporting the default expect as well so that on the tests we can have
// a single import for expect and test, but the test will be the extended test below.
export { expect } from '@playwright/test'

// See https://playwright.dev/docs/test-fixtures for more information about fixtures.
// Declare the types for the fixtures.
type TestFixtures = {
  // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
  setFixedDate: void
  // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
  setAutoCoverage: void

  context: BrowserContext
}

// Extend base test by providing `setFixedDate`.
// This new `test` can be used in multiple test files, and each of them will get the fixtures.
export const test = baseTest.extend<TestFixtures>({
  setFixedDate: [
    async ({ page }, use): Promise<void> => {
      // Set up the fixture.
      await setFixedDate(page)
      // Use the fixture value in the test.
      await use()
    },
    {
      // Automatic fixtures are set up for each test/worker, even when the test does not list them directly.
      auto: true,
    },
  ],
  // automatically create test coverage reports
  setAutoCoverage: [
    async ({ page }, use) => {
      // coverage API is chromium only, make sure to setup the project correctly
      await Promise.all([
        page.coverage.startJSCoverage({
          resetOnNavigation: false,
        }),
        page.coverage.startCSSCoverage({
          resetOnNavigation: false,
        }),
      ])

      await use()

      const [jsCoverage, cssCoverage] = await Promise.all([
        page.coverage.stopJSCoverage(),
        page.coverage.stopCSSCoverage(),
      ])
      const coverageList = [...jsCoverage, ...cssCoverage]
      await addCoverageReport(coverageList, test.info())
    },
    {
      scope: 'test',
      auto: true,
    },
  ],

  /**
   * This modifies the context so that all backend requests add testinfo as custom headers
   */
  context: async ({ browser }, use, testInfo) => {
    const context = await browser.newContext()

    await context.addInitScript(() => {
      const disableAnimations = () => {
        const style = document.createElement('style')
        style.dataset.testid = 'disable-animations'
        style.textContent = `
          *,
          *::before,
          *::after {
            animation-delay: 0s !important;
            animation-duration: 0s !important;
            transition-delay: 0s !important;
            transition-duration: 0s !important;
            scroll-behavior: auto !important;
          }

          html {
            scroll-behavior: auto !important;
          }
        `

        document.head?.append(style)
      }

      if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', disableAnimations, { once: true })
      } else {
        disableAnimations()
      }
    })

    registerContextForStability(context, new URL(TEST_CONFIG.apiURL))

    await context.route('**/*', async (route) => {
      const request = route.request()
      let handled = false

      try {
        const url = new URL(request.url())
        if (url.port == TEST_CONFIG.apiPort) {
          const headers = {
            ...request.headers(),
            ...getTestHeaders(testInfo),
          }
          handled = true //NOSONAR
          await route.continue({ headers })
          return
        }
      } catch {
        // ignore malformed URLs and just continue with default handling
      }

      if (!handled) {
        await route.continue()
      }
    })
    await use(context)
    await context.close()
  },
})
