import { test } from '@japa/runner'
import { DOMParser } from '@xmldom/xmldom'
import { ApiSchemaGenerator } from '../../../src/amf/ApiSchemaGenerator.js'
import { AmfLoader } from './AmfLoader.js'
import { IAmfDocument } from '../../../src/amf/definitions/Amf.js'

const loader = new AmfLoader()
const jsonMime = 'application/json'
const xmlMime = 'application/xml'

test.group(`OAS union types / ${jsonMime}`, (group) => {
  let model: IAmfDocument

  group.setup(async () => {
    model = await loader.getGraph('oas-unions')
  })
  test('generates schema for a oneOf union', async ({ assert }) => {
    const shape = loader.getShape(model, 'OneOfSchema')
    const result = ApiSchemaGenerator.asSchema(shape, jsonMime, {
      renderOptional: true,
      renderExamples: true,
      renderMocked: true,
    }) as string
    assert.typeOf(result, 'string', 'is a string')
    const value = JSON.parse(result)
    assert.typeOf(value.hunts, 'boolean')
    assert.typeOf(value.age, 'number')
  })

  test('generates schema for a allOf union', async ({ assert }) => {
    const shape = loader.getShape(model, 'AllOfSchema')
    const result = ApiSchemaGenerator.asSchema(shape, jsonMime, {
      renderOptional: true,
      renderExamples: true,
      renderMocked: true,
    }) as string

    assert.typeOf(result, 'string', 'is a string')
    const value = JSON.parse(result)
    assert.typeOf(value.hunts, 'boolean')
    assert.typeOf(value.bark, 'boolean')
    assert.typeOf(value.age, 'number')
    assert.equal(value.breed, 'Dingo', 'has the example value')
  })

  test('generates schema for a anyOf union', async ({ assert }) => {
    const shape = loader.getShape(model, 'AnyOfSchema')
    const result = ApiSchemaGenerator.asSchema(shape, jsonMime, {
      renderOptional: true,
      renderExamples: true,
      renderMocked: true,
    }) as string
    assert.typeOf(result, 'string', 'is a string')
    const value = JSON.parse(result)
    assert.typeOf(value.hunts, 'boolean')
    assert.typeOf(value.age, 'number')
  })
})

test.group(`OAS union types / ${xmlMime}`, (group) => {
  let model: IAmfDocument

  group.setup(async () => {
    model = await loader.getGraph('oas-unions')
  })
  test('generates schema for a oneOf union', async ({ assert }) => {
    const shape = loader.getShape(model, 'OneOfSchema')
    const result = ApiSchemaGenerator.asSchema(shape, xmlMime, {
      renderExamples: true,
      renderMocked: true,
      renderOptional: true,
    }) as string
    assert.typeOf(result, 'string', 'generates a string')
    assert.isNotEmpty(result, 'generates a value')

    const parser = new DOMParser()
    const schema = parser.parseFromString(result, xmlMime)

    const root = schema.getElementsByTagName('Cat')[0]
    assert.ok(root, 'has the Cat parent')
    const hunts = root.getElementsByTagName('hunts')[0]
    assert.ok(hunts, 'has the hunts node')
    assert.match(hunts.textContent!.trim(), /true|false/, 'hunts node has a generated value')
    const age = root.getElementsByTagName('age')[0]
    assert.ok(age, 'has the age node')
    assert.match(age.textContent!.trim(), /\d+/, 'age node has a generated value')
  })

  test('generates schema for a allOf union', async ({ assert }) => {
    const shape = loader.getShape(model, 'AllOfSchema')
    const result = ApiSchemaGenerator.asSchema(shape, xmlMime, {
      renderExamples: true,
      renderMocked: true,
      renderOptional: true,
    }) as string
    assert.typeOf(result, 'string', 'generates a string')
    assert.isNotEmpty(result, 'generates a value')

    const parser = new DOMParser()
    const schema = parser.parseFromString(result, xmlMime)

    const root = schema.getElementsByTagName('AllOfSchema')[0]
    assert.ok(root, 'has the AllOfSchema parent')
    const hunts = root.getElementsByTagName('hunts')[0]
    assert.ok(hunts, 'has the hunts node')
    assert.match(hunts.textContent!.trim(), /true|false/, 'hunts node has a generated value')
    const age = root.getElementsByTagName('age')[0]
    assert.ok(age, 'has the age node')
    assert.match(age.textContent!.trim(), /\d+/, 'age node has a generated value')
    const bark = root.getElementsByTagName('bark')[0]
    assert.ok(bark, 'has the bark node')
    assert.match(bark.textContent!.trim(), /true|false/, 'bark node has a generated value')
    const breed = root.getElementsByTagName('breed')[0]
    assert.ok(breed, 'has the breed node')
    assert.equal(breed.textContent!.trim(), 'Dingo', 'breed node has the example value')
  })

  test('generates schema for a anyOf union', async ({ assert }) => {
    const shape = loader.getShape(model, 'AnyOfSchema')
    const result = ApiSchemaGenerator.asSchema(shape, xmlMime, {
      renderExamples: true,
      renderMocked: true,
      renderOptional: true,
    }) as string
    assert.typeOf(result, 'string', 'generates a string')
    assert.isNotEmpty(result, 'generates a value')

    const parser = new DOMParser()
    const schema = parser.parseFromString(result, xmlMime)

    const root = schema.getElementsByTagName('Cat')[0]
    assert.ok(root, 'has the Cat parent')
    const hunts = root.getElementsByTagName('hunts')[0]
    assert.ok(hunts, 'has the hunts node')
    assert.match(hunts.textContent!.trim(), /true|false/, 'hunts node has a generated value')
    const age = root.getElementsByTagName('age')[0]
    assert.ok(age, 'has the age node')
    assert.match(age.textContent!.trim(), /\d+/, 'age node has a generated value')
  })
})
