import { test } from '@japa/runner'
import { DataDomain } from '../../../src/modeling/DataDomain.js'
import { DomainModel } from '../../../src/modeling/DomainModel.js'

test.group('DataDomain.addModel()', () => {
  test('addModel adds a model to the graph', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    assert.instanceOf(model, DomainModel)
    assert.isTrue(dataDomain.graph.hasNode(model.key))
  }).tags(['@modeling', '@model', '@add'])

  test('addModel adds a model to the graph with a parent', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace.key)
    assert.instanceOf(model, DomainModel)
    assert.isTrue(dataDomain.graph.hasNode(model.key))
    assert.equal(dataDomain.graph.parent(model.key), parentNamespace.key)
  }).tags(['@modeling', '@model', '@add'])

  test('addModel throws an error if parent namespace does not exist', ({ assert }) => {
    const dataDomain = new DataDomain()
    assert.throws(() => {
      dataDomain.addModel({ key: 'test-model' }, 'non-existent-parent')
    }, 'Parent non-existent-parent does not exist')
  }).tags(['@modeling', '@model', '@add'])

  test('addModel adds a model with default values', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel()
    assert.instanceOf(model, DomainModel)
    assert.isTrue(dataDomain.graph.hasNode(model.key))
    assert.isUndefined(dataDomain.graph.parent(model.key))
  }).tags(['@modeling', '@model', '@add'])

  test('addModel adds a model to a parent namespace', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace.key)
    assert.instanceOf(model, DomainModel)
    assert.isTrue(dataDomain.graph.hasNode(model.key))
    assert.equal(dataDomain.graph.parent(model.key), parentNamespace.key)
  }).tags(['@modeling', '@model', '@add'])

  test('addModel notifies change', async ({ assert }) => {
    const dataDomain = new DataDomain()
    dataDomain.addModel({ key: 'test-model' })
    await assert.dispatches(dataDomain, 'change', { timeout: 20 })
  }).tags(['@modeling', '@model', '@add'])

  test('addModel adds a model to the root of the graph', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    assert.instanceOf(model, DomainModel)
    assert.isTrue(dataDomain.graph.hasNode(model.key))
    assert.isUndefined(dataDomain.graph.parent(model.key))
  }).tags(['@modeling', '@model', '@add'])

  test('addModel adds a model to a parent namespace - checks parent-child relationship', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace.key)
    assert.isTrue(dataDomain.graph.hasParent(model.key, parentNamespace.key))
  }).tags(['@modeling', '@model', '@add'])

  test('addModel adds a model to the root of the graph - checks parent-child relationship', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    assert.isFalse(dataDomain.graph.hasParent(model.key, dataDomain.key))
  }).tags(['@modeling', '@model', '@add'])

  test('addModel adds a model to a parent namespace - checks items list', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace.key)
    const parentNs = dataDomain.findNamespace(parentNamespace.key)
    assert.deepInclude([...parentNs!.listModels()], model)
  }).tags(['@modeling', '@model', '@add'])

  test('addModel adds a model to the root of the graph - checks items list', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    assert.deepInclude([...dataDomain.listGraphModels()], model)
  }).tags(['@modeling', '@model', '@add'])

  test('addModel throws an error if parent is not a namespace', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    assert.throws(() => {
      dataDomain.addModel({ key: 'child-model' }, model.key)
    }, `Parent namespace ${model.key} is not a valid namespace`)
  }).tags(['@modeling', '@model', '@add'])

  test('addModel adds to the fields list', ({ assert }) => {
    const root = new DataDomain()
    const m1 = root.addModel({})
    assert.lengthOf(root.fields, 1)
    const [field] = root.fields
    assert.equal(field.key, m1.key)
    assert.equal(field.type, 'model')
  }).tags(['@modeling', '@model', '@add'])
})

