/**
 * Sprint UI-deep, пункт 12: Login edge cases.
 * - Неверный пароль → читаемая ошибка, не белый экран
 * - Rate-limit на /connect/token (6 попыток за минуту?) → 429 + понятный текст
 * - Forgot-password flow открывается без ошибок
 */
import { test, expect, request as apiRequest } from '@playwright/test'
import { watchPage, expectNoErrors } from '../lib/ui.js'

const BASE = process.env.E2E_ADMIN_URL ?? 'https://test.admin.food-market.kz'

test.describe('UI-12 login edge cases', () => {
  test.describe.configure({ mode: 'serial' })

  test('12.1 неверный пароль → читаемая ошибка на UI', async ({ page }) => {
    const errs = watchPage(page, {
      // 400 на /connect/token ожидаем
      expected4xxContains: ['/connect/token'],
    })
    await page.goto('/login')
    await expect(page).toHaveURL(/\/login/)

    // Заполняем поля
    await page.getByLabel(/email/i).fill('nonexistent-' + Date.now() + '@food-market.local')
    await page.getByLabel(/пароль/i).fill('WrongPassword123!')
    await page.getByRole('button', { name: /войти|sign in/i }).click()

    // На UI должна появиться ошибка — НЕ белый экран, НЕ generic
    await page.waitForLoadState('networkidle')
    const visibleText = await page.locator('body').innerText()
    // Должны быть ключевые слова: неверный, неправильн, неактивн, пароль, login
    expect(visibleText, 'после wrong password — текст ошибки должен быть видим')
      .toMatch(/неверн|неправильн|invalid|wrong|incorrect/i)
    // НЕ должно быть generic «Request failed»
    expect(visibleText).not.toContain('Request failed with status code')

    expectNoErrors(errs, 'wrong password')
  })

  test('12.2 rate-limit: 7+ попыток подряд → 429 на одной из них', async () => {
    test.setTimeout(60_000)
    const ctx = await apiRequest.newContext({ baseURL: BASE, ignoreHTTPSErrors: true })
    let got429 = false
    for (let i = 0; i < 10; i++) {
      const body = new URLSearchParams({
        grant_type: 'password',
        username: `ratelimit-${Date.now()}-${i}@food-market.local`,
        password: 'NonExistent12345!',
        client_id: 'food-market-web',
        scope: 'openid profile email roles api',
      })
      const r = await ctx.post('/connect/token', {
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        data: body.toString(),
        failOnStatusCode: false,
      })
      if (r.status() === 429) {
        got429 = true
        // Сообщение должно быть на человеческом языке
        const text = await r.text()
        expect(text, '429 должен иметь понятный текст')
          .toMatch(/слишком много|too many|попыт|attempt|rate.?limit/i)
        break
      }
    }
    // На production-стейдже rate-limit обычно настроен. Если нет — known issue.
    if (!got429) {
      console.warn('[UI-12.2] WARNING: за 10 попыток login не получили 429 — rate-limit или не настроен, или окно > 10')
      test.info().annotations.push({ type: 'known-bug', description: 'login rate-limit не сработал за 10 попыток' })
    }
    await ctx.dispose()
  })

  test('12.3 forgot-password страница рендерится', async ({ page }) => {
    const errs = watchPage(page, {
      expected4xxContains: ['/api/auth/forgot-password'],
    })
    await page.goto('/forgot-password')
    await page.waitForLoadState('networkidle')

    // Поле email
    const emailInput = page.getByLabel(/email/i).first()
    await expect(emailInput).toBeVisible({ timeout: 5_000 })
    // Кнопка «Отправить» / «Сбросить»
    await expect(page.getByRole('button', { name: /отправ|сбросить|reset/i }).first()).toBeVisible({ timeout: 5_000 })

    // Заполняем фейковый email и отправляем — должен пройти безсбоев
    await emailInput.fill(`forgot-${Date.now()}@food-market.local`)
    await page.getByRole('button', { name: /отправ|сбросить|reset/i }).first().click()
    await page.waitForLoadState('networkidle')
    // UI должно показать success-сообщение (security: всегда «отправлено» даже если email не найден)
    const txt = await page.locator('main, body').innerText()
    expect(txt).toMatch(/отправ|проверьте|sent|check.*email/i)

    expectNoErrors(errs, 'forgot password')
  })

  test('12.4 правильный логин → редирект на /', async ({ page }) => {
    const errs = watchPage(page)
    // Сначала создадим юзера через signup
    const ts = Date.now()
    const ctx = await apiRequest.newContext({ baseURL: BASE, ignoreHTTPSErrors: true, timeout: 60_000 })
    const email = `login-ok-${ts}@food-market.local`
    const password = 'LoginOK12345!'
    let r = await ctx.post('/api/auth/signup', {
      data: { email, password, organizationName: `LoginOK${ts}`, phone: '+77011190001', plan: 'start' },
      failOnStatusCode: false,
    })
    for (let i = 0; i < 5 && r.status() === 429; i++) {
      await new Promise(res => setTimeout(res, 15_000))
      r = await ctx.post('/api/auth/signup', {
        data: { email, password, organizationName: `LoginOK${ts}`, phone: '+77011190001', plan: 'start' },
        failOnStatusCode: false,
      })
    }
    expect(r.status()).toBe(200)
    await ctx.dispose()

    // Логинимся через UI
    await page.goto('/login')
    await page.getByLabel(/email/i).fill(email)
    await page.getByLabel(/пароль/i).fill(password)
    await page.getByRole('button', { name: /войти|sign in/i }).click()

    // Должен быть redirect с /login на /dashboard или /
    await page.waitForURL((u) => !u.pathname.startsWith('/login'), { timeout: 10_000 })
    expect(page.url()).not.toContain('/login')

    expectNoErrors(errs, 'login ok')
  })
})
