import { expect, test, type Page } from '@playwright/test'

const EXPLORER_URL = process.env.EXPLORER_URL || 'https://explorer.d-bis.org'
const ADDRESS_TEST = '0x99b3511a2d315a497c8112c1fdd8d508d4b1e506'

async function expectHeading(page: Page, name: RegExp) {
  await expect(page.getByRole('heading', { name })).toBeVisible({ timeout: 10000 })
}

function collectUnexpectedConsoleErrors(page: Page, allowlist: RegExp[] = []) {
  const unexpectedErrors: string[] = []

  page.on('console', (message) => {
    if (message.type() !== 'error') {
      return
    }

    const text = message.text()
    if (allowlist.some((pattern) => pattern.test(text))) {
      return
    }

    unexpectedErrors.push(text)
  })

  return async () => {
    expect(unexpectedErrors).toEqual([])
  }
}

test.describe('Explorer Frontend - Route Coverage', () => {
  for (const route of [
    { path: '/', heading: /DBIS Explorer/i },
    { path: '/blocks', heading: /^Blocks$/i },
    { path: '/transactions', heading: /^Transactions$/i },
    { path: '/addresses', heading: /^Addresses$/i },
    { path: '/watchlist', heading: /^Watchlist$/i },
    { path: '/pools', heading: /^Pools$/i },
    { path: '/liquidity', heading: /Public liquidity, route discovery, and execution access points/i },
    { path: '/wallet', heading: /Wallet & MetaMask/i },
    { path: '/tokens', heading: /^Tokens$/i },
    { path: '/search', heading: /^Search$/i },
  ]) {
    test(`${route.path} loads`, async ({ page }) => {
      await page.goto(`${EXPLORER_URL}${route.path}`, { waitUntil: 'domcontentloaded', timeout: 20000 })
      await expect(page).toHaveURL(new RegExp(route.path === '/' ? '/?$' : route.path.replace('/', '\\/')), { timeout: 8000 })
      await expectHeading(page, route.heading)
    })
  }

  test('/addresses/:address loads address detail', async ({ page }) => {
    await page.goto(`${EXPLORER_URL}/addresses/${ADDRESS_TEST}`, { waitUntil: 'domcontentloaded', timeout: 20000 })
    await expectHeading(page, /Address/i)
    await expect(page.getByText(/Back to addresses/i)).toBeVisible({ timeout: 10000 })
  })
})

test.describe('Explorer Frontend - Current Navigation', () => {
  test('global shell is present on both app and pages routes', async ({ page }) => {
    await page.goto(`${EXPLORER_URL}/wallet`, { waitUntil: 'domcontentloaded', timeout: 20000 })
    await expect(page.getByRole('link', { name: /Go to explorer home/i })).toBeVisible({ timeout: 10000 })
    await expect(page.getByText(/Support:/i)).toBeVisible({ timeout: 10000 })

    await page.goto(`${EXPLORER_URL}/transactions`, { waitUntil: 'domcontentloaded', timeout: 20000 })
    await expect(page.getByRole('link', { name: /Go to explorer home/i })).toBeVisible({ timeout: 10000 })
    await expect(page.getByText(/Support:/i)).toBeVisible({ timeout: 10000 })
  })

  test('wallet page exposes the current Chain 138 Snap action', async ({ page }) => {
    await page.goto(`${EXPLORER_URL}/wallet`, { waitUntil: 'domcontentloaded', timeout: 20000 })
    await expect(page.getByRole('button', { name: /Install Open Snap/i })).toBeVisible({ timeout: 10000 })
    await expect(page.getByText(/Chain 138 Open Snap/i)).toBeVisible({ timeout: 10000 })
  })

  test('blocks list links to a current block detail route', async ({ page }) => {
    await page.goto(`${EXPLORER_URL}/blocks`, { waitUntil: 'networkidle', timeout: 20000 })
    const blockLink = page.locator('a[href^="/blocks/"]').first()
    await expect(blockLink).toBeVisible({ timeout: 10000 })
    await blockLink.click()
    await expect(page).toHaveURL(/\/blocks\/\d+$/, { timeout: 10000 })
    await expect(page.getByText(/Back to blocks/i)).toBeVisible({ timeout: 10000 })
  })

  test('transactions list links to a current transaction detail route', async ({ page }) => {
    await page.goto(`${EXPLORER_URL}/transactions`, { waitUntil: 'networkidle', timeout: 20000 })
    const transactionLinks = page.locator('a[href^="/transactions/"]')
    const transactionCount = await transactionLinks.count()

    if (transactionCount === 0) {
      await expect(page.getByText(/Recent transactions are unavailable right now/i)).toBeVisible({ timeout: 10000 })
      await expect(page.getByRole('button', { name: /^Next$/i })).toBeDisabled()
      return
    }

    const href = await transactionLinks.first().getAttribute('href')
    expect(href).toMatch(/^\/transactions\/0x[a-f0-9]+$/i)
    await page.goto(`${EXPLORER_URL}${href}`, { waitUntil: 'domcontentloaded', timeout: 20000 })
    await expect(page).toHaveURL(/\/transactions\/0x[a-f0-9]+$/i, { timeout: 10000 })
    await expect(page.getByText(/Back to transactions/i)).toBeVisible({ timeout: 10000 })
  })

  test('addresses page opens a current address detail route', async ({ page }) => {
    await page.goto(`${EXPLORER_URL}/addresses`, { waitUntil: 'networkidle', timeout: 20000 })
    await page.getByPlaceholder('0x...').fill(ADDRESS_TEST)
    await page.getByRole('button', { name: /Open address/i }).click()
    await expect(page).toHaveURL(new RegExp(`/addresses/${ADDRESS_TEST}$`, 'i'), { timeout: 10000 })
    await expect(page.getByText(/Back to addresses/i)).toBeVisible({ timeout: 10000 })
  })

  test('homepage keeps recent blocks visible when stats are temporarily unavailable', async ({ page }) => {
    const assertConsole = collectUnexpectedConsoleErrors(page, [
      /api\/v2\/stats/i,
      /503/i,
      /service unavailable/i,
    ])

    await page.route(`${EXPLORER_URL}/api/v2/stats`, async (route) => {
      await route.fulfill({
        status: 503,
        contentType: 'application/json',
        body: JSON.stringify({ error: 'service_unavailable' }),
      })
    })

    await page.route(new RegExp(`${EXPLORER_URL.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/api/v2/blocks\\?.*`), async (route) => {
      await route.fulfill({
        status: 200,
        contentType: 'application/json',
        body: JSON.stringify({
          items: [
            {
              hash: '0xabc',
              height: 4321,
              timestamp: '2026-04-05T00:00:00.000Z',
              miner: { hash: '0xdef' },
              transaction_count: 7,
              gas_used: 21000,
              gas_limit: 30000000,
            },
          ],
        }),
      })
    })

    await page.goto(`${EXPLORER_URL}/`, { waitUntil: 'domcontentloaded', timeout: 20000 })
    await expect(page.getByText(/Live network stats are temporarily unavailable/i)).toBeVisible({ timeout: 10000 })
    await expect(page.getByRole('link', { name: /Block #4321/i })).toBeVisible({ timeout: 10000 })
    await assertConsole()
  })
})
