import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { http } from 'msw'
import { Route, Routes } from 'react-router-dom'
import userEvent from '@testing-library/user-event'
import type { ReactNode } from 'react'
import { server } from '../../tests/msw/server'
import { jsonResponse, paginate } from '../../tests/msw/helpers'
import { renderWithProviders, screen, waitFor } from '../../tests/helpers/render'
import { seedBearer, clearBearer } from '../../tests/helpers/auth'
import { seedFlights } from '../../tests/fixtures/seed_flights'
import { opAlice, seedPermissions } from '../../tests/fixtures/seed_users'
import { FlightProvider } from './FlightContext'
import Header from './Header'

// AZ-468 — Header flight-dropdown a11y + Escape handler.
//   FT-P-30  closed-state a11y     — aria-expanded=false, accessible trigger name
//   FT-P-31  open-state  a11y      — aria-expanded=true, role=listbox/menu,
//                                    aria-activedescendant points to a real id
//   FT-N-09  Escape close + detach — Escape closes the dropdown and the
//                                    document-level Escape handler is removed
//                                    (no leakage into other components).
//
// Production status (today): src/components/Header.tsx renders a plain
// <button> trigger and a <div> menu without any aria-* attributes, and the
// dropdown has NO Escape key handler (only a `mousedown` listener for
// click-outside). All three task ACs therefore fail today; FT-P-30/31 are
// captured as documented DRIFT via `it.fails()` (flips green when production
// gains the attributes); FT-N-09 is QUARANTINEd via `it.skip` because the
// behavior is wholly absent — there is no addEventListener('keydown', ...) in
// the dropdown to assert against.

function HeaderHarness({ children }: { children?: ReactNode }) {
  return <FlightProvider>{children}<Header /></FlightProvider>
}

function mountHeader() {
  return renderWithProviders(
    <Routes>
      <Route
        path="/flights"
        element={<HeaderHarness><div data-testid="content" /></HeaderHarness>}
      />
      <Route path="/login" element={<div data-testid="login-route" />} />
    </Routes>,
    { initialEntries: ['/flights'] },
  )
}

function wireAuthAndFlights() {
  server.use(
    // AZ-510 — bootstrap = POST refresh -> { token } + chained GET /users/me.
    http.post('/api/admin/auth/refresh', () => jsonResponse({ token: 'test-bearer-default' })),
    http.get('/api/admin/users/me', () =>
      jsonResponse({ ...opAlice, permissions: seedPermissions[opAlice.id] ?? [] }),
    ),
    http.get('/api/flights', ({ request }) => {
      const url = new URL(request.url)
      const pageSize = Number(url.searchParams.get('pageSize') ?? '50')
      return jsonResponse(paginate(seedFlights, 1, pageSize))
    }),
    http.get('/api/annotations/settings/user', () =>
      jsonResponse({
        id: 'us-1', userId: opAlice.id, selectedFlightId: null,
        annotationsLeftPanelWidth: null, annotationsRightPanelWidth: null,
        datasetLeftPanelWidth: null, datasetRightPanelWidth: null,
      }),
    ),
    http.put('/api/annotations/settings/user', async ({ request }) => {
      const body = await request.json()
      return jsonResponse(body)
    }),
  )
}

