import { test } from '@japa/runner'
import { AmfLoader } from '../AmfLoader.js'
import { AmfSerializer } from '../../../../src/amf/AmfSerializer.js'
import type { IAmfDomainElement } from '../../../../src/amf/definitions/Amf.js'

const loader = new AmfLoader()

test.group('apiSummary()', (group) => {
  let petstore: IAmfDomainElement
  let demoApi: IAmfDomainElement
  let petstoreSerializer: AmfSerializer
  let demoSerializer: AmfSerializer

  group.setup(async () => {
    const a1 = await loader.getGraph('petstore')
    const a2 = await loader.getGraph('arc-demo-api')
    petstoreSerializer = new AmfSerializer(a1)
    demoSerializer = new AmfSerializer(a2)
    petstore = petstoreSerializer._computeEncodes(a1) as IAmfDomainElement
    demoApi = demoSerializer._computeEncodes(a2) as IAmfDomainElement
  })

  test('serializes the id', ({ assert }) => {
    const result = demoSerializer.apiSummary(demoApi)
    assert.typeOf(result.id, 'string', 'has the id')
    assert.equal(result.id, demoApi['@id'], 'has the web api id')
  })

  test('serializes the types', ({ assert }) => {
    const result = demoSerializer.apiSummary(demoApi)
    assert.typeOf(result.types, 'array', 'has the id')
    assert.equal(result.types.length, demoApi['@type'].length, 'has all types')
  })

  test('serializes empty customDomainProperties', ({ assert }) => {
    const result = demoSerializer.apiSummary(demoApi)
    assert.typeOf(result.customDomainProperties, 'array', 'has the customDomainProperties')
    assert.lengthOf(result.customDomainProperties, 0, 'has no values')
  })

  test('serializes the sourceMaps', ({ assert }) => {
    const result = demoSerializer.apiSummary(demoApi)
    assert.typeOf(result.sourceMaps, 'object', 'has the sourceMaps')
  })

  test('serializes the schemes', ({ assert }) => {
    const result = demoSerializer.apiSummary(demoApi)
    assert.deepEqual(result.schemes, ['HTTP', 'HTTPS'])
  })

  test('has default schemes', ({ assert }) => {
    const result = petstoreSerializer.apiSummary(petstore)
    assert.deepEqual(result.schemes, [])
  })

  test('serializes the accepts', ({ assert }) => {
    const result = demoSerializer.apiSummary(demoApi)
    assert.deepEqual(result.accepts, ['application/json', 'application/xml'])
  })

  test('has default accepts', ({ assert }) => {
    const result = petstoreSerializer.apiSummary(petstore)
    assert.deepEqual(result.accepts, [])
  })

  test('serializes the contentType', ({ assert }) => {
    const result = demoSerializer.apiSummary(demoApi)
    assert.deepEqual(result.contentType, ['application/json', 'application/xml'])
  })

  test('has default contentType', ({ assert }) => {
    const result = petstoreSerializer.apiSummary(petstore)
    assert.deepEqual(result.contentType, [])
  })

  test('serializes the documentations', ({ assert }) => {
    const result = petstoreSerializer.apiSummary(petstore)
    assert.typeOf(result.documentations, 'array', 'has the array')
    assert.lengthOf(result.documentations, 1, 'has a single documentation')
  })

  test('serializes the tags', ({ assert }) => {
    const result = petstoreSerializer.apiSummary(petstore)
    assert.typeOf(result.tags, 'array', 'has the tags')
    assert.lengthOf(result.tags, 3, 'has all tags')
    const [tag] = result.tags
    assert.equal(tag.name, 'pet', 'has the tags definition')
  })

  test('has default tags', ({ assert }) => {
    const result = demoSerializer.apiSummary(demoApi)
    assert.deepEqual(result.tags, [])
  })

  test('serializes the license', ({ assert }) => {
    const result = petstoreSerializer.apiSummary(petstore)
    const { name, url } = result.license!
    assert.equal(name, 'Apache 2.0', 'has the license.name')
    assert.equal(url, 'http://www.apache.org/licenses/LICENSE-2.0.html', 'has the license.url')
  })

  test('serializes the provider', ({ assert }) => {
    const result = petstoreSerializer.apiSummary(petstore)
    const { name, url, email } = result.provider!
    assert.equal(name, 'Swagger IO', 'has the provider.name')
    assert.equal(url, 'swagger.io', 'has the provider.url')
    assert.equal(email, 'apiteam@swagger.io', 'has the provider.email')
  })
})

