import { describe, it, expect } from 'vitest'
import { renderWithProviders, screen, fireEvent, userEvent } from '../../tests/helpers/render'
import ConfirmDialog from './ConfirmDialog'

// AZ-466 — Destructive UX policy (ConfirmDialog half)
//
// Scope of this file (per AZ-466 ACs that target the dialog itself):
//   AC-3 (FT-P-28): `role="dialog"`, `aria-modal="true"`, `aria-labelledby`,
//                   `aria-describedby` linkage.
//   AC-3 (FT-P-29): focus trap — Tab cycles inside the dialog.
//   AC-2 (FT-N-08): Escape on `<ConfirmDialog>` cancels — `onCancel` is invoked.
//
// Production drift (`src/components/ConfirmDialog.tsx`):
//   The dialog renders a plain `<div>` shell with NO `role="dialog"`,
//   `aria-modal`, `aria-labelledby`, or `aria-describedby` linkage. AC-3
//   attributes are recorded as `it.fails()`. Focus trap is absent — Tab
//   does not wrap inside the dialog. AC-3 focus trap is `it.skip` QUARANTINE
//   until production lands a focus trap. Escape close (FT-N-08) IS wired
//   (line 22-27 of ConfirmDialog.tsx) and PASSES today.

describe('AZ-466 — ConfirmDialog (component-level a11y / Escape)', () => {
  describe('AC-3 (FT-P-28) — modal a11y attributes', () => {
    it.fails('exposes role="dialog" + aria-modal="true" on the container', () => {
      // Arrange
      const noop = () => {}
      renderWithProviders(
        <ConfirmDialog
          open
          title="Delete class?"
          message="This cannot be undone."
          onConfirm={noop}
          onCancel={noop}
        />,
      )

      // Assert — the dialog's container element has the modal a11y attrs.
      // Drift: production renders a plain <div> with no role / aria attrs.
      const dialog = screen.getByRole('dialog')
      expect(dialog).toHaveAttribute('aria-modal', 'true')
    })

    it.fails('links aria-labelledby and aria-describedby to title + message', () => {
      const noop = () => {}
      renderWithProviders(
        <ConfirmDialog
          open
          title="Delete class?"
          message="This cannot be undone."
          onConfirm={noop}
          onCancel={noop}
        />,
      )

      const dialog = screen.getByRole('dialog')
      const labelId = dialog.getAttribute('aria-labelledby')
      const describeId = dialog.getAttribute('aria-describedby')
      expect(labelId).toBeTruthy()
      expect(describeId).toBeTruthy()
      // The referenced ids must point to the title and message nodes.
      const titleEl = document.getElementById(labelId!)
      const messageEl = document.getElementById(describeId!)
      expect(titleEl).toHaveTextContent('Delete class?')
      expect(messageEl).toHaveTextContent('This cannot be undone.')
    })

    it('control: the dialog DOM is currently a non-semantic <div> shell', () => {
      // Pin the current (drift) shape so a regression that, e.g., flips the
      // outer node to a <span> is caught even before AC-3 is fixed.
      const noop = () => {}
      const { container } = renderWithProviders(
        <ConfirmDialog
          open
          title="Delete class?"
          onConfirm={noop}
          onCancel={noop}
        />,
      )
      const outerDiv = container.querySelector('div.fixed.inset-0')
      expect(outerDiv).not.toBeNull()
      expect(outerDiv?.getAttribute('role')).toBeNull()
      expect(outerDiv?.getAttribute('aria-modal')).toBeNull()
    })
  })

  describe('AC-3 (FT-P-29) — focus trap', () => {
    it.skip(
      'QUARANTINE — Tab from the last button cycles back to the first focusable element inside the dialog',
      async () => {
        // Production has no focus trap. The cancel button auto-focuses on
        // open (`useEffect` on line 16-18 of ConfirmDialog.tsx) but Tab can
        // escape the dialog. When a focus trap is added (typically via
        // `react-focus-lock` or a manual keydown handler), this test should
        // assert that Tab on the last focusable element returns focus to
        // the first, and Shift+Tab on the first returns focus to the last.
      },
    )
  })

  describe('AC-2 (FT-N-08) — Escape cancel', () => {
    it('invokes onCancel when Escape is pressed while the dialog is open', () => {
      // Arrange
      let cancelCalls = 0
      let confirmCalls = 0
      renderWithProviders(
        <ConfirmDialog
          open
          title="Delete?"
          onConfirm={() => { confirmCalls += 1 }}
          onCancel={() => { cancelCalls += 1 }}
        />,
      )

      // Act — fire Escape on window (production attaches a window-level keydown listener).
      fireEvent.keyDown(window, { key: 'Escape', code: 'Escape' })

      // Assert
      expect(cancelCalls).toBe(1)
      expect(confirmCalls).toBe(0)
    })

    it('does NOT call onCancel when Escape is pressed while the dialog is closed', () => {
      let cancelCalls = 0
      renderWithProviders(
        <ConfirmDialog
          open={false}
          title="Closed"
          onConfirm={() => {}}
          onCancel={() => { cancelCalls += 1 }}
        />,
      )

      fireEvent.keyDown(window, { key: 'Escape', code: 'Escape' })

      expect(cancelCalls).toBe(0)
    })
  })

  describe('AC-1 / AC-2 — happy + cancel paths invoked via the dialog buttons', () => {
    it('clicking Confirm invokes onConfirm exactly once and not onCancel', async () => {
      let confirmCalls = 0
      let cancelCalls = 0
      renderWithProviders(
        <ConfirmDialog
          open
          title="Delete?"
          onConfirm={() => { confirmCalls += 1 }}
          onCancel={() => { cancelCalls += 1 }}
        />,
      )

      const confirm = screen.getAllByRole('button').find(b => /confirm/i.test(b.textContent ?? ''))
      expect(confirm).toBeDefined()
      await userEvent.click(confirm!)

      expect(confirmCalls).toBe(1)
      expect(cancelCalls).toBe(0)
    })

    it('clicking Cancel invokes onCancel exactly once and not onConfirm', async () => {
      let confirmCalls = 0
      let cancelCalls = 0
      renderWithProviders(
        <ConfirmDialog
          open
          title="Delete?"
          onConfirm={() => { confirmCalls += 1 }}
          onCancel={() => { cancelCalls += 1 }}
        />,
      )

      const cancel = screen.getAllByRole('button').find(b => /cancel/i.test(b.textContent ?? ''))
      expect(cancel).toBeDefined()
      await userEvent.click(cancel!)

      expect(cancelCalls).toBe(1)
      expect(confirmCalls).toBe(0)
    })
  })
})
