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 > Encryption > EventTypes.Encryption', () => {
  test('has the namespace', ({ assert }) => {
    assert.typeOf(EventTypes.Encryption, 'object')
  })

  test('has "{prop}" property')
    .with([
      { prop: 'encrypt', value: 'encryptionencrypt' },
      { prop: 'decrypt', value: 'encryptiondecrypt' },
    ])
    .run(({ assert }, { prop, value }) => {
      // @ts-expect-error Used in testing
      assert.equal(EventTypes.Encryption[prop], value)
    })

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

test.group('Events > Encryption > Events.Encryption > encrypt()', () => {
  const data = 'export data'
  const passphrase = 'passphrase data'
  const method = 'aes'

  test('dispatches the event', async ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Encryption.encrypt, spy)
    await Events.Encryption.encrypt(data, passphrase, method)
    globalThis.removeEventListener(EventTypes.Encryption.encrypt, spy)
    assert.isTrue(spy.calledOnce)
  })

  test('has the data on the event', async ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Encryption.encrypt, spy)
    await Events.Encryption.encrypt(data, passphrase, method)
    globalThis.removeEventListener(EventTypes.Encryption.encrypt, spy)
    const e = spy.args[0][0] as CustomEvent
    assert.equal(e.detail.data, data)
  })

  test('has the passphrase on the event', async ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Encryption.encrypt, spy)
    await Events.Encryption.encrypt(data, passphrase, method)
    globalThis.removeEventListener(EventTypes.Encryption.encrypt, spy)
    const e = spy.args[0][0] as CustomEvent
    assert.equal(e.detail.passphrase, passphrase)
  })

  test('has the method on the event', async ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Encryption.encrypt, spy)
    await Events.Encryption.encrypt(data, passphrase, method)
    globalThis.removeEventListener(EventTypes.Encryption.encrypt, spy)
    const e = spy.args[0][0] as CustomEvent
    assert.equal(e.detail.method, method)
  })
})

test.group('Events > Encryption > Events.Encryption > decrypt()', () => {
  const data = 'export data'
  const passphrase = 'passphrase data'
  const method = 'aes'

  test('dispatches the event', async ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Encryption.decrypt, spy)
    await Events.Encryption.decrypt(data, passphrase, method)
    globalThis.removeEventListener(EventTypes.Encryption.decrypt, spy)
    assert.isTrue(spy.calledOnce)
  })

  test('has the data on the event', async ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Encryption.decrypt, spy)
    await Events.Encryption.decrypt(data, passphrase, method)
    globalThis.removeEventListener(EventTypes.Encryption.decrypt, spy)
    const e = spy.args[0][0] as CustomEvent
    assert.equal(e.detail.data, data)
  })

  test('has the passphrase on the event', async ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Encryption.decrypt, spy)
    await Events.Encryption.decrypt(data, passphrase, method)
    globalThis.removeEventListener(EventTypes.Encryption.decrypt, spy)
    const e = spy.args[0][0] as CustomEvent
    assert.equal(e.detail.passphrase, passphrase)
  })

  test('has the method on the event', async ({ assert }) => {
    const spy = sinon.spy()
    globalThis.addEventListener(EventTypes.Encryption.decrypt, spy)
    await Events.Encryption.decrypt(data, passphrase, method)
    globalThis.removeEventListener(EventTypes.Encryption.decrypt, spy)
    const e = spy.args[0][0] as CustomEvent
    assert.equal(e.detail.method, method)
  })
})
