import { test } from '@japa/runner'
import {
  IResponse,
  Response,
  createLogger,
  CoreEngine,
  IHttpRequest,
  HttpEngineOptions,
  Headers,
} from '../../../../src/index.js'

const logger = createLogger()

test.group('prepareHeaders()', (group) => {
  let request: IHttpRequest
  let opts: HttpEngineOptions

  group.each.setup(() => {
    request = {
      url: 'https://api.domain.com',
      method: 'GET',
      headers: '',
    }
    opts = {
      defaultHeaders: true,
      logger,
    }
  })

  test('adds default user-agent', ({ assert }) => {
    const base = new CoreEngine(request, opts)
    const headers = new Headers()
    base.prepareHeaders(headers)
    assert.equal(headers.get('user-agent'), 'api client')
  })

  test('adds default accept', ({ assert }) => {
    const base = new CoreEngine(request, opts)
    const headers = new Headers()
    base.prepareHeaders(headers)
    assert.equal(headers.get('accept'), '*/*')
  })

  test('adds configured user-agent', ({ assert }) => {
    opts.defaultUserAgent = 'test'
    const base = new CoreEngine(request, opts)
    const headers = new Headers()
    base.prepareHeaders(headers)
    assert.equal(headers.get('user-agent'), 'test')
  })

  test('adds configured accept', ({ assert }) => {
    opts.defaultAccept = 'test'
    const base = new CoreEngine(request, opts)
    const headers = new Headers()
    base.prepareHeaders(headers)
    assert.equal(headers.get('accept'), 'test')
  })

  test('ignores adding headers when no config option', ({ assert }) => {
    opts.defaultHeaders = false
    const base = new CoreEngine(request, opts)
    const headers = new Headers()
    base.prepareHeaders(headers)
    assert.isFalse(headers.has('user-agent'), 'user-agent is not set')
    assert.isFalse(headers.has('accept'), 'accept is not set')
  })

  test('skips when user-agent header is set', ({ assert }) => {
    const base = new CoreEngine(request, opts)
    const headers = new Headers({
      'user-agent': 'test',
    })
    base.prepareHeaders(headers)
    assert.equal(headers.get('user-agent'), 'test')
  })

  test('skips when accept header is set', ({ assert }) => {
    const base = new CoreEngine(request, opts)
    const headers = new Headers({
      accept: 'test',
    })
    base.prepareHeaders(headers)
    assert.equal(headers.get('accept'), 'test')
  })

  test('adds the content-type when missing and defined in options', ({ assert }) => {
    const base = new CoreEngine({ ...request, method: 'POST', payloadOptions: { mime: 'test/text' } }, opts)
    const headers = new Headers()
    base.prepareHeaders(headers, true)
    assert.equal(headers.get('content-type'), 'test/text')
  })

  test('ignores adding the content-type when header set and defined in options', ({ assert }) => {
    const base = new CoreEngine({ ...request, method: 'POST', payloadOptions: { mime: 'test/text' } }, opts)
    const headers = new Headers({ 'content-type': 'test/other' })
    base.prepareHeaders(headers, true)
    assert.equal(headers.get('content-type'), 'test/other')
  })

  test('ignores adding the content-type when no options', ({ assert }) => {
    const base = new CoreEngine({ ...request, method: 'POST' }, opts)
    const headers = new Headers()
    base.prepareHeaders(headers, true)
    assert.isFalse(headers.has('content-type'))
  })
})

test.group('headers processing', (group) => {
  let request: IHttpRequest
  const opts: HttpEngineOptions = {
    logger,
  }

  group.each.setup((ctx) => {
    request = {
      url: `http://localhost:${ctx.context.httpConfig.httpPort}/v1/headers/`,
      method: 'GET',
      headers: '',
    }
  })

  test('sends a header', async ({ assert }) => {
    const r = { ...request }
    r.headers = 'x-test-header: true'
    const er = new CoreEngine(r, opts)
    const log = await er.send()
    const response = new Response(log.response as IResponse)
    const payload = (await response.readPayload('buffer')) as Buffer
    const body = JSON.parse(payload.toString('utf8'))
    assert.equal(body.headers['x-test-header'], 'true')
  })

  test('sends multiple headers', async ({ assert }) => {
    const r = { ...request }
    r.headers = 'x-test-header: true\nAccept-CH: DPR, Viewport-Width'
    const er = new CoreEngine(r, opts)
    const log = await er.send()
    const response = new Response(log.response as IResponse)
    const payload = (await response.readPayload('buffer')) as Buffer
    const body = JSON.parse(payload.toString('utf8'))
    assert.equal(body.headers['x-test-header'], 'true')
    assert.equal(body.headers['accept-ch'], 'DPR, Viewport-Width')
  })

  test('sends array headers', async ({ assert }) => {
    const r = { ...request }
    r.headers = 'x-test-header: true, x-value'
    const er = new CoreEngine(r, opts)
    const log = await er.send()
    const response = new Response(log.response as IResponse)
    const payload = (await response.readPayload('buffer')) as Buffer
    const body = JSON.parse(payload.toString('utf8'))
    assert.equal(body.headers['x-test-header'], 'true, x-value')
  })
})