test.group('DataDomain.removeModel()', () => {
  test('removeModel removes a model from the graph', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    dataDomain.removeModel(model.key)
    assert.isFalse(dataDomain.graph.hasNode(model.key))
  }).tags(['@modeling', '@model', '@remove'])

  test('removeModel throws an error if model does not exist', ({ assert }) => {
    const dataDomain = new DataDomain()
    assert.throws(() => {
      dataDomain.removeModel('non-existent-model')
    }, 'Data model non-existent-model does not exist')
  }).tags(['@modeling', '@model', '@remove'])

  test('removeModel notifies change', async ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    dataDomain.removeModel(model.key)
    await assert.dispatches(dataDomain, 'change', { timeout: 20 })
  }).tags(['@modeling', '@model', '@remove'])

  test('removeModel removes a model from the root of the graph', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    dataDomain.removeModel(model.key)
    assert.isFalse(dataDomain.graph.hasNode(model.key))
    assert.isUndefined(dataDomain.graph.parent(model.key))
  }).tags(['@modeling', '@model', '@remove'])

  test('removeModel removes a model from a parent namespace', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace.key)
    dataDomain.removeModel(model.key)
    assert.isFalse(dataDomain.graph.hasNode(model.key))
    assert.equal(dataDomain.graph.parent(model.key), undefined)
  }).tags(['@modeling', '@model', '@remove'])

  test('removeModel removes a model with entities', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    const entity = dataDomain.addEntity(model.key, { key: 'test-entity' })
    dataDomain.removeModel(model.key)
    assert.isFalse(dataDomain.graph.hasNode(model.key))
    assert.isFalse(dataDomain.graph.hasNode(entity.key))
  }).tags(['@modeling', '@model', '@remove'])

  test('removeModel removes a model from a parent namespace - checks parent-child relationship', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace.key)
    dataDomain.removeModel(model.key)
    assert.isFalse(dataDomain.graph.hasParent(model.key, parentNamespace.key))
  }).tags(['@modeling', '@model', '@remove'])

  test('removeModel removes a model from the root of the graph - checks parent-child relationship', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    dataDomain.removeModel(model.key)
    assert.isFalse(dataDomain.graph.hasParent(model.key, dataDomain.key))
  }).tags(['@modeling', '@model', '@remove'])

  test('removeModel removes a model from a parent namespace - checks items list', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace.key)
    dataDomain.removeModel(model.key)
    const parentNs = dataDomain.findNamespace(parentNamespace.key)
    assert.notDeepInclude([...parentNs!.listModels()], model)
  }).tags(['@modeling', '@model', '@remove'])

  test('removeModel removes a model from the root of the graph - checks items list', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    dataDomain.removeModel(model.key)
    assert.notDeepInclude([...dataDomain.listGraphModels()], model)
  }).tags(['@modeling', '@model', '@remove'])

  test('removeModel throws an error if key is not a model', ({ assert }) => {
    const dataDomain = new DataDomain()
    const namespace = dataDomain.addNamespace({ key: 'test-ns' })
    assert.throws(() => {
      dataDomain.removeModel(namespace.key)
    }, `Data model ${namespace.key} not found`)
  }).tags(['@modeling', '@model', '@remove'])

  test('removeModel removes from fields', ({ assert }) => {
    const root = new DataDomain()
    const m1 = root.addModel()
    root.removeModel(m1.key)
    assert.deepEqual(root.fields, [])
  }).tags(['@modeling', '@model', '@remove'])
})

test.group('DataDomain.listModels()', () => {
  test('lists all models in the data domain', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model1 = dataDomain.addModel()
    const model2 = dataDomain.addModel()
    const models = [...dataDomain.listModels()]
    assert.lengthOf(models, 2)
    assert.deepInclude(models, model1)
    assert.deepInclude(models, model2)
  }).tags(['@modeling', '@model', '@list'])

  test('returns an empty array if there are no models', ({ assert }) => {
    const dataDomain = new DataDomain()
    const models = [...dataDomain.listModels()]
    assert.lengthOf(models, 0)
  }).tags(['@modeling', '@model', '@list'])

  test('returns only models', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model1 = dataDomain.addModel()
    dataDomain.addNamespace()
    const models = [...dataDomain.listModels()]
    assert.lengthOf(models, 1)
    assert.deepInclude(models, model1)
  }).tags(['@modeling', '@model', '@list'])

  test('models in the list are of type DomainModel', ({ assert }) => {
    const dataDomain = new DataDomain()
    dataDomain.addModel()
    const models = [...dataDomain.listModels()]
    assert.instanceOf(models[0], DomainModel)
  }).tags(['@modeling', '@model', '@list'])

  test('lists models in the order they were added', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model1 = dataDomain.addModel()
    const model2 = dataDomain.addModel()
    const models = [...dataDomain.listModels()]
    assert.deepEqual(models, [model1, model2])
  }).tags(['@modeling', '@model', '@list'])

  test('lists models when there are no models', ({ assert }) => {
    const dataDomain = new DataDomain()
    const models = [...dataDomain.listModels()]
    assert.deepEqual(models, [])
  }).tags(['@modeling', '@model', '@list'])

  test('lists models when there are other domain elements', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model1 = dataDomain.addModel()
    dataDomain.addNamespace()
    const models = [...dataDomain.listModels()]
    assert.deepEqual(models, [model1])
  }).tags(['@modeling', '@model', '@list'])
})