describe('AZ-468 / src/components/Header.tsx — flight dropdown', () => {
  beforeEach(() => {
    seedBearer()
    wireAuthAndFlights()
  })

  afterEach(() => {
    clearBearer()
    vi.restoreAllMocks()
  })

  describe('FT-P-30 — closed-state a11y', () => {
    it.fails(
      'trigger advertises aria-expanded=false when the menu is closed (drift: attribute currently missing)',
      async () => {
        mountHeader()

        // Wait for the flights list to have been fetched so the trigger is hydrated.
        await waitFor(() =>
          expect(screen.getByRole('button', { name: /select flight/i })).toBeInTheDocument(),
        )
        const trigger = screen.getByRole('button', { name: /select flight/i })

        // AC-1 contract: aria-expanded=false when closed; no aria-activedescendant.
        expect(trigger).toHaveAttribute('aria-expanded', 'false')
        expect(trigger).not.toHaveAttribute('aria-activedescendant')
      },
    )

    it('control — closed trigger today lacks aria-expanded entirely (drift seen)', async () => {
      mountHeader()
      await waitFor(() =>
        expect(screen.getByRole('button', { name: /select flight/i })).toBeInTheDocument(),
      )
      const trigger = screen.getByRole('button', { name: /select flight/i })
      expect(trigger).not.toHaveAttribute('aria-expanded')
    })
  })

  describe('FT-P-31 — open-state a11y', () => {
    it.fails(
      'opened dropdown advertises aria-expanded=true and listbox/menu role with a real aria-activedescendant (drift: attributes missing today)',
      async () => {
        const user = userEvent.setup()
        mountHeader()
        await waitFor(() =>
          expect(screen.getByRole('button', { name: /select flight/i })).toBeInTheDocument(),
        )
        const trigger = screen.getByRole('button', { name: /select flight/i })

        await user.click(trigger)

        // AC-2 contract.
        expect(trigger).toHaveAttribute('aria-expanded', 'true')
        const listbox = screen.getByRole('listbox')
        expect(listbox).toBeInTheDocument()
        const optionId = trigger.getAttribute('aria-activedescendant')
        expect(optionId).toBeTruthy()
        expect(document.getElementById(optionId as string)).not.toBeNull()
      },
    )

    it('control — opened dropdown today exposes options but with no role and no aria wiring (drift seen)', async () => {
      const user = userEvent.setup()
      mountHeader()
      await waitFor(() =>
        expect(screen.getByRole('button', { name: /select flight/i })).toBeInTheDocument(),
      )
      const trigger = screen.getByRole('button', { name: /select flight/i })
      await user.click(trigger)

      // The filter input renders on open, so the panel is visibly open.
      expect(screen.getByPlaceholderText(/filter/i)).toBeInTheDocument()
      // But none of the listbox roles or aria-activedescendant wiring exists yet.
      expect(screen.queryByRole('listbox')).toBeNull()
      expect(trigger).not.toHaveAttribute('aria-activedescendant')
    })
  })

  describe('FT-N-09 — Escape close + document-level handler detached', () => {
    it.skip(
      'QUARANTINE (no production behavior): Escape closes the dropdown and the document keydown handler is removed',
      async () => {
        // When the production code lands a document-level keydown listener that
        // handles Escape, this test asserts:
        //   1. Pressing Escape closes the dropdown (filter input gone)
        //   2. The document.addEventListener('keydown', ...) call made when the
        //      dropdown opened is paired with a removeEventListener('keydown', ...)
        //      with the SAME handler reference when the dropdown closes (verified
        //      via spies on document.addEventListener/removeEventListener).
        // The test below is a sketch of the assertion shape — left skipped because
        // Header has no keydown listener today and asserting against absent code
        // would produce noise, not signal.
        const addSpy = vi.spyOn(document, 'addEventListener')
        const removeSpy = vi.spyOn(document, 'removeEventListener')
        const user = userEvent.setup()
        mountHeader()
        await waitFor(() =>
          expect(screen.getByRole('button', { name: /select flight/i })).toBeInTheDocument(),
        )
        const trigger = screen.getByRole('button', { name: /select flight/i })

        await user.click(trigger)
        const keydownAdds = addSpy.mock.calls.filter(([type]) => type === 'keydown')
        expect(keydownAdds.length).toBeGreaterThanOrEqual(1)

        await user.keyboard('{Escape}')
        expect(screen.queryByPlaceholderText(/filter/i)).toBeNull()

        const keydownRemoves = removeSpy.mock.calls.filter(([type, fn]) =>
          type === 'keydown' && fn === keydownAdds[0]?.[1],
        )
        expect(keydownRemoves.length).toBeGreaterThanOrEqual(1)
      },
    )

    it('control — Escape today is a no-op; the dropdown stays open (drift seen)', async () => {
      const user = userEvent.setup()
      mountHeader()
      await waitFor(() =>
        expect(screen.getByRole('button', { name: /select flight/i })).toBeInTheDocument(),
      )
      const trigger = screen.getByRole('button', { name: /select flight/i })
      await user.click(trigger)
      expect(screen.getByPlaceholderText(/filter/i)).toBeInTheDocument()

      await user.keyboard('{Escape}')

      // QUARANTINE evidence: the filter input is still present — Escape did
      // nothing because the Header has no keydown handler today.
      expect(screen.getByPlaceholderText(/filter/i)).toBeInTheDocument()
    })
  })
})
