import { test } from '@japa/runner'
import { RateLimitRule } from '../../../../src/modeling/rules/RateLimitRule.js'

test.group('RateLimitRule', () => {
  test('initializes with default values', ({ assert }) => {
    const rule = new RateLimitRule()
    assert.isUndefined(rule.description)
    assert.isUndefined(rule.key)
    assert.isUndefined(rule.rate)
    assert.isUndefined(rule.interval)
    assert.isUndefined(rule.burst)
  }).tags(['@modeling', '@rule', '@rate-limit'])

  test('initializes with provided values', ({ assert }) => {
    const rule = new RateLimitRule({
      description: 'Test Rule',
      key: { type: 'ip' },
      rate: 100,
      interval: 'minute',
      burst: 10,
    })

    assert.equal(rule.description, 'Test Rule')
    assert.deepEqual(rule.key, { type: 'ip' })
    assert.equal(rule.rate, 100)
    assert.equal(rule.interval, 'minute')
    assert.equal(rule.burst, 10)
  }).tags(['@modeling', '@rule', '@rate-limit'])

  test('constructor copies objects (immutability)', ({ assert }) => {
    const key = { type: 'role', value: 'admin' } as const
    const rule = new RateLimitRule({ key })

    // Modify original source
    // @ts-expect-error: modifying readonly property for test
    key.value = 'guest'

    assert.deepEqual(rule.key, { type: 'role', value: 'admin' })
  }).tags(['@modeling', '@rule', '@rate-limit', '@immutability'])

  test('toJSON returns valid schema', ({ assert }) => {
    const rule = new RateLimitRule({
      description: 'Test Rule',
      key: { type: 'userId' },
      rate: 60,
      interval: 'hour',
      burst: 5,
    })

    const json = rule.toJSON()

    assert.equal(json.description, 'Test Rule')
    assert.deepEqual(json.key, { type: 'userId' })
    assert.equal(json.rate, 60)
    assert.equal(json.interval, 'hour')
    assert.equal(json.burst, 5)
  }).tags(['@modeling', '@rule', '@rate-limit', '@serialization'])

  test('notifies change when properties change', async ({ assert }) => {
    const rule = new RateLimitRule()
    let notified = false
    rule.addEventListener('change', () => {
      notified = true
    })

    rule.rate = 50
    await Promise.resolve()
    assert.isTrue(notified)
  }).tags(['@modeling', '@rule', '@rate-limit', '@observed'])
})
