import { test } from '@japa/runner'
import { DomainValidation } from '../../../src/modeling/DomainValidation.js'
import { DataDomain, DataDomainKind } from '../../../src/index.js'
import { SemanticType } from '../../../src/modeling/Semantics.js'

test.group('DomainImpactAnalysis.validate()', (group) => {
  let domain: DataDomain
  let analysis: DomainValidation

  group.each.setup(() => {
    domain = new DataDomain()
    analysis = new DomainValidation(domain)
  })

  test('validate() should return an empty report when the domain is empty', ({ assert }) => {
    const report = analysis.validate()
    assert.deepEqual(report, {
      key: '',
      kind: DataDomainKind,
      impact: [],
      canProceed: true,
    })
  })

  test('validate() should return validation errors for entities', ({ assert }) => {
    const model = domain.addModel({ key: 'model' })
    model.addEntity({ key: 'entity', info: { name: 'Invalid-Name' } }) // Invalid name

    const report = analysis.validate()
    assert.lengthOf(report.impact, 8)
    // we test specific rules in the validation tests
  })

  test('validate() should return validation errors for properties', ({ assert }) => {
    const model = domain.addModel({ key: 'model' })
    const entity = model.addEntity({ key: 'entity', info: { name: 'entity' } })
    entity.addProperty({ key: 'invalid-property', type: 'string', info: { name: 'invalid-property' } })

    const report = analysis.validate()
    assert.lengthOf(report.impact, 6)
    // we test specific rules in the validation tests
  })

  test('validate() should return validation errors for associations', ({ assert }) => {
    const model = domain.addModel({ key: 'model' })
    const entity1 = model.addEntity({ key: 'entity1', info: { name: 'entity1' } })
    const entity2 = model.addEntity({ key: 'entity2', info: { name: 'entity2' } })
    entity1.addAssociation({ key: entity2.key }, { info: { name: 'Invalid-Name' } })

    const report = analysis.validate()
    assert.lengthOf(report.impact, 12)
    // we test specific rules in the validation tests
  })

  test('validate() should return multiple validation errors', ({ assert }) => {
    const model = domain.addModel({ key: 'model' })
    const entity1 = model.addEntity({ key: 'invalid-entity', info: { name: 'Invalid-Entity' } })
    entity1.addProperty({ key: 'invalid-property', type: 'string', info: { name: 'Invalid-Property' } })
    const entity2 = model.addEntity({ key: 'entity2', info: { name: 'entity2' } })
    entity1.addAssociation({ key: entity2.key }, { info: { name: 'Invalid-Name' } })

    const report = analysis.validate()
    assert.lengthOf(report.impact, 16)
    // we test specific rules in the validation tests
  })

  test('validate() should return no errors for a valid domain', ({ assert }) => {
    const model = domain.addModel({ key: 'model' })
    const entity1 = model.addEntity({ key: 'entity1', info: { name: 'entity1' } })
    entity1.addProperty({ key: 'p1', type: 'string', info: { name: 'property1' } })
    entity1.addProperty({ key: 'p2', type: 'string', primary: true, info: { name: 'property2' } })
    const entity2 = model.addEntity({ key: 'entity2', info: { name: 'entity2' } })
    const p3e2 = entity2.addProperty({ key: 'p3', type: 'datetime', info: { name: 'property3' } })
    entity2.addProperty({ key: 'p4', type: 'string', primary: true, info: { name: 'property4' } })
    const p5e2 = entity2.addProperty({ key: 'p5', type: 'datetime', info: { name: 'property5' } })
    const p6e2 = entity2.addProperty({ key: 'p6', type: 'datetime', info: { name: 'property6' } })
    entity1.addAssociation({ key: entity2.key }, { info: { name: 'name' } })
    const p3e1 = entity1.addProperty({ type: 'datetime', info: { name: 'p3e1' } })
    const p4e1 = entity1.addProperty({ type: 'datetime', info: { name: 'p4e1' } })
    const p5e1 = entity1.addProperty({ type: 'boolean', info: { name: 'p5e1' } })

    entity1.addSemantic({ id: SemanticType.User })
    p3e2.addSemantic({ id: SemanticType.CreatedTimestamp })
    p5e2.addSemantic({ id: SemanticType.UpdatedTimestamp })
    p6e2.addSemantic({ id: SemanticType.DeletedTimestamp })
    p3e1.addSemantic({ id: SemanticType.CreatedTimestamp })
    p4e1.addSemantic({ id: SemanticType.UpdatedTimestamp })
    p5e1.addSemantic({ id: SemanticType.DeletedFlag })

    const report = analysis.validate()
    assert.lengthOf(report.impact, 0)
    assert.equal(report.canProceed, true)
  })
})
