/// <reference types="node" />
// @vitest-environment jsdom
import React, { useState } from 'react'
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { Heading } from '@tiptap/extension-heading'
import { Image } from '@tiptap/extension-image'
import { axe } from 'vitest-axe'
import { afterEach, describe, expect, it, vi } from 'vitest'
import {
  EditorWidget,
  isEditorWidgetError,
  type EditorWidgetError,
  type EditorWidgetMediaAdapter,
  type EditorWidgetMediaItem,
  type EditorWidgetProps,
} from './index.js'

const editorHarness = vi.hoisted(() => ({ available: true }))
const previewHarness = vi.hoisted(() => ({ builds: 0 }))

vi.mock('@platform-modules/ui-editor', async (importOriginal) => {
  const actual = await importOriginal<typeof import('@platform-modules/ui-editor')>()
  const { createElement } = await import('react')
  return {
    ...actual,
    RichTextEditor: (props: React.ComponentProps<typeof actual.RichTextEditor>) =>
      editorHarness.available
        ? createElement(actual.RichTextEditor, props)
        : props.renderToolbar?.({
            editor: null,
            isBold: false,
            isItalic: false,
            isH2: false,
            isBullet: false,
          }),
  }
})

vi.mock('./preview.js', async (importOriginal) => {
  const actual = await importOriginal<typeof import('./preview.js')>()
  return {
    ...actual,
    buildPreviewDocument(sourceHtml: string, dir: 'ltr' | 'rtl') {
      previewHarness.builds += 1
      return actual.buildPreviewDocument(sourceHtml, dir)
    },
  }
})

const ImageWithDimensions = Image.extend({
  addAttributes() {
    return {
      ...this.parent?.(),
      width: { default: null },
      height: { default: null },
    }
  },
})

function mediaAdapter(
  item: EditorWidgetMediaItem = {
    src: 'https://cdn.example/image.jpg',
    alt: 'A "quoted" <cover>',
    width: 640,
    height: 480,
  },
): EditorWidgetMediaAdapter {
  return {
    extensions: {
      extensions: [ImageWithDimensions.configure({ allowBase64: false })],
    },
    renderPicker: ({ disabled, onSelect }) => (
      <button type="button" disabled={disabled} onClick={() => onSelect(item)}>
        Insert image
      </button>
    ),
  }
}

function renderControlledEditorWidget() {
  const onChange = vi.fn()
  function ControlledEditorWidget() {
    const [value, setValue] = useState('<p>Text</p>')
    return (
      <EditorWidget
        value={value}
        onChange={(nextValue) => {
          onChange(nextValue)
          setValue(nextValue)
        }}
        ariaLabel="Body"
      />
    )
  }
  render(<ControlledEditorWidget />)
  return onChange
}

async function editor(name = 'Body') {
  return waitFor(() => screen.getByRole('textbox', { name }))
}

function selectTab(name: 'Write' | 'Preview'): void {
  fireEvent.click(screen.getByRole('tab', { name }))
}

async function selectAllText(editorNode: HTMLElement): Promise<void> {
  editorNode.focus()
  fireEvent.keyDown(editorNode, { key: 'a', code: 'KeyA', ctrlKey: true })
  await Promise.resolve()
}

afterEach(() => {
  editorHarness.available = true
  previewHarness.builds = 0
})

describe('@platform-modules/ui-primitives/editor-widget public seam', () => {
  it('maps the public subpath to built JavaScript and declarations', () => {
    const packageJson = JSON.parse(
      readFileSync(resolve(process.cwd(), 'package.json'), 'utf8'),
    ) as { exports?: Record<string, { import?: string; types?: string }> }
    expect(packageJson.exports?.['./editor-widget']).toEqual({
      types: './dist/editor-widget/index.d.ts',
      import: './dist/editor-widget/index.js',
    })
  })

  it('accepts the public DTS-facing props and renders the exported component', async () => {
    const props: EditorWidgetProps = {
      value: '<p>Public import</p>',
      onChange: vi.fn(),
      ariaLabel: 'Body',
      className: 'consumer-class',
    }
    const { container } = render(<EditorWidget {...props} />)
    expect(await editor()).toHaveTextContent('Public import')
    expect(container.querySelector('[data-editor-widget]')).toHaveClass('consumer-class')
  })

  it('structurally identifies only supported EditorWidget errors', () => {
    const error = Object.assign(new Error('invalid'), {
      name: 'EditorWidgetError' as const,
      code: 'invalid_media' as const,
    }) satisfies EditorWidgetError

    expect(isEditorWidgetError(error)).toBe(true)
    expect(isEditorWidgetError({ name: 'EditorWidgetError', code: 'unknown', message: 'x' })).toBe(false)
    expect(isEditorWidgetError(new Error('x'))).toBe(false)
  })
})

