import { expect, test, type Page } from '@playwright/test'
import { mkdirSync } from 'node:fs'
import path from 'node:path'

// e2e-full-stack.spec.ts
//
// Playwright spec that exercises the golden-path behaviours of the
// explorer against a *locally booted* backend + frontend, rather than
// against the production deploy that `e2e-explorer-frontend.spec.ts`
// targets. `make e2e-full` stands up the stack, points this spec at
// it via EXPLORER_URL / EXPLORER_API_URL, and tears it down afterwards.
//
// The spec intentionally sticks to Track-1 (public, no auth) routes so
// it can run without provisioning wallet credentials in CI. Track 2-4
// behaviours are covered by the Go and unit-test layers.

const EXPLORER_URL = process.env.EXPLORER_URL || 'http://localhost:3000'
const EXPLORER_API_URL = process.env.EXPLORER_API_URL || 'http://localhost:8080'
const SCREENSHOT_DIR = process.env.E2E_SCREENSHOT_DIR || 'test-results/screenshots'

mkdirSync(SCREENSHOT_DIR, { recursive: true })

async function snapshot(page: Page, name: string) {
  const file = path.join(SCREENSHOT_DIR, `${name}.png`)
  await page.screenshot({ path: file, fullPage: true })
}

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

test.describe('Explorer full-stack smoke', () => {
  test('backend /healthz responds 200', async ({ request }) => {
    const response = await request.get(`${EXPLORER_API_URL}/healthz`)
    expect(response.status()).toBeLessThan(500)
  })

  for (const route of [
    { path: '/', heading: /DBIS Explorer/i, name: 'home' },
    { path: '/blocks', heading: /^Blocks$/i, name: 'blocks' },
    { path: '/transactions', heading: /^Transactions$/i, name: 'transactions' },
    { path: '/addresses', heading: /^Addresses$/i, name: 'addresses' },
    { path: '/tokens', heading: /^Tokens$/i, name: 'tokens' },
    { path: '/pools', heading: /^Pools$/i, name: 'pools' },
    { path: '/search', heading: /^Search$/i, name: 'search' },
    { path: '/wallet', heading: /Wallet & MetaMask/i, name: 'wallet' },
    { path: '/routes', heading: /Route/i, name: 'routes' },
  ]) {
    test(`frontend route ${route.path} renders`, async ({ page }) => {
      await page.goto(`${EXPLORER_URL}${route.path}`, {
        waitUntil: 'domcontentloaded',
        timeout: 30000,
      })
      await expectHeading(page, route.heading)
      await snapshot(page, route.name)
    })
  }

  test('access products endpoint is reachable', async ({ request }) => {
    // Covers the YAML-backed catalogue wired up in PR #7. The endpoint
    // is public (lists available RPC products) so no auth is needed.
    const response = await request.get(`${EXPLORER_API_URL}/api/v1/access/products`)
    expect(response.status()).toBe(200)
    const body = await response.json()
    expect(Array.isArray(body.products)).toBe(true)
    expect(body.products.length).toBeGreaterThanOrEqual(3)
  })

  test('auth nonce endpoint issues a nonce', async ({ request }) => {
    // Covers wallet auth kickoff: /api/v1/auth/nonce must issue a
    // fresh nonce even without credentials. This is Track-1-safe.
    const response = await request.post(`${EXPLORER_API_URL}/api/v1/auth/nonce`, {
      data: { address: '0x4A666F96fC8764181194447A7dFdb7d471b301C8' },
    })
    expect(response.status()).toBe(200)
    const body = await response.json()
    expect(typeof body.nonce === 'string' && body.nonce.length > 0).toBe(true)
  })
})
