import { describe, it, expect, vi, beforeEach } from 'vitest'
import { useHighlights } from '../useHighlights'

vi.mock('../../api/client', () => ({
  api: { get: vi.fn(), post: vi.fn(), delete: vi.fn() },
}))
vi.mock('../useToast', () => ({
  useToast: () => ({ apiError: vi.fn(), success: vi.fn(), error: vi.fn(), warning: vi.fn(), info: vi.fn() }),
}))

describe('useHighlights', () => {
  beforeEach(() => {
    vi.restoreAllMocks()
  })

  it('initial state is empty with no form visible', () => {
    const { highlights, showHlForm, hlToolbarVisible, hlText } = useHighlights(12345)
    expect(highlights.value).toEqual([])
    expect(showHlForm.value).toBe(false)
    expect(hlToolbarVisible.value).toBe(false)
    expect(hlText.value).toBe('')
  })

  it('handleCreateHighlight posts and reloads', async () => {
    const { api } = await import('../../api/client')
    vi.mocked(api.post).mockResolvedValue({ data: {} })
    vi.mocked(api.get).mockResolvedValue({ data: [{ id: 'h1', text: 'existing' }] })

    const { hlText, handleCreateHighlight, highlights } = useHighlights(12345)
    hlText.value = 'test highlight'
    await handleCreateHighlight()
    expect(api.post).toHaveBeenCalledWith('/highlights/12345', expect.objectContaining({
      highlight_type: 'highlight',
      text: 'test highlight',
    }))
    expect(highlights.value).toHaveLength(1)
    expect(hlText.value).toBe('')
  })

  it('handleCreateHighlight does nothing for empty text', async () => {
    const { handleCreateHighlight, highlights } = useHighlights(12345)
    await handleCreateHighlight()
    expect(highlights.value).toEqual([])
  })

  it('handleDeleteHighlight removes from list', async () => {
    const { api } = await import('../../api/client')
    vi.mocked(api.get).mockResolvedValue({ data: [] })
    vi.mocked(api.delete).mockResolvedValue({})

    const { highlights: hls, handleDeleteHighlight } = useHighlights(12345)
    hls.value = [{ id: 'h1', text: 'a' }, { id: 'h2', text: 'b' }] as any
    await handleDeleteHighlight('h1')
    expect(hls.value).toHaveLength(1)
    expect(api.delete).toHaveBeenCalledWith('/highlights/h1')
  })

  it('onAbstractMouseup shows toolbar when text is selected', () => {
    const mockSelection = {
      isCollapsed: false,
      toString: () => 'selected text',
    } as any
    vi.spyOn(window, 'getSelection').mockReturnValue(mockSelection)

    const { hlToolbarVisible, hlToolbarPos, onAbstractMouseup } = useHighlights(12345)
    const event = { clientX: 100, clientY: 200 } as MouseEvent
    onAbstractMouseup(event)
    expect(hlToolbarVisible.value).toBe(true)
    expect(hlToolbarPos.value).toEqual({ x: 100, y: 200 })
  })

  it('onAbstractMouseup hides toolbar when no selection', () => {
    vi.spyOn(window, 'getSelection').mockReturnValue({
      isCollapsed: true,
      toString: () => '',
    } as any)

    const { hlToolbarVisible, onAbstractMouseup } = useHighlights(12345)
    onAbstractMouseup({} as MouseEvent)
    expect(hlToolbarVisible.value).toBe(false)
  })

  it('useSelectedText sets hlText from selection', () => {
    const mockRemoveAllRanges = vi.fn()
    const mockSelection = {
      isCollapsed: false,
      toString: () => 'selected text',
      removeAllRanges: mockRemoveAllRanges,
    } as any
    vi.spyOn(window, 'getSelection').mockReturnValue(mockSelection)

    const { hlText, showHlForm, hlToolbarVisible, useSelectedText } = useHighlights(12345)
    useSelectedText()
    expect(hlText.value).toBe('selected text')
    expect(showHlForm.value).toBe(true)
    expect(hlToolbarVisible.value).toBe(false)
    expect(mockRemoveAllRanges).toHaveBeenCalled()
  })
})