describe('EditorWidget', () => {
  it('uses deterministic unique IDs and accessible names for two instances', async () => {
    const { container } = render(
      <>
        <EditorWidget value="" onChange={vi.fn()} ariaLabel="Primary body" />
        <EditorWidget value="" onChange={vi.fn()} ariaLabel="Secondary body" />
      </>,
    )

    await editor('Primary body')
    await editor('Secondary body')
    const sections = Array.from(container.querySelectorAll('[data-editor-widget]'))
    const labelIds = sections.map((section) => section.getAttribute('aria-labelledby'))
    expect(new Set(labelIds).size).toBe(2)
    for (const id of labelIds) {
      expect(id).toBeTruthy()
      expect(container.querySelectorAll(`[id="${id}"]`)).toHaveLength(1)
    }
    expect(screen.getByRole('toolbar', { name: 'Primary body formatting' })).toBeTruthy()
    expect(screen.getByRole('tablist', { name: 'Secondary body view' })).toBeTruthy()
  })

  it('uses only canonical semantic color tokens for widget states', async () => {
    render(<EditorWidget value="<p>Body</p>" onChange={vi.fn()} ariaLabel="Body" />)
    await editor()

    const classes = [
      screen.getByRole('button', { name: 'Bold' }).className,
      screen.getByRole('tab', { name: 'Write' }).className,
      screen.getByRole('tab', { name: 'Preview' }).parentElement?.className ?? '',
    ].join(' ')
    expect(classes).toContain('--mod-color-surface-raised')
    expect(classes).toContain('--mod-color-border-strong')
    expect(classes).toContain('--mod-color-accent')
    expect(classes).toContain('--mod-color-accent-fg')
    expect(screen.getByRole('tab', { name: 'Write' }).className).toContain('forced-colors:data-[state=active]:border-current')
    expect(screen.getByRole('tab', { name: 'Write' }).className).toMatch(/data-\[state=active\].*border/)
    expect(classes).not.toMatch(/--mod-(?:accent|neutral)-/)
  })

  it('mounts initial formatted HTML without emitting a change', async () => {
    const onChange = vi.fn()
    render(
      <EditorWidget
        value="<h2><strong>Heading</strong></h2><ul><li><p>Item</p></li></ul>"
        onChange={onChange}
        ariaLabel="Body"
      />,
    )

    const textbox = await editor()
    expect(textbox.querySelector('h2 strong')).toHaveTextContent('Heading')
    expect(textbox.querySelector('ul li')).toHaveTextContent('Item')
    expect(onChange).not.toHaveBeenCalled()
  })

  for (const testCase of [
    {
      name: 'Bold',
      key: 'Enter',
      expected: '<p dir="ltr"><strong>Text</strong></p>',
    },
    {
      name: 'Italic',
      key: ' ',
      expected: '<p dir="ltr"><em>Text</em></p>',
    },
    {
      name: 'Heading 2',
      key: 'Enter',
      expected: '<h2 dir="ltr">Text</h2>',
    },
    {
      name: 'Bullet list',
      key: ' ',
      expected: '<ul><li><p>Text</p></li></ul>',
    },
  ] as const) {
    it(`activates ${testCase.name} by keyboard and emits exact HTML with pressed state`, async () => {
      const onChange = renderControlledEditorWidget()
      const textbox = await editor()
      await selectAllText(textbox)

      const control = screen.getByRole('button', { name: testCase.name })
      control.focus()
      fireEvent.keyDown(control, { key: testCase.key })

      await waitFor(() => expect(onChange).toHaveBeenLastCalledWith(testCase.expected))
      expect(control).toHaveAttribute('aria-pressed', 'true')
    })
  }

  it('preserves the editor selection on pointer formatting and exposes platform-neutral shortcut hints', async () => {
    const onChange = renderControlledEditorWidget()
    const textbox = await editor()
    await selectAllText(textbox)
    const bold = screen.getByRole('button', { name: 'Bold' })
    fireEvent.pointerDown(bold)
    fireEvent.mouseDown(bold)
    fireEvent.click(bold)
    await waitFor(() => expect(onChange).toHaveBeenLastCalledWith('<p dir="ltr"><strong>Text</strong></p>'))
    expect(textbox).toHaveFocus()
    expect(screen.getByText(/Control\/Command\+B/)).toBeVisible()
    expect(screen.getByText(/Control\/Command\+I/)).toBeVisible()
    expect(bold).toHaveAttribute('aria-keyshortcuts', 'Control+B Meta+B')
  })

  it('implements one roving toolbar tab stop with ArrowLeft, ArrowRight, Home, and End', async () => {
    render(<EditorWidget value="<p>Body</p>" onChange={vi.fn()} ariaLabel="Body" />)
    await editor()
    const bold = screen.getByRole('button', { name: 'Bold' })
    const italic = screen.getByRole('button', { name: 'Italic' })
    const heading = screen.getByRole('button', { name: 'Heading 2' })
    const list = screen.getByRole('button', { name: 'Bullet list' })

    expect(bold).toHaveAttribute('tabindex', '0')
    expect(italic).toHaveAttribute('tabindex', '-1')
    bold.focus()
    fireEvent.keyDown(bold, { key: 'ArrowRight' })
    expect(italic).toHaveFocus()
    fireEvent.keyDown(italic, { key: 'End' })
    expect(list).toHaveFocus()
    fireEvent.keyDown(list, { key: 'ArrowLeft' })
    expect(heading).toHaveFocus()
    fireEvent.keyDown(heading, { key: 'Home' })
    expect(bold).toHaveFocus()
  })

  it('reverses only horizontal toolbar navigation in RTL', async () => {
    render(<EditorWidget value="<p>Body</p>" onChange={vi.fn()} ariaLabel="Body" dir="rtl" />)
    await editor()
    const bold = screen.getByRole('button', { name: 'Bold' })
    const italic = screen.getByRole('button', { name: 'Italic' })
    const list = screen.getByRole('button', { name: 'Bullet list' })

    bold.focus()
    fireEvent.keyDown(bold, { key: 'ArrowRight' })
    expect(list).toHaveFocus()
    fireEvent.keyDown(list, { key: 'ArrowLeft' })
    expect(bold).toHaveFocus()
    fireEvent.keyDown(bold, { key: 'ArrowLeft' })
    expect(italic).toHaveFocus()
    fireEvent.keyDown(italic, { key: 'End' })
    expect(list).toHaveFocus()
    fireEvent.keyDown(list, { key: 'Home' })
    expect(bold).toHaveFocus()
  })

  it('moves and wraps the Write and Preview tab focus with Arrow keys, Home, and End', async () => {
    render(<EditorWidget value="<p>Body</p>" onChange={vi.fn()} ariaLabel="Body" />)
    await editor()
    const write = screen.getByRole('tab', { name: 'Write' })
    const preview = screen.getByRole('tab', { name: 'Preview' })

    write.focus()
    fireEvent.keyDown(write, { key: 'ArrowRight' })
    expect(preview).toHaveFocus()
    expect(preview).toHaveAttribute('aria-selected', 'true')
    fireEvent.keyDown(preview, { key: 'ArrowRight' })
    expect(write).toHaveFocus()
    expect(write).toHaveAttribute('aria-selected', 'true')
    fireEvent.keyDown(write, { key: 'End' })
    expect(preview).toHaveFocus()
    fireEvent.keyDown(preview, { key: 'Home' })
    expect(write).toHaveFocus()
    fireEvent.keyDown(write, { key: 'ArrowLeft' })
    expect(preview).toHaveFocus()
  })

  it('keeps Home and End on DOM-first and DOM-last tabs in RTL', async () => {
    render(<EditorWidget value="<p>Body</p>" onChange={vi.fn()} ariaLabel="Body" dir="rtl" />)
    await editor()
    const write = screen.getByRole('tab', { name: 'Write' })
    const preview = screen.getByRole('tab', { name: 'Preview' })

    write.focus()
    fireEvent.keyDown(write, { key: 'Home' })
    expect(write).toHaveFocus()
    expect(write).toHaveAttribute('aria-selected', 'true')
    fireEvent.keyDown(write, { key: 'End' })
    expect(preview).toHaveFocus()
    expect(preview).toHaveAttribute('aria-selected', 'true')
  })

  it('keeps Write mounted and preserves its undo history across Preview tab switches', async () => {
    function ControlledWidget() {
      const [value, setValue] = useState('<p>Text</p>')
      return (
        <>
          <EditorWidget value={value} onChange={setValue} ariaLabel="Body" />
          <output data-testid="html">{value}</output>
        </>
      )
    }

    render(<ControlledWidget />)
    const textbox = await editor()
    await selectAllText(textbox)

    selectTab('Preview')
    const hiddenTextbox = screen.getByRole('textbox', { name: 'Body', hidden: true })
    expect(hiddenTextbox).toBe(textbox)
    const writePanel = textbox.closest('[data-editor-widget-part="write-panel"]') as HTMLElement
    expect(writePanel).toHaveAttribute('hidden')
    expect(writePanel).toHaveAttribute('aria-hidden', 'true')
    expect(writePanel).toHaveAttribute('inert')

    selectTab('Write')
    expect(screen.getByRole('textbox', { name: 'Body' })).toBe(textbox)
    const bold = screen.getByRole('button', { name: 'Bold' })
    bold.focus()
    fireEvent.keyDown(bold, { key: 'Enter' })
    await waitFor(() => expect(screen.getByTestId('html')).toHaveTextContent('<strong>Text</strong>'))

    textbox.focus()
    fireEvent.keyDown(textbox, { key: 'z', code: 'KeyZ', ctrlKey: true })
    await waitFor(() => expect(screen.getByTestId('html')).not.toHaveTextContent('<strong>'))
  })

  it('preserves editor instance, focus, and history across inline media-adapter rerenders', async () => {
    function InlineMediaWidget({ revision }: { revision: number }) {
      const [value, setValue] = useState('<p>Text</p>')
      return (
        <>
          <EditorWidget value={value} onChange={setValue} ariaLabel="Body" media={mediaAdapter()} />
          <output data-testid="html">{value}</output>
          <span data-testid="revision">{revision}</span>
        </>
      )
    }

    const { rerender } = render(<InlineMediaWidget revision={0} />)
    const textbox = await editor()
    await selectAllText(textbox)
    fireEvent.click(screen.getByRole('button', { name: 'Bold' }))
    await waitFor(() => expect(screen.getByTestId('html')).toHaveTextContent('<strong>Text</strong>'))

    textbox.focus()
    rerender(<InlineMediaWidget revision={1} />)
    expect(screen.getByTestId('revision')).toHaveTextContent('1')
    expect(screen.getByRole('textbox', { name: 'Body' })).toBe(textbox)
    expect(textbox).toHaveFocus()

    fireEvent.keyDown(textbox, { key: 'z', code: 'KeyZ', ctrlKey: true })
    await waitFor(() => expect(screen.getByTestId('html')).not.toHaveTextContent('<strong>'))
  })

  it('recreates the editor when media extension options legitimately change', async () => {
    const onChange = vi.fn()
    const configuredMedia = (allowBase64: boolean): EditorWidgetMediaAdapter => ({
      extensions: { extensions: [ImageWithDimensions.configure({ allowBase64 })] },
      renderPicker: () => null,
    })
    const { rerender } = render(
      <EditorWidget value="<p>Text</p>" onChange={onChange} ariaLabel="Body" media={configuredMedia(false)} />,
    )
    const initialTextbox = await editor()

    rerender(
      <EditorWidget value="<p>Text</p>" onChange={onChange} ariaLabel="Body" media={configuredMedia(true)} />,
    )
    await waitFor(() => expect(screen.getByRole('textbox', { name: 'Body' })).not.toBe(initialTextbox))
  })

  it('constructs Preview lazily and only recomputes it while Preview is active', async () => {
    const onChange = vi.fn()
    const { rerender } = render(
      <EditorWidget value="<p>First</p>" onChange={onChange} ariaLabel="Body" />,
    )
    await editor()
    expect(previewHarness.builds).toBe(0)
    expect(screen.queryByTitle('Body preview')).toBeNull()

    rerender(<EditorWidget value="<p>Second</p>" onChange={onChange} ariaLabel="Body" />)
    expect(previewHarness.builds).toBe(0)

    selectTab('Preview')
    expect(previewHarness.builds).toBe(1)
    expect(screen.getByTitle('Body preview')).toHaveAttribute('sandbox', '')

    rerender(<EditorWidget value="<p>Third</p>" onChange={onChange} ariaLabel="Body" />)
    expect(previewHarness.builds).toBe(2)
  })

  it('builds an RTL, sandboxed preview that structurally removes navigation, forms, and scripts', async () => {
    render(
      <EditorWidget
        value={'<h1>Preserved heading</h1><p dir="rtl">مرحبا</p><a href="https://example.com">Link</a><form><input value="x"><button>Send</button></form><script>alert(1)</script>'}
        onChange={vi.fn()}
        ariaLabel="Body"
        dir="rtl"
      />,
    )
    await editor()
    selectTab('Preview')

    const frame = screen.getByTitle('Body preview')
    const srcDoc = frame.getAttribute('srcdoc') ?? ''
    expect(frame).toHaveAttribute('sandbox', '')
    expect(frame).toHaveAttribute('tabindex', '0')
    expect(srcDoc).toContain('<html dir="rtl">')
    expect(srcDoc).toContain("default-src 'none'")
    expect(srcDoc).toContain("form-action 'none'")
    expect(srcDoc).toContain('<meta name="referrer" content="no-referrer">')
    expect(srcDoc).not.toContain('navigate-to')
    expect(srcDoc).not.toMatch(/<a\b|<form\b|<input\b|<button\b|<script\b/i)
    expect(srcDoc).toContain('<h1>Preserved heading</h1>')
    expect(srcDoc).toContain('Link')
  })

  it('keeps Preview available while read-only and exposes no editing commands or media insertion', async () => {
    render(
      <EditorWidget
        value="<h2>Read only</h2>"
        onChange={vi.fn()}
        ariaLabel="Body"
        readOnly
        media={mediaAdapter()}
      />,
    )

    const textbox = await editor()
    await waitFor(() => expect(textbox).toHaveAttribute('contenteditable', 'false'))
    expect(screen.queryByRole('toolbar')).toBeNull()
    expect(screen.queryByRole('button', { name: 'Insert image' })).toBeNull()
    selectTab('Preview')
    expect(screen.getByTitle('Body preview')).toBeTruthy()
  })

  it('inserts validated media through Tiptap serialization with escaped alt text and dimensions', async () => {
    const onChange = vi.fn()
    render(
      <EditorWidget
        value="<p>Body</p>"
        onChange={onChange}
        ariaLabel="Body"
        media={mediaAdapter()}
      />,
    )
    await editor()
    await waitFor(() => expect(screen.getByRole('button', { name: 'Insert image' })).not.toBeDisabled())
    fireEvent.click(screen.getByRole('button', { name: 'Insert image' }))

    await waitFor(() => expect(onChange).toHaveBeenCalled())
    const html = String(onChange.mock.calls.at(-1)?.[0] ?? '')
    const parsed = new DOMParser().parseFromString(html, 'text/html')
    const image = parsed.querySelector('img')
    expect(image?.getAttribute('src')).toBe('https://cdn.example/image.jpg')
    expect(image?.getAttribute('alt')).toBe('A "quoted" <cover>')
    expect(image?.getAttribute('width')).toBe('640')
    expect(image?.getAttribute('height')).toBe('480')
    expect(parsed.querySelector('cover')).toBeNull()
  })

  it('retains companion media extensions and lets supplied same-name extensions replace defaults', async () => {
    const media: EditorWidgetMediaAdapter = {
      extensions: {
        extensions: [
          Heading.configure({ levels: [1] }),
          ImageWithDimensions.configure({ allowBase64: false }),
        ],
      },
      renderPicker: () => null,
    }
    render(
      <EditorWidget
        value="<h1>Preserved heading</h1>"
        onChange={vi.fn()}
        ariaLabel="Body"
        media={media}
      />,
    )

    const textbox = await editor()
    expect(textbox.querySelector('h1')).toHaveTextContent('Preserved heading')
    expect(screen.queryByRole('button', { name: /Heading 1/i })).toBeNull()
    expect(textbox.querySelector('h2')).toBeNull()
  })

  it('forwards validation description to the editable textbox', async () => {
    render(
      <EditorWidget
        value="<p>Body</p>"
        onChange={vi.fn()}
        ariaLabel="Body"
        ariaDescribedBy="body-error"
      />,
    )
    expect(await editor()).toHaveAttribute('aria-describedby', 'body-error')
  })

  it('re-announces consecutive identical media success events with distinct live-region identity', async () => {
    render(
      <EditorWidget value="<p>Body</p>" onChange={vi.fn()} ariaLabel="Body" media={mediaAdapter()} />,
    )
    await editor()
    const insert = await screen.findByRole('button', { name: 'Insert image' })
    const status = screen.getByRole('status')

    fireEvent.click(insert)
    await waitFor(() => expect(status).toHaveTextContent('Image inserted.'))
    const firstEvent = status.firstElementChild
    fireEvent.click(insert)
    await waitFor(() => expect(status.firstElementChild).not.toBe(firstEvent))
    expect(status).toHaveTextContent('Image inserted.')
  })

  it('re-announces consecutive identical media errors with distinct live-region identity', async () => {
    const invalid = { src: 'http://unsafe.example/image.jpg', alt: 'Unsafe' }
    const adapter = mediaAdapter()
    adapter.renderPicker = ({ onSelect }) => (
      <button type="button" onClick={() => onSelect(invalid)}>Insert invalid image</button>
    )
    render(
      <EditorWidget value="<p>Body</p>" onChange={vi.fn()} ariaLabel="Body" media={adapter} />,
    )
    await editor()
    const insert = screen.getByRole('button', { name: 'Insert invalid image' })
    const status = screen.getByRole('status')

    fireEvent.click(insert)
    await waitFor(() => expect(status).toHaveTextContent('The selected image is invalid.'))
    const firstEvent = status.firstElementChild
    fireEvent.click(insert)
    await waitFor(() => expect(status.firstElementChild).not.toBe(firstEvent))
    expect(status).toHaveTextContent('The selected image is invalid.')
  })

  it('reports invalid media structurally and does not mutate the document', async () => {
    const onChange = vi.fn()
    const onError = vi.fn()
    const invalid = {
      src: 'javascript:alert(1)',
      alt: 3,
      width: 0,
      height: Number.POSITIVE_INFINITY,
    } as unknown as EditorWidgetMediaItem

    let result: boolean | undefined
    const invalidAdapter = mediaAdapter(invalid)
    invalidAdapter.renderPicker = ({ disabled, onSelect }) => (
      <button type="button" disabled={disabled} onClick={() => { result = onSelect(invalid) }}>
        Insert image
      </button>
    )

    render(
      <EditorWidget
        value="<p>Body</p>"
        onChange={onChange}
        ariaLabel="Body"
        media={invalidAdapter}
        onError={onError}
      />,
    )
    await editor()
    await waitFor(() => expect(screen.getByRole('button', { name: 'Insert image' })).not.toBeDisabled())
    fireEvent.click(screen.getByRole('button', { name: 'Insert image' }))

    expect(result).toBe(false)
    expect(onChange).not.toHaveBeenCalled()
    expect(onError).toHaveBeenCalledOnce()
    expect(isEditorWidgetError(onError.mock.calls[0]?.[0])).toBe(true)
    expect(onError.mock.calls[0]?.[0]).toMatchObject({
      name: 'EditorWidgetError',
      code: 'invalid_media',
    })
  })

  it('keeps an unavailable picker disabled and reports a forced unavailable insertion without discarding it', () => {
    editorHarness.available = false
    let select: ((item: EditorWidgetMediaItem) => boolean) | undefined
    const onError = vi.fn()
    const media: EditorWidgetMediaAdapter = {
      extensions: { extensions: [ImageWithDimensions] },
      renderPicker: (props) => {
        select = props.onSelect
        return (
          <button type="button" disabled={props.disabled}>
            Unavailable picker
          </button>
        )
      },
    }

    render(
      <EditorWidget
        value="<p>Body</p>"
        onChange={vi.fn()}
        ariaLabel="Body"
        media={media}
        onError={onError}
      />,
    )

    expect(screen.getByRole('button', { name: 'Unavailable picker' })).toBeDisabled()
    expect(screen.getByRole('button', { name: 'Unavailable picker' })).toBeInTheDocument()
    expect(select?.({ src: 'https://cdn.example/image.jpg', alt: 'Cover' })).toBe(false)
    expect(onError).toHaveBeenCalledWith(
      expect.objectContaining({ name: 'EditorWidgetError', code: 'media_insert_failed' }),
    )
  })

  it('has no axe violations in its interactive Write state', async () => {
    const { container } = render(
      <EditorWidget value="<p>Accessible</p>" onChange={vi.fn()} ariaLabel="Article body" media={mediaAdapter()} />,
    )
    await editor('Article body')
    const results = await axe(container, { rules: { 'color-contrast': { enabled: false } } })
    expect(results).toHaveNoViolations()
  })
})
