import { test } from '@japa/runner'
import { Server, IServer, Kind as ServerKind } from '../../../src/models/Server.js'
import { Property } from '../../../src/models/Property.js'

test.group('Models > Server > Server.fromUri()', () => {
  test('sets the kind', ({ assert }) => {
    const result = Server.fromUri('https://dot.com')
    assert.equal(result.kind, ServerKind)
  })

  test('sets the uri', ({ assert }) => {
    const result = Server.fromUri('https://dot.com')
    assert.equal(result.uri, 'https://dot.com')
  })
})

test.group('Models > Server > constructor()', () => {
  test('creates an empty Server', ({ assert }) => {
    const result = new Server()
    assert.equal(result.kind, ServerKind)
    assert.equal(result.uri, '')
    assert.isUndefined(result.description)
    assert.isUndefined(result.protocol)
    assert.isUndefined(result.basePath)
  })

  test('creates a Server from the schema values', ({ assert }) => {
    const schema: IServer = {
      kind: ServerKind,
      uri: 'dot.com',
      description: 'a desc',
      protocol: 'https:',
      basePath: '/api',
    }
    const result = new Server(schema)
    assert.equal(result.kind, ServerKind)
    assert.equal(result.uri, 'dot.com')
    assert.equal(result.description, 'a desc')
    assert.equal(result.protocol, 'https:')
    assert.equal(result.basePath, '/api')
  })

  test('creates a Server from the JSON schema string', ({ assert }) => {
    const schema: IServer = {
      kind: ServerKind,
      uri: 'dot.com',
      description: 'a desc',
      protocol: 'https:',
      basePath: '/api',
    }
    const result = new Server(JSON.stringify(schema))
    assert.equal(result.kind, ServerKind)
    assert.equal(result.uri, 'dot.com')
    assert.equal(result.description, 'a desc')
    assert.equal(result.protocol, 'https:')
    assert.equal(result.basePath, '/api')
  })

  test('throws when invalid schema', ({ assert }) => {
    assert.throws(() => {
      new Server(
        JSON.stringify({
          name: 'a name', // Invalid, Server expects 'uri' not 'name' for primary identifier
        })
      )
    })
  })
})

test.group('Models > Server > toJSON()', (group) => {
  let server: Server
  group.each.setup(() => {
    server = new Server()
  })

  test('serializes the kind', ({ assert }) => {
    const result = server.toJSON()
    assert.equal(result.kind, ServerKind)
  })

  test('serializes the uri', ({ assert }) => {
    server.uri = 'dot.com'
    const result = server.toJSON()
    assert.equal(result.uri, 'dot.com')
  })

  test('serializes the description', ({ assert }) => {
    server.description = 'a description'
    const result = server.toJSON()
    assert.equal(result.description, 'a description')
  })

  test('does not serialize description when missing', ({ assert }) => {
    const result = server.toJSON()
    assert.isUndefined(result.description)
  })

  test('serializes the protocol', ({ assert }) => {
    server.protocol = 'a protocol'
    const result = server.toJSON()
    assert.equal(result.protocol, 'a protocol')
  })

  test('does not serialize protocol when missing', ({ assert }) => {
    const result = server.toJSON()
    assert.isUndefined(result.protocol)
  })

  test('serializes the basePath', ({ assert }) => {
    server.basePath = 'a basePath'
    const result = server.toJSON()
    assert.equal(result.basePath, 'a basePath')
  })

  test('does not serialize basePath when missing', ({ assert }) => {
    const result = server.toJSON()
    assert.isUndefined(result.basePath)
  })
})

test.group('Models > Server > readUri()', () => {
  test('returns empty string when no data', ({ assert }) => {
    const info = new Server()
    const result = info.readUri()
    assert.equal(result, '')
  })

  test('returns the uri value', ({ assert }) => {
    const info = new Server()
    info.uri = 'dot.com'
    const result = info.readUri()
    assert.equal(result, 'dot.com')
  })

  test('adds the protocol when missing', ({ assert }) => {
    const info = new Server()
    info.uri = 'dot.com'
    info.protocol = 'http:'
    const result = info.readUri()
    assert.equal(result, 'http://dot.com')
  })

  test('ignores the protocol when not missing', ({ assert }) => {
    const info = new Server()
    info.uri = 'https://dot.com'
    info.protocol = 'http:'
    const result = info.readUri()
    assert.equal(result, 'https://dot.com')
  })

  test('adds the base path', ({ assert }) => {
    const info = new Server()
    info.uri = 'dot.com'
    info.basePath = '/api'
    const result = info.readUri()
    assert.equal(result, 'dot.com/api')
  })

  test('clears the base uri before adding the base path', ({ assert }) => {
    const info = new Server()
    info.uri = 'dot.com/'
    info.basePath = '/api'
    const result = info.readUri()
    assert.equal(result, 'dot.com/api')
  })

  test('normalizes the base path', ({ assert }) => {
    const info = new Server()
    info.uri = 'dot.com'
    info.basePath = 'api'
    const result = info.readUri()
    assert.equal(result, 'dot.com/api')
  })

  test('evaluates the uri when no variables', ({ assert }) => {
    const info = Server.fromUri('https://api.com')
    const p1 = Property.String('a', 'b')
    const result = info.readUri([p1])
    assert.equal(result, 'https://api.com')
  })

  test('evaluates the uri', ({ assert }) => {
    const info = Server.fromUri('https://{a}.com')
    const p1 = Property.String('a', 'b')
    const result = info.readUri([p1])
    assert.equal(result, 'https://b.com')
  })

  test('evaluates the uri when no property', ({ assert }) => {
    const info = Server.fromUri('https://{a}.com')
    const p1 = Property.String('c', 'b')
    const result = info.readUri([p1])
    assert.equal(result, 'https://{a}.com')
  })
})
