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

import DraggableDroppableTagRow from '@/components/DraggableDroppableTagRow'
import { buildTag } from '@/test/factories'
import { renderWithProviders } from '@/test/render'

const dndKit = vi.hoisted (() => ({
  useDraggable: vi.fn (),
  useDroppable: vi.fn (),
}))

vi.mock ('@dnd-kit/core', () => dndKit)

const tag = buildTag ({ id: 7, name: 'ドラッグ元', postCount: 3 })

const renderRow = (activeDndId?: string) => {
  renderWithProviders (
      <DraggableDroppableTagRow
          activeDndId={activeDndId}
          tag={tag}
          nestLevel={2}
          pathKey="cat-general-7"
          suppressClickRef={{ current: false }}/>,
  )
}

const tagBody = (): HTMLElement => {
  const link = document.querySelector<HTMLElement> ('a[title="ドラッグ元"]')

  if (link == null)
    throw new Error ('tag link not found')

  const body = link.closest ('div')

  if (body == null)
    throw new Error ('tag body not found')

  return body
}

describe ('DraggableDroppableTagRow', () => {
  beforeEach (() => {
    vi.clearAllMocks ()
    dndKit.useDraggable.mockReturnValue ({
        attributes: { 'aria-describedby': 'drag-source' },
        listeners:  { onPointerDown: vi.fn () },
        setNodeRef: vi.fn (),
        transform:  null })
    dndKit.useDroppable.mockReturnValue ({
        isOver:     false,
        setNodeRef: vi.fn () })
  })

  it ('passes dndId through draggable data for active-row tracking', () => {
    renderRow ()

    expect (dndKit.useDraggable).toHaveBeenCalledWith (
        expect.objectContaining ({
            id:   'tag-node:cat-general-7',
            data: expect.objectContaining ({
                dndId:     'tag-node:cat-general-7',
                nestLevel: 2,
                tagId:     7 }) }))
  })

  it ('hides only the active drag source from the explicit active dnd id', () => {
    renderRow ('tag-node:cat-general-7')
    expect (tagBody ()).toHaveStyle ({ visibility: 'hidden' })
  })

  it ('keeps inactive tag rows visible while another tag is dragged', () => {
    renderRow ('tag-node:other')
    expect (tagBody ()).toHaveStyle ({ visibility: 'visible' })
  })
})
