import { describe, it, expect, afterEach } from 'vitest'
import { mount, VueWrapper } from '@vue/test-utils'
import ConfirmDialog from '../ConfirmDialog.vue'

let wrapper: VueWrapper

function mountDialog(props: Record<string, unknown> = {}) {
  wrapper = mount(ConfirmDialog, {
    props: {
      open: true,
      ...props,
    },
    attachTo: document.body,
  })
  return wrapper
}

function dialog() {
  return document.body.querySelector('.confirm-dialog')
}

function overlay() {
  return document.body.querySelector('.confirm-dialog__overlay')
}

afterEach(() => {
  wrapper?.unmount()
})

describe('ConfirmDialog', () => {
  it('renders when open is true', () => {
    mountDialog()
    expect(dialog()).not.toBeNull()
  })

  it('does not render when open is false', () => {
    mountDialog({ open: false })
    expect(dialog()).toBeNull()
  })

  it('displays default title', () => {
    mountDialog()
    expect(dialog()!.querySelector('.confirm-dialog__title')!.textContent).toBe('Are you sure?')
  })

  it('displays custom title and message', () => {
    mountDialog({
      title: 'Remove event?',
      message: 'This cannot be undone.',
    })
    expect(dialog()!.querySelector('.confirm-dialog__title')!.textContent).toBe('Remove event?')
    expect(dialog()!.querySelector('.confirm-dialog__message')!.textContent).toBe('This cannot be undone.')
  })

  it('displays custom button labels', () => {
    mountDialog({
      confirmLabel: 'Delete',
      cancelLabel: 'Keep',
    })
    const buttons = dialog()!.querySelectorAll('.confirm-dialog__btn')
    expect(buttons[0]!.textContent!.trim()).toBe('Keep')
    expect(buttons[1]!.textContent!.trim()).toBe('Delete')
  })

  it('emits confirm when confirm button is clicked', async () => {
    mountDialog()
    const btn = dialog()!.querySelector('.confirm-dialog__btn--confirm') as HTMLElement
    btn.click()
    await wrapper.vm.$nextTick()
    expect(wrapper.emitted('confirm')).toHaveLength(1)
  })

  it('emits cancel when cancel button is clicked', async () => {
    mountDialog()
    const btn = dialog()!.querySelector('.confirm-dialog__btn--cancel') as HTMLElement
    btn.click()
    await wrapper.vm.$nextTick()
    expect(wrapper.emitted('cancel')).toHaveLength(1)
  })

  it('emits cancel when overlay is clicked', async () => {
    mountDialog()
    const el = overlay() as HTMLElement
    el.click()
    await wrapper.vm.$nextTick()
    expect(wrapper.emitted('cancel')).toHaveLength(1)
  })

  it('emits cancel when Escape key is pressed', async () => {
    mountDialog()
    const el = dialog() as HTMLElement
    el.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
    await wrapper.vm.$nextTick()
    expect(wrapper.emitted('cancel')).toHaveLength(1)
  })

  it('focuses cancel button when opened', async () => {
    mountDialog({ open: false })
    await wrapper.setProps({ open: true })
    await wrapper.vm.$nextTick()
    const cancelBtn = dialog()!.querySelector('.confirm-dialog__btn--cancel')
    expect(document.activeElement).toBe(cancelBtn)
  })

  it('has alertdialog role and aria-modal', () => {
    mountDialog()
    const el = dialog() as HTMLElement
    expect(el.getAttribute('role')).toBe('alertdialog')
    expect(el.getAttribute('aria-modal')).toBe('true')
  })
})
