import { chromium } from '@playwright/test'
import assert from 'node:assert/strict'
import { mkdir, writeFile } from 'node:fs/promises'

const baseUrl = process.env.OVERDECK_WEB_URL ?? 'http://127.0.0.1:31337'
const artifactDir = 'apps/web/browser-proof/agent-observability-live/results'
await mkdir(artifactDir, { recursive: true })
const browser = await chromium.launch({ headless: true })
const page = await browser.newPage()
const requests = []
const consoleErrors = []
page.on('request', (request) => {
  const url = new URL(request.url())
  if (url.pathname.startsWith('/api/collector/')) requests.push(url)
})
page.on('console', (message) => { if (message.type() === 'error') consoleErrors.push(message.text()) })

async function computedTheme() {
  return page.evaluate(() => ({
    background: getComputedStyle(document.body).backgroundColor,
    color: getComputedStyle(document.body).color,
  }))
}

try {
  const activityResponsePromise = page.waitForResponse((response) => new URL(response.url()).pathname === '/api/collector/activity' && response.ok())
  await page.goto(`${baseUrl}/logs?range=1h&grouping=off`, { waitUntil: 'domcontentloaded' })
  const activityResponse = await activityResponsePromise
  await page.getByTestId('logs-page').waitFor()
  const activity = await activityResponse.json()
  assert.ok(Array.isArray(activity.events))
  assert.ok(Array.isArray(activity.coverage))
  assert.ok(Array.isArray(activity.series) && activity.series.length === 6)
  assert.ok(activity.series.every((series) => series.status === 'unavailable' || series.points.length > 0))
  assert.equal(await page.getByRole('img', { name: /over time/ }).count() + await page.getByRole('status', { name: '' }).count() >= activity.series.length, true)
  assert.ok(activity.errorCount === undefined || Number.isFinite(activity.errorCount))

  for (const range of ['1h', '1d', '3d', '7d', '30d', 'all']) {
    await page.getByRole('button', { name: range, exact: true }).click()
    assert.equal(new URL(page.url()).searchParams.get('range'), range)
  }

  const categoryButtons = page.getByText('Category', { exact: true }).locator('..').locator(':scope > button')
  assert.ok(await categoryButtons.count() >= 1)
  if (await categoryButtons.count() > 1) await categoryButtons.nth(1).click()
  const severityButtons = page.getByText('Severity', { exact: true }).locator('..').locator(':scope > button')
  assert.ok(await severityButtons.count() > 1)
  await severityButtons.nth(1).click()
  await page.getByLabel('Search projects').fill('a')
  const projectButtons = page.getByText('Project', { exact: true }).locator('..').locator(':scope > button')
  assert.ok(await projectButtons.count() >= 1)
  if (await projectButtons.count() > 1) await projectButtons.nth(1).click()
  await page.getByLabel('Filter').fill('session')
  const groupingButtons = page.getByText('Grouping', { exact: true }).locator('..').locator(':scope > button')
  await groupingButtons.filter({ hasText: 'ON' }).click()
  await page.waitForURL((url) => url.searchParams.get('grouping') === null)
  await groupingButtons.filter({ hasText: 'OFF' }).click()
  await page.waitForURL((url) => url.searchParams.get('grouping') === 'off')
  await page.goto(`${baseUrl}/logs?range=1h&grouping=off`, { waitUntil: 'domcontentloaded' })
  await page.getByTestId('logs-page').waitFor()

  let evidenceActivity = activity
  if (!evidenceActivity.events.some((event) => (event.evidence?.length ?? 0) > 0)) {
    const allActivityPromise = page.waitForResponse((response) => {
      const url = new URL(response.url())
      return url.pathname === '/api/collector/activity' && !url.searchParams.has('from') && response.ok()
    })
    await page.goto(`${baseUrl}/logs?range=all&grouping=off`, { waitUntil: 'domcontentloaded' })
    evidenceActivity = await (await allActivityPromise).json()
    await page.getByTestId('logs-page').waitFor()
  }
  const evidenceEvent = evidenceActivity.events.find((event) => (event.evidence?.length ?? 0) > 0)
  if (evidenceEvent) {
    await page.goto(`${baseUrl}/logs?range=all&grouping=off&event=${encodeURIComponent(`event:${evidenceEvent.id}`)}`, { waitUntil: 'domcontentloaded' })
    await page.getByRole('dialog').waitFor()
    const evidence = page.getByRole('link', { name: 'Open evidence' }).first()
    assert.equal(await evidence.count(), 1)
    const href = await evidence.getAttribute('href')
    assert.match(href ?? '', /^\/logs\/[^?]+\?event=.+/)
    await evidence.click()
    assert.equal(new URL(page.url()).searchParams.has('event'), true)
    const evidenceDialog = page.getByRole('dialog')
    await evidenceDialog.waitFor()
    await evidenceDialog.getByRole('button', { name: 'Close', exact: true }).click()
    assert.equal(new URL(page.url()).searchParams.has('event'), false)
    await page.goto(`${baseUrl}/logs?range=1h&grouping=off`, { waitUntil: 'domcontentloaded' })
    await page.getByTestId('logs-page').waitFor()
  } else {
    assert.equal(await page.getByRole('link', { name: 'Open evidence' }).count(), 0)
    assert.ok(evidenceActivity.coverage.every((source) => source.status !== 'ok' || source.records === 0))
  }

  await page.evaluate(() => { document.documentElement.dataset.theme = 'light' })
  const light = await computedTheme()
  await page.evaluate(() => { document.documentElement.dataset.theme = 'dark' })
  const dark = await computedTheme()
  assert.notDeepEqual(dark, light)
  await page.evaluate(() => { document.documentElement.dataset.theme = 'light' })
  assert.deepEqual(await computedTheme(), light)
  await page.screenshot({ path: `${artifactDir}/logs.png`, fullPage: true })

  const firstCycle = requests.filter((url) => url.pathname === '/api/collector/activity').length
  await page.waitForTimeout(16_000)
  const secondCycle = requests.filter((url) => url.pathname === '/api/collector/activity').length
  assert.equal(secondCycle, firstCycle + 1)

  const clusterResponsePromise = page.waitForResponse((response) => new URL(response.url()).pathname === '/api/collector/cluster')
  await page.goto(`${baseUrl}/cluster`, { waitUntil: 'domcontentloaded' })
  const clusterResponse = await clusterResponsePromise
  const clusterBody = await clusterResponse.text()
  await page.screenshot({ path: `${artifactDir}/cluster-arrival.png`, fullPage: true })
  await writeFile(`${artifactDir}/cluster-arrival.txt`, await page.locator('body').innerText())
  await writeFile(`${artifactDir}/cluster-response.json`, JSON.stringify({ status: clusterResponse.status(), body: clusterBody }, null, 2))
  if (clusterResponse.ok()) {
    await page.getByTestId('cluster-page').waitFor()
    await page.getByTestId('cluster-content').waitFor()
    assert.ok(await page.getByText(/Machines|machine/i).count())
    assert.ok(await page.getByText(/Nodes/i).count())
    assert.ok(await page.getByText(/workload/i).count())
    assert.ok(await page.getByText(/build/i).count())
    assert.ok(await page.getByText(/session/i).count())
  } else {
    assert.notEqual(clusterResponse.status(), 200)
    await page.getByText(/unavailable|failed|error|could not/i).first().waitFor()
  }
  await page.screenshot({ path: `${artifactDir}/cluster.png`, fullPage: true })

  const sessionLink = page.locator('a[href^="/sessions?session="]').first()
  if (await sessionLink.count()) {
    const href = await sessionLink.getAttribute('href')
    const sessionId = new URL(href, baseUrl).searchParams.get('session')
    assert.ok(sessionId)
    await sessionLink.click()
    assert.equal(new URL(page.url()).searchParams.get('session'), sessionId)
  } else {
    if (clusterResponse.ok()) assert.ok(await page.getByText(/0 session|Sessions unavailable|could not be placed/i).count())
    else assert.equal(clusterResponse.status(), 503)
    await page.goto(`${baseUrl}/sessions`, { waitUntil: 'domcontentloaded' })
  }

  const sessionsHeading = page.getByText('Agent sessions', { exact: true })
  await sessionsHeading.waitFor()
  const reconnect = page.getByRole('button', { name: /reopen|attach|resume/i }).first()
  if (await reconnect.count()) {
    await reconnect.click()
    await page.getByRole('dialog').waitFor()
    assert.ok(await page.getByText(/Reopen from a terminal|Reopen on its host|Resume from a terminal|session /i).count())
    assert.equal(requests.some((url) => url.pathname.includes('/actions/')), false)
  } else {
    assert.ok(await page.getByText(/Reconnectable/).count())
    const reconnectable = await page.getByText(/^Reconnectable\s*0$/).textContent()
    assert.match(reconnectable ?? '', /0/)
    assert.ok(await page.getByText(/cannot|unavailable|not loopback|no sessions/i).count())
  }

  const expectedClusterUnavailable = clusterResponse.status() === 503
  const unexpectedConsoleErrors = consoleErrors.filter((message) =>
    !(expectedClusterUnavailable && message === 'Failed to load resource: the server responded with a status of 503 (Service Unavailable)')
  )
  assert.equal(unexpectedConsoleErrors.length, 0, unexpectedConsoleErrors.join('\n'))
  await page.screenshot({ path: `${artifactDir}/sessions.png`, fullPage: true })
  await writeFile(`${artifactDir}/receipt.json`, JSON.stringify({
    activity: {
      events: activity.events.length,
      coverage: activity.coverage.length,
      series: activity.series.map(({ id, status, points }) => ({ id, status, points: points.length })),
      categoryCounts: activity.categoryCounts,
      projectCounts: activity.projectCounts ?? [],
    },
    requests: requests.map((url) => `${url.pathname}${url.search}`),
    consoleErrors,
    finalUrl: page.url(),
    actionRequests: requests.filter((url) => url.pathname.includes('/actions/')).length,
  }, null, 2))
} finally {
  await browser.close()
}
