/**
 * Shared Playwright helpers for Nexus SPA E2E.
 */
import { expect } from '@playwright/test'

export const BASE = process.env.NEXUS_E2E_BASE || 'https://api.synaglobal.vip'
export const USER = process.env.NEXUS_E2E_USER || 'admin'
export const PASS = process.env.NEXUS_E2E_PASSWORD || ''
export const APP = `${BASE.replace(/\/$/, '')}/app/`

const SIDEBAR_LINKS = {
  '/': '仪表盘',
  '/servers': '服务器',
  '/terminal': '终端',
  '/files': '文件管理',
  '/push': '推送',
  '/scripts': '脚本库',
  '/executions': '执行记录',
  '/schedules': '调度',
  '/retries': '重试队列',
  '/commands': '命令日志',
  '/alerts': '告警中心',
  '/audit': '审计日志',
}

const E2E_ACCESS_TOKEN = process.env.NEXUS_E2E_ACCESS_TOKEN || ''

/** Mock refresh + profile so Pinia bootstraps with a pre-minted JWT (bypass login IP allowlist). */
export async function loginWithAccessToken(page, accessToken = E2E_ACCESS_TOKEN) {
  if (!accessToken) {
    throw new Error('Set NEXUS_E2E_ACCESS_TOKEN for token-based E2E login')
  }
  await page.route('**/api/auth/refresh', async (route) => {
    await route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify({ access_token: accessToken }),
    })
  })
  await page.route('**/api/auth/me', async (route) => {
    await route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify({
        id: 1,
        username: USER,
        totp_enabled: false,
        created_at: '2020-01-01T00:00:00Z',
      }),
    })
  })
  await page.goto(`${APP}#/`, { waitUntil: 'domcontentloaded' })
  await expect(page).not.toHaveURL(/#\/login/, { timeout: 20000 })
  await expect(page.getByRole('button', { name: USER })).toBeVisible({ timeout: 15000 })
}

/** Restore session from worker refresh cookie (avoids parallel UI logins / lockout). */
export async function login(page) {
  if (E2E_ACCESS_TOKEN) {
    return loginWithAccessToken(page, E2E_ACCESS_TOKEN)
  }
  await page.goto(`${APP}#/`, { waitUntil: 'domcontentloaded' })
  await expect(page).not.toHaveURL(/#\/login/, { timeout: 20000 })
  await expect(page.getByRole('button', { name: 'admin' })).toBeVisible({ timeout: 15000 })
}

/** Navigate via drawer clicks (reliable with Vue keep-alive; hash goto alone is flaky). */
export async function nav(page, hash) {
  const path = hash.startsWith('/') ? hash : `/${hash}`
  const routePath = path.split('?')[0]
  const escaped = routePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')

  if (routePath === '/settings') {
    await page.locator('.v-navigation-drawer').getByText('设置', { exact: true }).click()
  } else {
    const label = SIDEBAR_LINKS[routePath]
    if (!label) throw new Error(`Unknown route for nav(): ${path}`)
    await page.getByRole('link', { name: label, exact: true }).click()
  }

  await expect(page).toHaveURL(new RegExp(`#${escaped}(?:\\?|$)`), { timeout: 20000 })

  if (path.includes('?')) {
    await page.evaluate((p) => {
      window.location.hash = `#${p}`
    }, path)
    await expect(page).toHaveURL(new RegExp(`#${escaped}\\?`), { timeout: 10000 })
  }

  await page.waitForLoadState('networkidle').catch(() => {})
}

/** ISO UTC bare string e.g. 2026-06-08T12:00:00Z — should not appear in display columns */
export const ISO_UTC_RE = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z/