test.group('DataDomain.hasModels()', () => {
  test('returns true if there are child models', ({ assert }) => {
    const dataDomain = new DataDomain()
    dataDomain.addModel()
    assert.isTrue(dataDomain.hasModels())
  }).tags(['@modeling', '@model', '@has'])

  test('returns false if there are no child models', ({ assert }) => {
    const dataDomain = new DataDomain()
    assert.isFalse(dataDomain.hasModels())
  }).tags(['@modeling', '@model', '@has'])

  test('returns false if there are only namespaces', ({ assert }) => {
    const dataDomain = new DataDomain()
    dataDomain.addNamespace()
    assert.isFalse(dataDomain.hasModels())
  }).tags(['@modeling', '@model', '@has'])

  test('returns true if there are both models and namespaces', ({ assert }) => {
    const dataDomain = new DataDomain()
    dataDomain.addModel()
    dataDomain.addNamespace()
    assert.isTrue(dataDomain.hasModels())
  }).tags(['@modeling', '@model', '@has'])

  test('returns false if the data domain has no fields', ({ assert }) => {
    const dataDomain = new DataDomain()
    dataDomain.fields = []
    assert.isFalse(dataDomain.hasModels())
  }).tags(['@modeling', '@model', '@has'])
})

test.group('DataDomain.listGraphModels()', () => {
  test('lists all models in the graph', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model1 = dataDomain.addModel({ key: 'model1' })
    const model2 = dataDomain.addModel({ key: 'model2' })
    const models = [...dataDomain.listGraphModels()]
    assert.lengthOf(models, 2)
    assert.deepInclude(models, model1)
    assert.deepInclude(models, model2)
  }).tags(['@modeling', '@model', '@list'])

  test('lists all models in the graph with a parent', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    const model1 = dataDomain.addModel({ key: 'model1' }, parentNamespace.key)
    dataDomain.addModel({ key: 'model2' })
    const models = [...dataDomain.listGraphModels(parentNamespace.key)]
    assert.lengthOf(models, 1)
    assert.deepInclude(models, model1)
  }).tags(['@modeling', '@model', '@list'])

  test('returns an empty array if there are no models', ({ assert }) => {
    const dataDomain = new DataDomain()
    const models = [...dataDomain.listGraphModels()]
    assert.lengthOf(models, 0)
  }).tags(['@modeling', '@model', '@list'])

  test('returns an empty array if the parent does not exist', ({ assert }) => {
    const dataDomain = new DataDomain()
    const models = [...dataDomain.listGraphModels('non-existent-parent')]
    assert.lengthOf(models, 0)
  }).tags(['@modeling', '@model', '@list'])

  test('returns only models', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model1 = dataDomain.addModel({ key: 'model1' })
    dataDomain.addNamespace({ key: 'ns1' })
    const models = [...dataDomain.listGraphModels()]
    assert.lengthOf(models, 1)
    assert.deepInclude(models, model1)
  }).tags(['@modeling', '@model', '@list'])

  test('returns only models for the given parent', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    const model1 = dataDomain.addModel({ key: 'model1' }, parentNamespace.key)
    dataDomain.addModel({ key: 'model2' })
    dataDomain.addNamespace({ key: 'ns1' }, parentNamespace.key)
    dataDomain.addNamespace({ key: 'ns2' })
    const models = [...dataDomain.listGraphModels(parentNamespace.key)]
    assert.lengthOf(models, 1)
    assert.deepInclude(models, model1)
  }).tags(['@modeling', '@model', '@list'])

  test('models in the list are of type DomainModel', ({ assert }) => {
    const dataDomain = new DataDomain()
    dataDomain.addModel({ key: 'model1' })
    const models = [...dataDomain.listGraphModels()]
    assert.instanceOf(models[0], DomainModel)
  }).tags(['@modeling', '@model', '@list'])

  test('lists models from the root when no parent is provided', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model1 = dataDomain.addModel({ key: 'model1' })
    const model2 = dataDomain.addModel({ key: 'model2' })
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    dataDomain.addModel({ key: 'model3' }, parentNamespace.key)

    const models = [...dataDomain.listGraphModels()]
    assert.lengthOf(models, 2)
    assert.deepInclude(models, model1)
    assert.deepInclude(models, model2)
  }).tags(['@modeling', '@model', '@list'])

  test('lists models from a parent namespace', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    const model1 = dataDomain.addModel({ key: 'model1' }, parentNamespace.key)
    dataDomain.addModel({ key: 'model2' })

    const models = [...dataDomain.listGraphModels(parentNamespace.key)]
    assert.lengthOf(models, 1)
    assert.deepInclude(models, model1)
  }).tags(['@modeling', '@model', '@list'])

  test('lists models from a parent namespace and the parent has no models', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })

    const models = [...dataDomain.listGraphModels(parentNamespace.key)]
    assert.lengthOf(models, 0)
  }).tags(['@modeling', '@model', '@list'])

  test('lists models from a parent namespace and the parent is not a namespace', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'model-1' })

    const models = [...dataDomain.listGraphModels(model.key)]
    assert.lengthOf(models, 0)
  }).tags(['@modeling', '@model', '@list'])

  test('lists models from a parent namespace and the parent is not in the graph', ({ assert }) => {
    const dataDomain = new DataDomain()

    const models = [...dataDomain.listGraphModels('non-existent-parent')]
    assert.lengthOf(models, 0)
  }).tags(['@modeling', '@model', '@list'])

  test('lists all children for the root, excluding foreign models', ({ assert }) => {
    const domain1 = new DataDomain()
    const m1 = domain1.addModel({ key: 'model1' })

    const domain2 = new DataDomain()
    domain2.addModel({ key: 'model2' })
    domain2.info.version = '1.0.0'
    domain1.registerForeignDomain(domain2)

    const children = [...domain1.listGraphModels()]
    assert.lengthOf(children, 1)
    assert.deepInclude(children, m1)
  }).tags(['@modeling', '@model', '@list'])

  test('lists all children for a namespace, excluding foreign models', ({ assert }) => {
    const domain1 = new DataDomain()
    const ns1 = domain1.addNamespace({ key: 'ns1' })
    const m1 = domain1.addModel({ key: 'model1' }, ns1.key)
    const domain2 = new DataDomain()
    domain2.addModel({ key: 'model2' })
    domain2.info.version = '1.0.0'
    domain1.registerForeignDomain(domain2)
    const children = [...domain1.listGraphModels(ns1.key)]
    assert.lengthOf(children, 1)
    assert.deepInclude(children, m1)
  }).tags(['@modeling', '@model', '@list'])
})

