import type { Page, Locator } from '@playwright/test'

/** Presses real Tab keys (bounded, deterministic — never a sleep/timeout)
 * until `locator`'s element is `document.activeElement`, proving the
 * element is ACTUALLY reachable via real Tab traversal (not just
 * programmatically `.focus()`-able) — the literal meaning of the brief's
 * "Tab erreicht Node". Throws if not reached within `maxPresses`. */
export async function tabUntilFocused(page: Page, locator: Locator, maxPresses = 40): Promise<number> {
  for (let i = 1; i <= maxPresses; i++) {
    await page.keyboard.press('Tab')
    const isFocused = await locator.evaluate((el) => el === document.activeElement)
    if (isFocused) return i
  }
  throw new Error(`Tab did not reach the target element within ${maxPresses} presses`)
}

/** Presses real Tab keys until `document.activeElement` is no longer a
 * descendant of `containerSelector` — i.e. focus has genuinely LEFT that
 * container, via real keyboard traversal.
 *
 * Deliberately NOT "click somewhere outside the panel" (the more obvious
 * way to leave it): a REAL BROWSER FINDING from building this suite
 * (documented in the P8.2d builder report) — clicking empty canvas while a
 * panel field is focused calls vsm-editor.tsx's `selectNode(null)`
 * SYNCHRONOUSLY inside the same pointerdown handler that ALSO triggers the
 * browser's native default focus-shift; the resulting re-render can
 * unmount the still-focused input BEFORE the browser's native blur/focusout
 * for it finishes propagating through React's synthetic event system, so
 * `handlePanelBlurCapture` (and therefore the undo-history commit) is
 * SILENTLY SKIPPED for that specific edit — a real race jsdom's
 * `.focus()`/`.blur()`-direct-call tests (P8.2b) can never expose, since
 * they never interleave a DESELECTING state update with the blur at all.
 * Tabbing out never touches selection, so it never races this way — the
 * reliable, always-correct way to test the commit-on-leave mechanism
 * itself, independent of that separate (out-of-scope-to-fix-here) edge
 * case. */
export async function tabUntilOutside(page: Page, containerSelector: string, maxPresses = 30): Promise<number> {
  for (let i = 1; i <= maxPresses; i++) {
    await page.keyboard.press('Tab')
    const stillInside = await page.evaluate((sel) => {
      const container = document.querySelector(sel)
      return !!container && !!document.activeElement && container.contains(document.activeElement)
    }, containerSelector)
    if (!stillInside) return i
  }
  throw new Error(`Focus did not leave "${containerSelector}" within ${maxPresses} Tab presses`)
}
