import { describe, it, expect, beforeEach, vi } from 'vitest'
import { flushPromises, type VueWrapper } from '@vue/test-utils'
import { readBody } from 'h3'
import { mountSuspended, registerEndpoint } from '@nuxt/test-utils/runtime'
import ContactModal from './ContactModal.vue'
import { useContactModal } from '~/composables/useContactModal'

let lastRequestBody: unknown
let shouldFail = false

registerEndpoint('/api/contact', {
  method: 'POST',
  handler: async (event) => {
    lastRequestBody = await readBody(event)
    if (shouldFail) {
      throw new Error('SMTP unavailable')
    }
    return { ok: true }
  },
})

async function fillRequiredFields(wrapper: VueWrapper) {
  await wrapper.find('input[type="text"]').setValue('Jane Doe')
  await wrapper.find('input[type="email"]').setValue('jane@example.com')
  await wrapper.find('textarea').setValue('Hello there')
}

async function selectSubject(wrapper: VueWrapper, label: string) {
  await wrapper.find('.app-select-trigger').trigger('click')
  const option = wrapper.findAll('.app-select-option').find((o) => o.text() === label)
  await option!.trigger('click')
}

describe('ContactModal', () => {
  beforeEach(() => {
    lastRequestBody = undefined
    shouldFail = false
    useContactModal().close()
  })

  it('renders nothing when closed', async () => {
    const wrapper = await mountSuspended(ContactModal)
    expect(wrapper.find('.contact-modal-overlay').exists()).toBe(false)
  })

  it('preselects the subject when opened via a specific topic', async () => {
    const wrapper = await mountSuspended(ContactModal)
    useContactModal().open('volunteer')
    await wrapper.vm.$nextTick()

    expect(wrapper.find('.contact-modal-overlay').exists()).toBe(true)
    expect(wrapper.find('.app-select-trigger').text()).toBe('Volunteering')
  })

  it('shows a validation error and does not submit when no subject is chosen', async () => {
    useContactModal().open()
    const wrapper = await mountSuspended(ContactModal)
    await fillRequiredFields(wrapper)

    await wrapper.find('form').trigger('submit.prevent')
    await flushPromises()

    expect(wrapper.text()).toContain('Please select a subject.')
    expect(lastRequestBody).toBeUndefined()
  })

  it('submits the form with the entered data and shows a success state', async () => {
    useContactModal().open()
    const wrapper = await mountSuspended(ContactModal)
    await fillRequiredFields(wrapper)
    await selectSubject(wrapper, 'Learn About Programs')

    await wrapper.find('form').trigger('submit.prevent')

    await vi.waitFor(() => {
      expect(wrapper.text()).toContain('Thank you for reaching out to DLEAG!')
    })
    expect(lastRequestBody).toMatchObject({
      name: 'Jane Doe',
      email: 'jane@example.com',
      subject: 'programs',
      message: 'Hello there',
    })
  })

  it('shows a generic error message when the request fails', async () => {
    shouldFail = true
    useContactModal().open()
    const wrapper = await mountSuspended(ContactModal)
    await fillRequiredFields(wrapper)
    await selectSubject(wrapper, 'Partnership')

    await wrapper.find('form').trigger('submit.prevent')

    await vi.waitFor(() => {
      expect(wrapper.text()).toContain('Something went wrong sending your message.')
    })
    expect(wrapper.text()).not.toContain('Thank you for reaching out to DLEAG!')
  })

  it('closes via the close button and the composable state stays in sync', async () => {
    useContactModal().open()
    const wrapper = await mountSuspended(ContactModal)

    await wrapper.find('.contact-modal-close').trigger('click')

    expect(useContactModal().isOpen.value).toBe(false)
  })
})
