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

// AZ-477 — e2e companion for Settings save resilience + 2 s deadline.
//
// AC-1 (FT-N-13 / NFT-RES-05): real backend returns 500 on settings PUT;
//                              SPA renders an error region AND clears the
//                              `saving` flag (button enabled again) within
//                              2 s. Today both contracts are drift —
//                              `test.fail()` until try/finally + alert lands.
// AC-2 (FT-N-14 / NFT-RES-06): same on a network drop. The fast-profile
//                              test pins both contracts against MSW; this
//                              companion exercises the real wire boundary
//                              against the suite stack.
// AC-3 (NFT-PERF-09):          ≤ 2 s deadline for error visibility — pinned
//                              in the fast suite via `performance.now()`;
//                              the e2e companion just asserts visibility
//                              within Playwright's 2 s timeout.
//
// Requires the suite docker-compose stack (`e2e/docker-compose.suite-e2e.yml`).
// Uses `page.route` to inject the failure mode without depending on a real
// crashed backend in CI.

test.describe('AZ-477 — Settings save resilience (e2e companion)', () => {
  test.fail(
    'AC-1 (500) — Save button re-enables AND error region visible within 2 s',
    async ({ page }) => {
      // Force the system-settings PUT to fail with a 500. Other endpoints
      // pass through so the page mounts normally.
      await page.route('**/api/annotations/settings/system', async (route) => {
        if (route.request().method() === 'PUT') {
          await route.fulfill({ status: 500, body: 'upstream failure' })
          return
        }
        await route.continue()
      })

      await page.goto('/settings')

      // Tenant Configuration heading + scoped Save button — same anchor as
      // the fast suite. If the suite seed has no tenant config, the test
      // reports the gap rather than masking the UI.
      const tenantHeading = page.getByRole('heading', { name: /Tenant Configuration/i })
      if (!(await tenantHeading.isVisible({ timeout: 5000 }).catch(() => false))) {
        test.skip(true, 'Suite UI did not render Settings → Tenant Configuration')
      }
      const tenantPanel = tenantHeading.locator('xpath=..')
      const saveBtn = tenantPanel.getByRole('button', { name: /^Save$/i })

      await saveBtn.click()

      // Both assertions race the 2 s deadline.
      await expect(saveBtn).toBeEnabled({ timeout: 2000 })
      const alertEl = page.getByRole('alert').first()
      await expect(alertEl).toBeVisible({ timeout: 2000 })
      await expect(alertEl).toContainText(/error|failed|try again|500/i)
    },
  )

  test.fail(
    'AC-2 (network drop) — Save button re-enables AND error region visible within 2 s',
    async ({ page }) => {
      await page.route('**/api/annotations/settings/system', async (route) => {
        if (route.request().method() === 'PUT') {
          await route.abort('connectionfailed')
          return
        }
        await route.continue()
      })

      await page.goto('/settings')

      const tenantHeading = page.getByRole('heading', { name: /Tenant Configuration/i })
      if (!(await tenantHeading.isVisible({ timeout: 5000 }).catch(() => false))) {
        test.skip(true, 'Suite UI did not render Settings → Tenant Configuration')
      }
      const tenantPanel = tenantHeading.locator('xpath=..')
      const saveBtn = tenantPanel.getByRole('button', { name: /^Save$/i })

      await saveBtn.click()

      await expect(saveBtn).toBeEnabled({ timeout: 2000 })
      const alertEl = page.getByRole('alert').first()
      await expect(alertEl).toBeVisible({ timeout: 2000 })
    },
  )
})
