import { expect, test } from '@playwright/test'
import { startFixtureCollector, type FixtureCollector } from './fixture-collector'
import { ADAPTER_STATUSES, ALL_ITEMS, ALL_PANELS } from './fixtures/collector-fixtures'

const SIDEBAR_ENTRIES = [
  'Overview',
  'Inbox',
  'Decisions',
  'Map',
  'Projects',
  'Plans',
  'Factory',
  'Agents',
  'CI & Build',
  'Bots',
  'Limits & Spend',
  'Gates',
  'Settings',
]

test.describe.configure({ mode: 'serial' })

let collector: FixtureCollector

test.beforeAll(async () => {
  collector = await startFixtureCollector({ panels: ALL_PANELS, adapters: ADAPTER_STATUSES, items: ALL_ITEMS })
})

test.afterAll(async () => {
  await collector.close()
})

test('renders the dashboard shell with the exact sidebar structure', async ({ page }) => {
  await page.goto('/')
  const sidebar = page.getByRole('navigation', { name: 'Sidebar' })
  await expect(sidebar).toBeVisible()

  for (const label of SIDEBAR_ENTRIES) {
    await expect(sidebar.getByRole('link', { name: new RegExp(`^${label}`) })).toBeVisible()
  }

  await expect(sidebar.getByRole('link', { name: /^Operations$/ })).toHaveCount(0)
})

test('defaults to dark theme with no console errors', async ({ page }) => {
  const errors: string[] = []
  page.on('console', (msg) => {
    if (msg.type() === 'error') errors.push(msg.text())
  })
  page.on('pageerror', (err) => errors.push(err.message))

  await page.goto('/')
  await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark')
  expect(errors).toEqual([])
})

test('theme preference persists across a fresh shell load', {
  tag: ['@UJ-003', '@H1', '@persistence', '@browser-sensitive'],
}, async ({ page }) => {
  const runtimeFailures: string[] = []
  page.on('console', (message) => {
    if (message.type() === 'error' || message.type() === 'warning') runtimeFailures.push(message.text())
  })
  page.on('pageerror', (error) => runtimeFailures.push(error.message))

  const collectorRequests: string[] = []
  page.on('request', (request) => {
    if (request.url().includes('/api/collector/')) collectorRequests.push(request.url())
  })
  await page.goto('/')
  await expect(page.locator('[role="radiogroup"][aria-label="Theme"]')).toHaveAttribute(
    'data-hydrated',
    'true',
  )
  // Page-load collector traffic arrives independently of the theme island; drain it first so
  // the assertion below measures only requests the toggle itself caused.
  await expect.poll(async () => {
    const seen = collectorRequests.length
    await page.waitForTimeout(300)
    return collectorRequests.length === seen
  }, { timeout: 10_000 }).toBe(true)
  collectorRequests.length = 0
  await page.getByRole('radio', { name: /Light/ }).click()
  await expect(page.locator('html')).toHaveAttribute('data-theme', 'light')
  await expect.poll(() => page.evaluate(() => localStorage.getItem('overdeck-theme'))).toBe('light')
  expect(collectorRequests).toEqual([])

  await page.reload()
  await expect(page.locator('html')).toHaveAttribute('data-theme', 'light')

  const bg = await page.locator('html').evaluate(
    (el) => getComputedStyle(el).getPropertyValue('color-scheme'),
  )
  expect(bg.trim()).toBe('light')
  expect(runtimeFailures).toEqual([])
})

test('invalid stored theme falls back to dark without overwriting storage', {
  tag: ['@UJ-003', '@A1', '@invalid-preference', '@browser-sensitive'],
}, async ({ page }) => {
  const runtimeFailures: string[] = []
  page.on('console', (message) => {
    if (message.type() === 'error' || message.type() === 'warning') runtimeFailures.push(message.text())
  })
  page.on('pageerror', (error) => runtimeFailures.push(error.message))

  await page.addInitScript(() => localStorage.setItem('overdeck-theme', 'invalid'))
  await page.goto('/')
  await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark')
  await expect.poll(() => page.evaluate(() => localStorage.getItem('overdeck-theme'))).toBe('invalid')

  await page.reload()
  await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark')
  await expect.poll(() => page.evaluate(() => localStorage.getItem('overdeck-theme'))).toBe('invalid')
  expect(runtimeFailures).toEqual([])
})
