import { describe, expect, it, vi } from 'vitest'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { Document } from '@tiptap/extension-document'
import { Paragraph } from '@tiptap/extension-paragraph'
import { Text } from '@tiptap/extension-text'
import { RichTextEditor } from './RichTextEditor'

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

describe('RichTextEditor', () => {
  it('renders an editable region with the passed aria-label', async () => {
    render(<RichTextEditor value="" onChange={vi.fn()} aria-label="Article body" />)
    const editor = await getEditor('Article body')
    expect(editor.getAttribute('aria-label')).toBe('Article body')
    expect(editor.getAttribute('contenteditable')).toBe('true')
  })

  it('fires onChange with HTML when content is updated', async () => {
    const onChange = vi.fn()
    render(<RichTextEditor value="<p></p>" onChange={onChange} aria-label="Body" />)
    await getEditor('Body')

    const bold = screen.getByRole('button', { name: 'Bold' })
    fireEvent.click(bold)

    await waitFor(() => {
      expect(onChange).toHaveBeenCalled()
      const last = onChange.mock.calls.at(-1)?.[0] as string
      expect(typeof last).toBe('string')
      expect(last).toMatch(/<p/)
    })
  })

  it('loads value HTML into the editor (round-trip)', async () => {
    const html = '<p><strong>Hello</strong></p>'
    render(<RichTextEditor value={html} onChange={vi.fn()} aria-label="Body" />)
    const editor = await getEditor('Body')
    await waitFor(() => {
      expect(editor.querySelector('strong')?.textContent).toBe('Hello')
    })
  })

  it("applies dir='rtl' to the editor root", async () => {
    render(<RichTextEditor value="" onChange={vi.fn()} dir="rtl" aria-label="Body" />)
    const editor = await getEditor('Body')
    expect(editor.getAttribute('dir')).toBe('rtl')
  })

  it('makes the editor non-editable when readOnly', async () => {
    render(<RichTextEditor value="<p>x</p>" onChange={vi.fn()} readOnly aria-label="Body" />)
    const editor = await getEditor('Body')
    await waitFor(() => {
      expect(editor.getAttribute('contenteditable')).toBe('false')
    })
  })

  it('toolbar Bold button toggles bold and reflects aria-pressed', async () => {
    render(<RichTextEditor value="<p>word</p>" onChange={vi.fn()} aria-label="Body" />)
    await getEditor('Body')

    const bold = screen.getByRole('button', { name: 'Bold' })
    expect(bold.getAttribute('aria-pressed')).toBe('false')

    fireEvent.click(bold)
    await waitFor(() => {
      expect(bold.getAttribute('aria-pressed')).toBe('true')
    })

    fireEvent.click(bold)
    await waitFor(() => {
      expect(bold.getAttribute('aria-pressed')).toBe('false')
    })
  })

  it('custom extensions override the default set', async () => {
    render(
      <RichTextEditor
        value="<h2>Title</h2><p>plain</p>"
        onChange={vi.fn()}
        aria-label="Body"
        extensions={{ extensions: [Document, Paragraph, Text] }}
        renderToolbar={() => null}
      />,
    )
    const editor = await getEditor('Body')
    await waitFor(() => {
      expect(editor.querySelector('h2')).toBeNull()
      expect(editor.textContent).toContain('plain')
    })
  })
})
