/**
 * U1 — Authentication state persistence E2E.
 *
 * Regression coverage for the "reload jumps to /login" bug (issue #4 from
 * 2026-06-28): the JWT secret was unset → AuthMiddleware entered dev mode →
 * the persisted refresh token was silently ignored on cold-start, so every
 * page reload lost the session.
 *
 * These tests exercise the full cold-start path:
 *   persisted refresh token → /auth/whoami → fresh access token → router
 * guard admits the user to /agent/*.
 *
 * ponytail: tests use the UI form for the initial login (same pattern as
 * calendar.spec.ts) to avoid the localStorage-hydration cold-start race
 * that affected earlier helpers. Subsequent reloads rely on the refresh
 * token that the auth store persists to localStorage (Web mode fallback).
 */

import { test, expect } from '@playwright/test'
import {
  TEST_USER,
  clearAuth,
  reloadAndWaitAuth,
  corruptRefreshToken,
} from './helpers'

test.describe('Auth state persistence', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/login')
    await clearAuth(page)
  })

  test('logged-in user survives page reload (cold-start whoami succeeds)', async ({
    page,
  }) => {
    // Login via the UI form so the refresh token is persisted via the
    // standard code path (tauriAuthStorage → localStorage fallback).
    await page.getByPlaceholder('请输入用户名').fill(TEST_USER.username)
    await page.getByPlaceholder('请输入密码').fill(TEST_USER.password)
    await page.getByRole('button', { name: /登\s*录/ }).click()
    await expect(page).toHaveURL(/\/agent/, { timeout: 15_000 })

    // Reload — the access token is in memory only, so cold-start MUST
    // re-issue one from the persisted refresh token. If the JWT secret
    // is ephemeral or dev mode is active, this reload lands on /login.
    const finalUrl = await reloadAndWaitAuth(page)
    expect(finalUrl).toMatch(/\/agent/)
    expect(finalUrl).not.toMatch(/\/login/)

    // The user avatar / top-nav should be visible (not the login form).
    await expect(page.getByPlaceholder('请输入用户名')).not.toBeVisible()
  })

  test('cleared localStorage on reload redirects to /login', async ({ page }) => {
    // Login first to obtain a valid session.
    await page.getByPlaceholder('请输入用户名').fill(TEST_USER.username)
    await page.getByPlaceholder('请输入密码').fill(TEST_USER.password)
    await page.getByRole('button', { name: /登\s*录/ }).click()
    await expect(page).toHaveURL(/\/agent/, { timeout: 15_000 })

    // Wipe persisted tokens — simulates user clearing site data.
    await clearAuth(page)

    const finalUrl = await reloadAndWaitAuth(page)
    expect(finalUrl).toMatch(/\/login/)
    // Login form should be visible.
    await expect(page.getByPlaceholder('请输入用户名')).toBeVisible({ timeout: 10_000 })
  })

  test('invalid persisted refresh token is rejected and cleared on cold-start', async ({
    page,
  }) => {
    await page.getByPlaceholder('请输入用户名').fill(TEST_USER.username)
    await page.getByPlaceholder('请输入密码').fill(TEST_USER.password)
    await page.getByRole('button', { name: /登\s*录/ }).click()
    await expect(page).toHaveURL(/\/agent/, { timeout: 15_000 })

    // Replace the persisted refresh token with a fake — the server should
    // return 401 from /auth/whoami, the store should transition to
    // 'invalid' and clear the bad token, then the router redirects to /login.
    await corruptRefreshToken(page)

    const finalUrl = await reloadAndWaitAuth(page)
    expect(finalUrl).toMatch(/\/login/)

    // The corrupted token must have been cleared by the store — otherwise
    // the next reload would retry the same dead token forever.
    const storedRefresh = await page.evaluate(() =>
      localStorage.getItem('agentkit.refresh_token'),
    )
    expect(storedRefresh).toBeNull()
  })

  test('protected page requests carry the Authorization header', async ({
    page,
  }) => {
    await page.getByPlaceholder('请输入用户名').fill(TEST_USER.username)
    await page.getByPlaceholder('请输入密码').fill(TEST_USER.password)
    await page.getByRole('button', { name: /登\s*录/ }).click()
    await expect(page).toHaveURL(/\/agent/, { timeout: 15_000 })

    // Intercept the next authenticated API call and capture its headers.
    let capturedAuth: string | null = null
    page.on('request', (req) => {
      const h = req.headers()
      if (h['authorization'] && !capturedAuth) {
        capturedAuth = h['authorization']
      }
    })

    // Trigger an authenticated call by reloading — startupCheck fires
    // whoami, which itself carries the refresh token. But the more
    // meaningful signal is the first post-startup data fetch (e.g.
    // conversations list) which carries the access token.
    await page.reload()
    await expect(page).toHaveURL(/\/agent/, { timeout: 20_000 })

    // Wait for at least one authenticated request to land.
    await expect
      .poll(async () => (capturedAuth ? true : false), {
        timeout: 15_000,
        intervals: [500],
      })
      .toBe(true)

    expect(capturedAuth).toBeTruthy()
    expect(capturedAuth!).toMatch(/^Bearer\s+\S+/)
  })

  test('access token is never written to localStorage', async ({ page }) => {
    // Access token must remain in memory only — see stores/auth.ts.
    // If a regression writes it to localStorage, this test catches it.
    await page.getByPlaceholder('请输入用户名').fill(TEST_USER.username)
    await page.getByPlaceholder('请输入密码').fill(TEST_USER.password)
    await page.getByRole('button', { name: /登\s*录/ }).click()
    await expect(page).toHaveURL(/\/agent/, { timeout: 15_000 })

    // Give the store a moment to finish persisting post-login.
    await page.waitForTimeout(500)

    const storedAccess = await page.evaluate(() =>
      localStorage.getItem('agentkit.access_token'),
    )
    expect(storedAccess).toBeNull()
  })
})