test.group('DataDomain.findModel()', () => {
  test('finds a model by its key', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    const foundModel = dataDomain.findModel('test-model')
    assert.deepEqual(foundModel, model)
  }).tags(['@modeling', '@model', '@find'])

  test('returns undefined if model does not exist', ({ assert }) => {
    const dataDomain = new DataDomain()
    const foundModel = dataDomain.findModel('non-existent-model')
    assert.isUndefined(foundModel)
  }).tags(['@modeling', '@model', '@find'])

  test('returns undefined if key is not a model', ({ assert }) => {
    const dataDomain = new DataDomain()
    const namespace = dataDomain.addNamespace({ key: 'test-ns' })
    const foundModel = dataDomain.findModel(namespace.key)
    assert.isUndefined(foundModel)
  }).tags(['@modeling', '@model', '@find'])

  test('returns undefined if key is undefined', ({ assert }) => {
    const dataDomain = new DataDomain()
    // @ts-expect-error For testing purposes
    const foundModel = dataDomain.findModel(undefined)
    assert.isUndefined(foundModel)
  }).tags(['@modeling', '@model', '@find'])

  test('returns undefined if key is null', ({ assert }) => {
    const dataDomain = new DataDomain()
    // @ts-expect-error For testing purposes
    const foundModel = dataDomain.findModel(null)
    assert.isUndefined(foundModel)
  }).tags(['@modeling', '@model', '@find'])

  test('returns undefined if key is an empty string', ({ assert }) => {
    const dataDomain = new DataDomain()
    const foundModel = dataDomain.findModel('')
    assert.isUndefined(foundModel)
  }).tags(['@modeling', '@model', '@find'])

  test('returns undefined if key is a number', ({ assert }) => {
    const dataDomain = new DataDomain()
    // @ts-expect-error For testing purposes
    const foundModel = dataDomain.findModel(123)
    assert.isUndefined(foundModel)
  }).tags(['@modeling', '@model', '@find'])

  test('returns undefined if key is a boolean', ({ assert }) => {
    const dataDomain = new DataDomain()
    // @ts-expect-error For testing purposes
    const foundModel = dataDomain.findModel(true)
    assert.isUndefined(foundModel)
  }).tags(['@modeling', '@model', '@find'])

  test('returns undefined if key is an object', ({ assert }) => {
    const dataDomain = new DataDomain()
    // @ts-expect-error For testing purposes
    const foundModel = dataDomain.findModel({})
    assert.isUndefined(foundModel)
  }).tags(['@modeling', '@model', '@find'])

  test('returns undefined if key is an array', ({ assert }) => {
    const dataDomain = new DataDomain()
    // @ts-expect-error For testing purposes
    const foundModel = dataDomain.findModel([])
    assert.isUndefined(foundModel)
  }).tags(['@modeling', '@model', '@find'])

  test('returns undefined if key is a function', ({ assert }) => {
    const dataDomain = new DataDomain()
    // @ts-expect-error For testing purposes
    const foundModel = dataDomain.findModel(() => {})
    assert.isUndefined(foundModel)
  }).tags(['@modeling', '@model', '@find'])
})

