import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { defineComponent, h } from 'vue'
import { mount, flushPromises } from '@vue/test-utils'
import { usePolling } from '@/composables/usePolling'

function mountPolling(fetchFn, intervalMs = 1_000) {
  let exposed
  const Comp = defineComponent({
    setup() {
      exposed = usePolling(fetchFn, intervalMs)
      return exposed
    },
    render: () => h('div'),
  })
  const wrapper = mount(Comp)
  return { wrapper, exposed }
}

describe('usePolling', () => {
  beforeEach(() => {
    vi.useFakeTimers()
  })

  afterEach(() => {
    vi.useRealTimers()
  })

  it('callsFetchOnMount', async () => {
    const fetchFn = vi.fn().mockResolvedValue({ ok: true })
    mountPolling(fetchFn)
    await flushPromises()
    expect(fetchFn).toHaveBeenCalledTimes(1)
  })

  it('callsFetchAtInterval', async () => {
    const fetchFn = vi.fn().mockResolvedValue(null)
    mountPolling(fetchFn, 1_000)
    await flushPromises()
    expect(fetchFn).toHaveBeenCalledTimes(1)

    vi.advanceTimersByTime(1_000)
    await flushPromises()
    expect(fetchFn).toHaveBeenCalledTimes(2)
  })

  it('clearsIntervalOnUnmount', async () => {
    const fetchFn = vi.fn().mockResolvedValue(null)
    const { wrapper } = mountPolling(fetchFn, 1_000)
    await flushPromises()
    expect(fetchFn).toHaveBeenCalledTimes(1)

    wrapper.unmount()
    vi.advanceTimersByTime(5_000)
    await flushPromises()
    expect(fetchFn).toHaveBeenCalledTimes(1)
  })

  it('setsErrorOnFailure', async () => {
    const fetchFn = vi.fn().mockRejectedValue(new Error('network error'))
    const { exposed } = mountPolling(fetchFn)
    await flushPromises()
    expect(exposed.error.value).toBe('network error')
  })
})