test.group('api()', (group) => {
  let demoApi: IAmfDomainElement
  let demoSerializer: AmfSerializer

  group.setup(async () => {
    const a2 = await loader.getGraph('arc-demo-api')
    demoSerializer = new AmfSerializer(a2)
    demoApi = demoSerializer._computeEncodes(a2) as IAmfDomainElement
  })

  test('has the ApiSummary properties', ({ assert }) => {
    const result = demoSerializer.api(demoApi)
    assert.typeOf(result.id, 'string', 'has the id')
    assert.equal(result.id, demoApi['@id'], 'has the web api id')
    assert.deepEqual(result.schemes, ['HTTP', 'HTTPS'])
    assert.deepEqual(result.accepts, ['application/json', 'application/xml'])
  })

  test('has the end points', ({ assert }) => {
    const result = demoSerializer.api(demoApi)
    assert.typeOf(result.endPoints, 'array', 'has the endpoints')
    const [endPoint] = result.endPoints
    assert.equal(endPoint.path, '/test-parameters/{feature}', 'has the end point definition')
  })

  test('has the servers', ({ assert }) => {
    const result = demoSerializer.api(demoApi)
    assert.typeOf(result.servers, 'array', 'has the servers')
    const [server] = result.servers
    assert.equal(server.url, 'http://{instance}.domain.com/', 'has the server definition')
  })
})

test.group('webApi()', (group) => {
  let demoApi: IAmfDomainElement
  let demoSerializer: AmfSerializer

  group.setup(async () => {
    const a2 = await loader.getGraph('arc-demo-api')
    demoSerializer = new AmfSerializer(a2)
    demoApi = demoSerializer._computeEncodes(a2) as IAmfDomainElement
  })

  test('has the ApiSummary properties', ({ assert }) => {
    const result = demoSerializer.webApi(demoApi)
    assert.typeOf(result.id, 'string', 'has the id')
    assert.equal(result.id, demoApi['@id'], 'has the web api id')
    assert.deepEqual(result.schemes, ['HTTP', 'HTTPS'])
    assert.deepEqual(result.accepts, ['application/json', 'application/xml'])
  })

  test('has the end points', ({ assert }) => {
    const result = demoSerializer.webApi(demoApi)
    assert.typeOf(result.endPoints, 'array', 'has the endpoints')
    const [endPoint] = result.endPoints
    assert.equal(endPoint.path, '/test-parameters/{feature}', 'has the end point definition')
  })

  test('has the servers', ({ assert }) => {
    const result = demoSerializer.webApi(demoApi)
    assert.typeOf(result.servers, 'array', 'has the servers')
    const [server] = result.servers
    assert.equal(server.url, 'http://{instance}.domain.com/', 'has the server definition')
  })
})

test.group('asyncApi()', (group) => {
  let asyncApi: IAmfDomainElement
  let demoSerializer: AmfSerializer
  let asyncSerializer: AmfSerializer

  group.setup(async () => {
    const a2 = await loader.getGraph('arc-demo-api')
    const a3 = await loader.getGraph('async-api')
    demoSerializer = new AmfSerializer(a2)
    asyncSerializer = new AmfSerializer(a3)
    asyncApi = asyncSerializer._computeEncodes(a3) as IAmfDomainElement
  })

  test('has the ApiSummary properties', ({ assert }) => {
    const result = demoSerializer.asyncApi(asyncApi)
    assert.typeOf(result.id, 'string', 'has the id')
    assert.equal(result.id, asyncApi['@id'], 'has the web api id')
    assert.equal(result.name, 'Hello world application')
  })

  test('has the end points', ({ assert }) => {
    const result = demoSerializer.asyncApi(asyncApi)
    assert.typeOf(result.endPoints, 'array', 'has the endpoints')
    const [endPoint] = result.endPoints
    assert.equal(endPoint.path, 'hello', 'has the end point definition')
  })

  test('has the servers', ({ assert }) => {
    const result = demoSerializer.asyncApi(asyncApi)
    assert.typeOf(result.servers, 'array', 'has the servers')
    const [server] = result.servers
    assert.equal(server.url, 'broker.mycompany.com', 'has the server definition')
  })
})
