import { test } from '@japa/runner'
import {
  ApiModel,
  CreateAction,
  DataDomain,
  DeleteAction,
  DomainEntity,
  ListAction,
  ReadAction,
  SearchAction,
  UpdateAction,
} from '../../../src/modeling/index.js'
import { ExposedEntityKind } from '../../../src/models/kinds.js'
import { nanoid } from '../../../src/nanoid.js'

test.group('ExposedEntity::actions', (group) => {
  let domain: DataDomain
  let entity: DomainEntity

  group.each.setup(() => {
    domain = new DataDomain()
    const m1 = domain.addModel()
    entity = m1.addEntity()
    domain.info.version = '1.0.0'
  })

  test('restores a list acton', ({ assert }) => {
    const action = new ListAction()
    const model = new ApiModel(
      {
        exposes: [
          {
            kind: ExposedEntityKind,
            key: nanoid(),
            entity: { key: entity.key },
            hasCollection: true,
            collectionPath: '/things',
            resourcePath: '/things/{id}',
            isRoot: true,
            actions: [action.toJSON()],
          },
        ],
      },
      domain
    )

    const restoredAction = model.exposes[0].actions[0]
    assert.ok(restoredAction, 'Action should be restored')
    assert.equal(restoredAction.kind, 'list', 'Action kind should be list')
    assert.instanceOf(restoredAction, ListAction, 'Action should be an instance of ListAction')
  }).tags(['@modeling', '@action', '@restoring'])

  test('restores a create acton', ({ assert }) => {
    const action = new CreateAction()
    const model = new ApiModel(
      {
        exposes: [
          {
            kind: ExposedEntityKind,
            key: nanoid(),
            entity: { key: entity.key },
            hasCollection: true,
            collectionPath: '/things',
            resourcePath: '/things/{id}',
            isRoot: true,
            actions: [action.toJSON()],
          },
        ],
      },
      domain
    )

    const restoredAction = model.exposes[0].actions[0]
    assert.ok(restoredAction, 'Action should be restored')
    assert.equal(restoredAction.kind, 'create', 'Action kind should be create')
    assert.instanceOf(restoredAction, CreateAction, 'Action should be an instance of CreateAction')
  }).tags(['@modeling', '@action', '@restoring'])

  test('restores a read acton', ({ assert }) => {
    const action = new ReadAction()
    const model = new ApiModel(
      {
        exposes: [
          {
            kind: ExposedEntityKind,
            key: nanoid(),
            entity: { key: entity.key },
            hasCollection: true,
            collectionPath: '/things',
            resourcePath: '/things/{id}',
            isRoot: true,
            actions: [action.toJSON()],
          },
        ],
      },
      domain
    )

    const restoredAction = model.exposes[0].actions[0]
    assert.ok(restoredAction, 'Action should be restored')
    assert.equal(restoredAction.kind, 'read', 'Action kind should be read')
    assert.instanceOf(restoredAction, ReadAction, 'Action should be an instance of ReadAction')
  }).tags(['@modeling', '@action', '@restoring'])

  test('restores a update acton', ({ assert }) => {
    const action = new UpdateAction()
    const model = new ApiModel(
      {
        exposes: [
          {
            kind: ExposedEntityKind,
            key: nanoid(),
            entity: { key: entity.key },
            hasCollection: true,
            collectionPath: '/things',
            resourcePath: '/things/{id}',
            isRoot: true,
            actions: [action.toJSON()],
          },
        ],
      },
      domain
    )

    const restoredAction = model.exposes[0].actions[0]
    assert.ok(restoredAction, 'Action should be restored')
    assert.equal(restoredAction.kind, 'update', 'Action kind should be update')
    assert.instanceOf(restoredAction, UpdateAction, 'Action should be an instance of UpdateAction')
  }).tags(['@modeling', '@action', '@restoring'])

  test('restores a delete acton', ({ assert }) => {
    const action = new DeleteAction()
    const model = new ApiModel(
      {
        exposes: [
          {
            kind: ExposedEntityKind,
            key: nanoid(),
            entity: { key: entity.key },
            hasCollection: true,
            collectionPath: '/things',
            resourcePath: '/things/{id}',
            isRoot: true,
            actions: [action.toJSON()],
          },
        ],
      },
      domain
    )

    const restoredAction = model.exposes[0].actions[0]
    assert.ok(restoredAction, 'Action should be restored')
    assert.equal(restoredAction.kind, 'delete', 'Action kind should be delete')
    assert.instanceOf(restoredAction, DeleteAction, 'Action should be an instance of DeleteAction')
  }).tags(['@modeling', '@action', '@restoring'])

  test('restores a search acton', ({ assert }) => {
    const action = new SearchAction()
    const model = new ApiModel(
      {
        exposes: [
          {
            kind: ExposedEntityKind,
            key: nanoid(),
            entity: { key: entity.key },
            hasCollection: true,
            collectionPath: '/things',
            resourcePath: '/things/{id}',
            isRoot: true,
            actions: [action.toJSON()],
          },
        ],
      },
      domain
    )

    const restoredAction = model.exposes[0].actions[0]
    assert.ok(restoredAction, 'Action should be restored')
    assert.equal(restoredAction.kind, 'search', 'Action kind should be search')
    assert.instanceOf(restoredAction, SearchAction, 'Action should be an instance of SearchAction')
  }).tags(['@modeling', '@action', '@restoring'])
})
