import { test } from '@japa/runner'
import { UpdateAction } from '../../../../src/modeling/actions/UpdateAction.js'

test.group('UpdateAction', () => {
  test('initializes with default values', ({ assert }) => {
    const action = new UpdateAction()
    assert.equal(action.kind, 'update')
    assert.deepEqual(action.allowedMethods, ['PATCH'])
    assert.isEmpty(action.accessRule)
  }).tags(['@modeling', '@action', '@update-action'])

  test('initializes with provided values', ({ assert }) => {
    const methods: ('PUT' | 'PATCH')[] = ['PUT', 'PATCH']
    const action = new UpdateAction({
      allowedMethods: methods,
    })

    assert.equal(action.kind, 'update')
    assert.deepEqual(action.allowedMethods, methods)
  }).tags(['@modeling', '@action', '@update-action'])

  test('constructor copies arrays (immutability)', ({ assert }) => {
    const methods: ('PUT' | 'PATCH')[] = ['PUT']

    const action = new UpdateAction({
      allowedMethods: methods,
    })

    // Modify original source
    methods.push('PATCH')

    assert.deepEqual(action.allowedMethods, ['PUT'])
  }).tags(['@modeling', '@action', '@update-action', '@immutability'])

  test('toJSON returns valid schema', ({ assert }) => {
    const action = new UpdateAction({
      allowedMethods: ['PUT'],
    })

    const json = action.toJSON()

    // Modify JSON
    json.allowedMethods.push('PATCH')

    assert.equal(json.kind, 'update')
    assert.lengthOf(action.allowedMethods, 1) // Ensure immutability
    assert.equal(action.allowedMethods[0], 'PUT')
  }).tags(['@modeling', '@action', '@update-action', '@serialization', '@immutability'])

  test('notifies change when allowedMethods changes', async ({ assert }) => {
    const action = new UpdateAction()
    let notified = false
    action.addEventListener('change', () => {
      notified = true
    })

    action.allowedMethods = ['PUT', 'PATCH']
    await Promise.resolve()
    assert.isTrue(notified)
  }).tags(['@modeling', '@action', '@update-action', '@observed'])

  test('notifies change when allowedMethods value change', async ({ assert }) => {
    const action = new UpdateAction()
    let notified = false
    action.addEventListener('change', () => {
      notified = true
    })

    action.allowedMethods.push('PUT')
    await Promise.resolve()
    assert.isTrue(notified)
  }).tags(['@modeling', '@action', '@update-action', '@observed'])
})