test.group('DataDomain.moveModel()', () => {
  test('moves a model from the root to a parent namespace', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    dataDomain.moveModel(model.key, parentNamespace.key)
    assert.equal(dataDomain.graph.parent(model.key), parentNamespace.key)
  }).tags(['@modeling', '@model', '@move'])

  test('moves a model from a parent namespace to the root', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace.key)
    dataDomain.moveModel(model.key)
    assert.equal(dataDomain.graph.parent(model.key), undefined)
  }).tags(['@modeling', '@model', '@move'])

  test('moves a model from one parent namespace to another', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace1 = dataDomain.addNamespace({ key: 'parent-ns1' })
    const parentNamespace2 = dataDomain.addNamespace({ key: 'parent-ns2' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace1.key)
    dataDomain.moveModel(model.key, parentNamespace2.key)
    assert.equal(dataDomain.graph.parent(model.key), parentNamespace2.key)
  }).tags(['@modeling', '@model', '@move'])

  test('throws an error if model does not exist', ({ assert }) => {
    const dataDomain = new DataDomain()
    assert.throws(() => {
      dataDomain.moveModel('non-existent-model', 'parent-ns')
    }, 'Data model non-existent-model does not exist')
  }).tags(['@modeling', '@model', '@move'])

  test('throws an error if parent namespace does not exist', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    assert.throws(() => {
      dataDomain.moveModel(model.key, 'non-existent-parent')
    }, 'Parent namespace non-existent-parent does not exist')
  }).tags(['@modeling', '@model', '@move'])

  test('throws an error if model is moved to itself', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    assert.throws(() => {
      dataDomain.moveModel(model.key, model.key)
    }, 'Parent namespace test-model does not exist')
  }).tags(['@modeling', '@model', '@move'])

  test('moveModel notifies change', async ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    dataDomain.moveModel(model.key, parentNamespace.key)
    await assert.dispatches(dataDomain, 'change', { timeout: 20 })
  }).tags(['@modeling', '@model', '@move'])

  test('moves a model from the root to a parent namespace - checks parent-child relationship', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    dataDomain.moveModel(model.key, parentNamespace.key)
    assert.isTrue(dataDomain.graph.hasParent(model.key, parentNamespace.key))
  }).tags(['@modeling', '@model', '@move'])

  test('moves a model from a parent namespace to the root - checks parent-child relationship', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace.key)
    dataDomain.moveModel(model.key)
    assert.isFalse(dataDomain.graph.hasParent(model.key, parentNamespace.key))
  }).tags(['@modeling', '@model', '@move'])

  test('moves a model from one parent namespace to another - checks parent-child relationship', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace1 = dataDomain.addNamespace({ key: 'parent-ns1' })
    const parentNamespace2 = dataDomain.addNamespace({ key: 'parent-ns2' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace1.key)
    dataDomain.moveModel(model.key, parentNamespace2.key)
    assert.isFalse(dataDomain.graph.hasParent(model.key, parentNamespace1.key))
    assert.isTrue(dataDomain.graph.hasParent(model.key, parentNamespace2.key))
  }).tags(['@modeling', '@model', '@move'])

  test('moves a model from the root to a parent namespace - checks items list', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    dataDomain.moveModel(model.key, parentNamespace.key)
    const parentNs = dataDomain.findNamespace(parentNamespace.key)
    assert.deepInclude([...parentNs!.listModels()], model)
  }).tags(['@modeling', '@model', '@move'])

  test('moves a model from a parent namespace to the root - checks items list', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace.key)
    dataDomain.moveModel(model.key)
    assert.deepInclude([...dataDomain.listGraphModels()], model)
  }).tags(['@modeling', '@model', '@move'])

  test('moves a model from one parent namespace to another - checks items list', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace1 = dataDomain.addNamespace({ key: 'parent-ns1' })
    const parentNamespace2 = dataDomain.addNamespace({ key: 'parent-ns2' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace1.key)
    dataDomain.moveModel(model.key, parentNamespace2.key)
    const parentNs1 = dataDomain.findNamespace(parentNamespace1.key)
    const parentNs2 = dataDomain.findNamespace(parentNamespace2.key)
    assert.notDeepInclude([...parentNs1!.listModels()], model)
    assert.deepInclude([...parentNs2!.listModels()], model)
  }).tags(['@modeling', '@model', '@move'])

  test('throws an error if the target is not a namespace', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model1 = dataDomain.addModel({ key: 'test-model' })
    const model2 = dataDomain.addModel({ key: 'other-model' })
    assert.throws(() => {
      dataDomain.moveModel(model1.key, model2.key)
    }, 'Parent namespace other-model does not exist')
  }).tags(['@modeling', '@model', '@move'])

  test('moves a model from the root to a parent namespace - updates fields array', ({ assert }) => {
    const dataDomain = new DataDomain()
    const model = dataDomain.addModel({ key: 'test-model' })
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    dataDomain.moveModel(model.key, parentNamespace.key)
    assert.notDeepInclude(dataDomain.fields, { key: model.key, type: 'model' })
  }).tags(['@modeling', '@model', '@move'])

  test('moves a model from a parent namespace to the root - updates fields array', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace = dataDomain.addNamespace({ key: 'parent-ns' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace.key)
    dataDomain.moveModel(model.key)
    assert.deepInclude(dataDomain.fields, { key: model.key, type: 'model' })
  }).tags(['@modeling', '@model', '@move'])

  test('moves a model from one parent namespace to another - updates fields array', ({ assert }) => {
    const dataDomain = new DataDomain()
    const parentNamespace1 = dataDomain.addNamespace({ key: 'parent-ns1' })
    const parentNamespace2 = dataDomain.addNamespace({ key: 'parent-ns2' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace1.key)
    dataDomain.moveModel(model.key, parentNamespace2.key)
    assert.notDeepInclude(dataDomain.fields, { key: model.key, type: 'model' })
  }).tags(['@modeling', '@model', '@move'])

  test('moves a model from one parent namespace to another - updates fields array when moving to root', ({
    assert,
  }) => {
    const dataDomain = new DataDomain()
    const parentNamespace1 = dataDomain.addNamespace({ key: 'parent-ns1' })
    const model = dataDomain.addModel({ key: 'test-model' }, parentNamespace1.key)
    dataDomain.moveModel(model.key)
    assert.deepInclude(dataDomain.fields, { key: model.key, type: 'model' })
  }).tags(['@modeling', '@model', '@move'])
})
