import { test } from '@japa/runner'
import sinon from 'sinon'
import { EventTypes } from '../../../src/events/EventTypes.js'
import { Events } from '../../../src/events/Events.js'
import { ensureUnique } from './EventsTestHelpers.js'
import './events_polyfills.js'

test.group('Events > Process > EventTypes.Process', () => {
  test('has the namespace', ({ assert }) => {
    assert.typeOf(EventTypes.Process, 'object')
  })

  test('has "{prop}" property')
    .with([
      { prop: 'loadingStart', value: 'processloadingstart' },
      { prop: 'loadingStop', value: 'processloadingstop' },
      { prop: 'loadingError', value: 'processloadingerror' },
    ])
    .run(({ assert }, { prop, value }) => {
      // @ts-expect-error Used in testing
      assert.equal(EventTypes.Process[prop], value)
    })

  test('has unique events for the namespace', () => {
    ensureUnique('EventTypes.Process', EventTypes.Process)
  })
})

test.group('Events > Process > Events.Process > loadingStart()', () => {
  const pid = 'process-id-1'
  const message = 'test-message'

  test('dispatches the event', ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Process.loadingStart, spy)
    Events.Process.loadingStart(pid, message)
    globalThis.removeEventListener(EventTypes.Process.loadingStart, spy)
    assert.isTrue(spy.calledOnce)
  })

  test('has the pid on the event', ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Process.loadingStart, spy)
    Events.Process.loadingStart(pid, message)
    globalThis.removeEventListener(EventTypes.Process.loadingStart, spy)
    const e = spy.args[0][0] as CustomEvent
    assert.equal(e.detail.pid, pid)
  })

  test('has the message on the event', ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Process.loadingStart, spy)
    Events.Process.loadingStart(pid, message)
    globalThis.removeEventListener(EventTypes.Process.loadingStart, spy)
    const e = spy.args[0][0] as CustomEvent
    assert.equal(e.detail.message, message)
  })
})

test.group('Events > Process > Events.Process > loadingStop()', () => {
  const pid = 'process-id-1'

  test('dispatches the event', ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Process.loadingStop, spy)
    Events.Process.loadingStop(pid)
    globalThis.removeEventListener(EventTypes.Process.loadingStop, spy)
    assert.isTrue(spy.calledOnce)
  })

  test('has the pid on the event', ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Process.loadingStop, spy)
    Events.Process.loadingStop(pid)
    globalThis.removeEventListener(EventTypes.Process.loadingStop, spy)
    const e = spy.args[0][0] as CustomEvent
    assert.equal(e.detail.pid, pid)
  })
})

test.group('Events > Process > Events.Process > loadingError()', () => {
  const pid = 'process-id-1'
  const message = 'test-message'
  const error = new Error('test-message')

  test('dispatches the event', ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Process.loadingError, spy)
    Events.Process.loadingError(pid, message)
    globalThis.removeEventListener(EventTypes.Process.loadingError, spy)
    assert.isTrue(spy.calledOnce)
  })

  test('has the pid on the event', ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Process.loadingError, spy)
    Events.Process.loadingError(pid, message)
    globalThis.removeEventListener(EventTypes.Process.loadingError, spy)
    const e = spy.args[0][0] as CustomEvent
    assert.equal(e.detail.pid, pid)
  })

  test('has the message on the event', ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Process.loadingError, spy)
    Events.Process.loadingError(pid, message)
    globalThis.removeEventListener(EventTypes.Process.loadingError, spy)
    const e = spy.args[0][0] as CustomEvent
    assert.equal(e.detail.message, message)
  })

  test('has the optional error on the event', ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Process.loadingError, spy)
    Events.Process.loadingError(pid, message, error)
    globalThis.removeEventListener(EventTypes.Process.loadingError, spy)
    const e = spy.args[0][0] as CustomEvent
    assert.deepEqual(e.detail.error, error)
  })
})
