import { EventEmitter } from 'node:events'
import { createRequire } from 'node:module'

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

const { observeProcessClose } = createRequire(import.meta.url)('../tests/install/e2e-assets/process-close.cjs')

it('waits for native close, not exit, and retains a close observed before hand-off', async () => {
  const pipe = { destroy: vi.fn() }
  const child = Object.assign(new EventEmitter(), { stdio: [null, pipe], exitCode: null, signalCode: null })
  const waitForClose = observeProcessClose(child)
  expect(pipe.destroy).not.toHaveBeenCalled()
  let finished = false
  const completion = waitForClose().then(() => { finished = true })
  child.emit('exit', 0)
  expect(pipe.destroy).toHaveBeenCalledOnce()
  await Promise.resolve()
  expect(finished).toBe(false)
  child.emit('close', 0)
  await completion
  expect(finished).toBe(true)
  await expect(waitForClose()).resolves.toBeUndefined()
})

it('fails if the launched process never closes', async () => {
  vi.useFakeTimers()

  try {
    const waitForClose = observeProcessClose(Object.assign(new EventEmitter(), { stdio: [], exitCode: null, signalCode: null }))
    const completion = expect(waitForClose(2_000)).rejects.toThrow()
    await vi.advanceTimersByTimeAsync(2_000)
    await completion
    expect(vi.getTimerCount()).toBe(0)
  } finally {
    vi.useRealTimers()
  }
})
