import { test } from '@japa/runner'
import { ApiModel, DataDomain, DomainEntity, ListAction } from '../../../../src/modeling/index.js'
import {
  AllowAuthenticatedAccessRule,
  AllowPublicAccessRule,
  MatchEmailDomainAccessRule,
  MatchResourceOwnerAccessRule,
  MatchUserPropertyAccessRule,
  MatchUserRoleAccessRule,
} from '../../../../src/modeling/index.js'
import { nanoid } from '../../../../src/nanoid.js'
import { ExposedEntityKind } from '../../../../src/models/kinds.js'

test.group('restoring 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 rules on the API model', ({ assert }) => {
    const r1 = new AllowAuthenticatedAccessRule()
    const r2 = new AllowPublicAccessRule()
    const r3 = new MatchEmailDomainAccessRule()
    const r4 = new MatchResourceOwnerAccessRule()
    const r5 = new MatchUserPropertyAccessRule()
    const r6 = new MatchUserRoleAccessRule()
    const model = new ApiModel(
      {
        accessRule: [r1.toJSON(), r2.toJSON(), r3.toJSON(), r4.toJSON(), r5.toJSON(), r6.toJSON()],
      },
      domain
    )

    assert.lengthOf(model.accessRule, 6)
    assert.instanceOf(model.accessRule[0], AllowAuthenticatedAccessRule)
    assert.instanceOf(model.accessRule[1], AllowPublicAccessRule)
    assert.instanceOf(model.accessRule[2], MatchEmailDomainAccessRule)
    assert.instanceOf(model.accessRule[3], MatchResourceOwnerAccessRule)
    assert.instanceOf(model.accessRule[4], MatchUserPropertyAccessRule)
    assert.instanceOf(model.accessRule[5], MatchUserRoleAccessRule)
  }).tags(['@modeling', '@rule', '@restoring'])

  test('restores rules on the exposed entity', ({ assert }) => {
    const r1 = new AllowAuthenticatedAccessRule()
    const r2 = new AllowPublicAccessRule()
    const r3 = new MatchEmailDomainAccessRule()
    const r4 = new MatchResourceOwnerAccessRule()
    const r5 = new MatchUserPropertyAccessRule()
    const r6 = new MatchUserRoleAccessRule()
    const model = new ApiModel(
      {
        exposes: [
          {
            kind: ExposedEntityKind,
            key: nanoid(),
            entity: { key: entity.key },
            hasCollection: true,
            collectionPath: '/things',
            resourcePath: '/things/{id}',
            isRoot: true,
            actions: [],
            accessRule: [r1.toJSON(), r2.toJSON(), r3.toJSON(), r4.toJSON(), r5.toJSON(), r6.toJSON()],
          },
        ],
      },
      domain
    )

    const ex = model.exposes[0]!
    assert.lengthOf(ex.accessRule!, 6)
    assert.instanceOf(ex.accessRule![0], AllowAuthenticatedAccessRule)
    assert.instanceOf(ex.accessRule![1], AllowPublicAccessRule)
    assert.instanceOf(ex.accessRule![2], MatchEmailDomainAccessRule)
    assert.instanceOf(ex.accessRule![3], MatchResourceOwnerAccessRule)
    assert.instanceOf(ex.accessRule![4], MatchUserPropertyAccessRule)
    assert.instanceOf(ex.accessRule![5], MatchUserRoleAccessRule)
  }).tags(['@modeling', '@rule', '@restoring'])

  test('restores rules on the action', ({ assert }) => {
    const r1 = new AllowAuthenticatedAccessRule()
    const r2 = new AllowPublicAccessRule()
    const r3 = new MatchEmailDomainAccessRule()
    const r4 = new MatchResourceOwnerAccessRule()
    const r5 = new MatchUserPropertyAccessRule()
    const r6 = new MatchUserRoleAccessRule()
    const action = new ListAction({
      accessRule: [r1.toJSON(), r2.toJSON(), r3.toJSON(), r4.toJSON(), r5.toJSON(), r6.toJSON()],
    }).toJSON()
    const model = new ApiModel(
      {
        exposes: [
          {
            kind: ExposedEntityKind,
            key: nanoid(),
            entity: { key: entity.key },
            hasCollection: true,
            collectionPath: '/things',
            resourcePath: '/things/{id}',
            isRoot: true,
            actions: [action],
          },
        ],
      },
      domain
    )

    const ex = model.exposes[0]!.actions[0]!
    assert.lengthOf(ex.accessRule!, 6)
    assert.instanceOf(ex.accessRule![0], AllowAuthenticatedAccessRule)
    assert.instanceOf(ex.accessRule![1], AllowPublicAccessRule)
    assert.instanceOf(ex.accessRule![2], MatchEmailDomainAccessRule)
    assert.instanceOf(ex.accessRule![3], MatchResourceOwnerAccessRule)
    assert.instanceOf(ex.accessRule![4], MatchUserPropertyAccessRule)
    assert.instanceOf(ex.accessRule![5], MatchUserRoleAccessRule)
  }).tags(['@modeling', '@rule', '@restoring'])
})
