import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { focusEditorWithRetries } from './editorFocusUtils'

describe('editorFocusUtils extra coverage', () => {
  beforeEach(() => {
    document.body.innerHTML = ''
  })

  afterEach(() => {
    vi.restoreAllMocks()
    document.body.innerHTML = ''
  })

  it('uses window focus and selection fallback before logging successful focus timing', () => {
    const editable = document.createElement('div')
    editable.className = 'ProseMirror'
    editable.contentEditable = 'true'
    editable.setAttribute('contenteditable', 'true')
    editable.tabIndex = -1
    Object.defineProperty(editable, 'isContentEditable', { configurable: true, value: true })
    document.body.appendChild(editable)

    const realFocus = HTMLElement.prototype.focus.bind(editable)
    let focusCalls = 0
    vi.spyOn(editable, 'focus').mockImplementation(() => {
      focusCalls += 1
      if (focusCalls >= 2) realFocus()
    })

    const selection = {
      removeAllRanges: vi.fn(),
      addRange: vi.fn(),
    } as unknown as Selection

    vi.spyOn(window.navigator, 'userAgent', 'get').mockReturnValue('Mozilla/5.0')
    const windowFocusSpy = vi.spyOn(window, 'focus').mockImplementation(() => {})
    vi.spyOn(window, 'getSelection').mockReturnValue(selection)
    vi.spyOn(performance, 'now').mockReturnValue(150)
    const debugSpy = vi.spyOn(console, 'debug').mockImplementation(() => {})

    focusEditorWithRetries({ focus: vi.fn() }, false, 100)

    expect(windowFocusSpy).toHaveBeenCalled()
    expect(selection.removeAllRanges).toHaveBeenCalled()
    expect(selection.addRange).toHaveBeenCalledTimes(1)
    expect(debugSpy).toHaveBeenCalledWith('[perf] createNote → focus: 50.0ms')
  })

  it('uses the fallback editable selector and treats mixed heading content as empty text', () => {
    const wrapper = document.createElement('div')
    wrapper.className = 'bn-editor'
    const editable = document.createElement('div')
    editable.contentEditable = 'true'
    editable.setAttribute('contenteditable', 'true')
    editable.tabIndex = -1
    Object.defineProperty(editable, 'isContentEditable', { configurable: true, value: true })
    wrapper.appendChild(editable)
    document.body.appendChild(wrapper)

    const realFocus = HTMLElement.prototype.focus.bind(editable)
    vi.spyOn(editable, 'focus').mockImplementation(() => realFocus())

    const rAF = vi.spyOn(window, 'requestAnimationFrame').mockImplementation((cb) => {
      cb(0)
      return 1
    })

    const setTextCursorPosition = vi.fn()

    focusEditorWithRetries({
      focus: vi.fn(),
      document: [
        {
          id: 'title',
          type: 'heading',
          content: [{ kind: 'ignored' }, { type: 'text' }],
        },
      ],
      setTextCursorPosition,
    }, true, undefined)

    expect(rAF).toHaveBeenCalled()
    expect(setTextCursorPosition).toHaveBeenCalledWith('title', 'start')
  })

  it('schedules another animation frame when nothing focusable is available yet', () => {
    const rAF = vi.spyOn(window, 'requestAnimationFrame').mockImplementation(() => 1)

    focusEditorWithRetries({ focus: vi.fn() }, false, undefined)

    expect(rAF).toHaveBeenCalledTimes(1)
  })
})
