import { test } from '@japa/runner'
import { DataDomain } from '../../../../src/modeling/DataDomain.js'
import { SemanticValidation } from '../../../../src/modeling/validation/semantic_validation.js'
import { SemanticType } from '../../../../src/modeling/Semantics.js'

test.group('SemanticValidation', (group) => {
  let domain: DataDomain
  let validation: SemanticValidation

  group.each.setup(() => {
    domain = new DataDomain()
    validation = new SemanticValidation(domain)
  })

  test('validate() should return a warning when no User entity is found', ({ assert }) => {
    const model = domain.addModel({ key: 'model' })
    model.addEntity({ key: 'entity', info: { name: 'Entity' } })
    const results = validation.validate()
    assert.lengthOf(results, 4) // Warning for User + 2 info for timestamps + info for soft delete
    assert.equal(results[0].rule, 'recommended')
    assert.equal(results[0].severity, 'warning')
    assert.equal(results[0].message, 'No entity with User taxonomy found in the domain.')
  })

  test('validate() should not return a warning when a User entity is found', ({ assert }) => {
    const model = domain.addModel({ key: 'model' })
    const entity = model.addEntity({ key: 'user', info: { name: 'User' } })
    entity.addSemantic({ id: SemanticType.User })
    const results = validation.validate()
    assert.lengthOf(results, 3) // Only info for timestamps (2) and soft delete
    assert.notEqual(results[0].message, 'No entity with User taxonomy found in the domain.')
  })

  test('validate() should return info when an entity has no timestamp taxonomy', ({ assert }) => {
    const model = domain.addModel({ key: 'model' })
    model.addEntity({ key: 'entity', info: { name: 'Entity' } })
    const results = validation.validate()
    assert.lengthOf(results, 4)
    const timestampResults = results.filter(
      (r) => r.message.includes('CreatedTimestamp') || r.message.includes('UpdatedTimestamp')
    )
    assert.lengthOf(timestampResults, 2)
    assert.equal(timestampResults[0].severity, 'info')
    assert.equal(timestampResults[1].severity, 'info')
  })

  test('validate() should not return info when an entity has timestamp taxonomy', ({ assert }) => {
    const model = domain.addModel({ key: 'model' })
    const entity = model.addEntity({ key: 'entity', info: { name: 'Entity' } })
    const createdProperty = entity.addProperty({
      key: 'created_at',
      type: 'datetime',
      info: { name: 'created_at' },
    })
    const updatedProperty = entity.addProperty({
      key: 'updated_at',
      type: 'datetime',
      info: { name: 'updated_at' },
    })
    createdProperty.addSemantic({ id: SemanticType.CreatedTimestamp })
    updatedProperty.addSemantic({ id: SemanticType.UpdatedTimestamp })
    const results = validation.validate()
    const timestampResults = results.filter(
      (r) => r.message.includes('CreatedTimestamp') || r.message.includes('UpdatedTimestamp')
    )
    assert.lengthOf(timestampResults, 0)
  })

  test('validate() should return info when an entity has no soft delete taxonomy', ({ assert }) => {
    const model = domain.addModel({ key: 'model' })
    model.addEntity({ key: 'entity', info: { name: 'Entity' } })
    const results = validation.validate()
    const softDeleteResults = results.filter((r) => r.message.includes('soft delete taxonomy'))
    assert.lengthOf(softDeleteResults, 1)
    assert.equal(softDeleteResults[0].severity, 'info')
  })

  test('validate() should not return info when an entity has soft delete taxonomy', ({ assert }) => {
    const model = domain.addModel({ key: 'model' })
    const entity = model.addEntity({ key: 'entity', info: { name: 'Entity' } })
    const deletedProperty = entity.addProperty({
      key: 'deleted_at',
      type: 'datetime',
      info: { name: 'deleted_at' },
    })
    deletedProperty.addSemantic({ id: SemanticType.DeletedTimestamp })
    const results = validation.validate()
    const softDeleteResults = results.filter((r) => r.message.includes('soft delete taxonomy'))
    assert.lengthOf(softDeleteResults, 0)
  })
})
