import { test } from '@japa/runner'
import { SentRequest, ISentRequest, IBaseSentRequest } from '../../../src/models/SentRequest.js'
import { Kind as HttpRequestKind } from '../../../src/models/HttpRequest.js'
import { TransportRequest as LegacyTransportRequest } from '../../../src/models/legacy/request/ArcRequest.js'

test.group('Models > SentRequest > SentRequest.fromBaseValues()', (group) => {
  let base: IBaseSentRequest
  group.each.setup(() => {
    base = {
      startTime: 1234,
      url: 'https://dot.com',
      endTime: 5678,
      headers: 'x-test: true',
      httpMessage: 'GET / HTTP 1/1\n\n',
      method: 'GET',
      payload: 'test',
    }
  })

  test('sets the kind', ({ assert }) => {
    const result = SentRequest.fromBaseValues(base)
    assert.equal(result.kind, HttpRequestKind)
  })

  // Note: The original test had a duplicate "sets the kind" test. I'm keeping one.
  // If the second was intended to test something else, it should be adjusted.

  test('sets the httpMessage', ({ assert }) => {
    const result = SentRequest.fromBaseValues(base)
    assert.equal(result.httpMessage, base.httpMessage)
  })

  test('sets the startTime', ({ assert }) => {
    const result = SentRequest.fromBaseValues(base)
    assert.equal(result.startTime, base.startTime)
  })

  test('sets the endTime', ({ assert }) => {
    const result = SentRequest.fromBaseValues(base)
    assert.equal(result.endTime, base.endTime)
  })
})

test.group('Models > SentRequest > SentRequest.fromLegacy()', (group) => {
  let base: LegacyTransportRequest
  group.each.setup(() => {
    base = {
      startTime: 1234,
      url: 'https://dot.com',
      endTime: 5678,
      httpMessage: 'GET / HTTP 1/1\n\n',
      method: 'GET',
      headers: 'x-test: true',
      payload: 'test',
    }
  })

  test('sets the kind', async ({ assert }) => {
    const result = await SentRequest.fromLegacy(base)
    assert.equal(result.kind, HttpRequestKind)
  })

  test('sets the url', async ({ assert }) => {
    const result = await SentRequest.fromLegacy(base)
    assert.equal(result.url, base.url)
  })

  test('sets the default url when missing', async ({ assert }) => {
    // @ts-expect-error Used in testing
    delete base.url
    const result = await SentRequest.fromLegacy(base)
    assert.equal(result.url, '')
  })

  test('sets the startTime', async ({ assert }) => {
    const result = await SentRequest.fromLegacy(base)
    assert.equal(result.startTime, base.startTime)
  })

  test('sets the default startTime', async ({ assert }) => {
    // @ts-expect-error Used in testing
    delete base.startTime
    const result = await SentRequest.fromLegacy(base)
    assert.equal(result.startTime, 0)
  })

  test('sets the endTime', async ({ assert }) => {
    const result = await SentRequest.fromLegacy(base)
    assert.equal(result.endTime, base.endTime)
  })

  test('sets the default endTime when missing', async ({ assert }) => {
    // @ts-expect-error Used in testing
    delete base.endTime
    const result = await SentRequest.fromLegacy(base)
    assert.equal(result.endTime, 0)
  })

  test('sets the httpMessage', async ({ assert }) => {
    const result = await SentRequest.fromLegacy(base)
    assert.equal(result.httpMessage, base.httpMessage)
  })

  test('does not set the httpMessage when missing', async ({ assert }) => {
    // @ts-expect-error Used in testing
    delete base.httpMessage
    const result = await SentRequest.fromLegacy(base)
    assert.isUndefined(result.httpMessage)
  })

  test('sets the method', async ({ assert }) => {
    const result = await SentRequest.fromLegacy(base)
    assert.equal(result.method, base.method)
  })

  test('sets the default method when missing', async ({ assert }) => {
    // @ts-expect-error Used in testing
    delete base.method
    const result = await SentRequest.fromLegacy(base)
    assert.equal(result.method, 'GET')
  })

  test('sets the headers', async ({ assert }) => {
    const result = await SentRequest.fromLegacy(base)
    assert.equal(result.headers, base.headers)
  })

  test('does not set the headers when missing', async ({ assert }) => {
    delete base.headers
    const result = await SentRequest.fromLegacy(base)
    assert.isUndefined(result.headers)
  })

  test('sets the payload', async ({ assert }) => {
    const result = await SentRequest.fromLegacy(base)
    assert.equal(result.payload, 'test')
  })

  test('does not set the payload when missing', async ({ assert }) => {
    delete base.payload
    const result = await SentRequest.fromLegacy(base)
    assert.isUndefined(result.payload)
  })
})

test.group('Models > SentRequest > constructor()', () => {
  test('creates a default instance', ({ assert }) => {
    const result = new SentRequest()
    assert.equal(result.kind, HttpRequestKind)
    assert.equal(result.url, '')
    assert.equal(result.startTime, 0)
  })

  test('creates an instance from schema', ({ assert }) => {
    const schema: ISentRequest = {
      kind: HttpRequestKind,
      startTime: 1234,
      url: 'https://dot.com',
      endTime: 56789,
      httpMessage: 'GET / HTTP 1/1\n\n',
      method: 'GET',
      headers: 'x-test: true',
      payload: 'test',
    }
    const result = new SentRequest(schema)
    assert.deepEqual(result.toJSON(), schema)
  })

  test('creates an instance from a JSON schema string', ({ assert }) => {
    const schema: ISentRequest = {
      kind: HttpRequestKind,
      startTime: 1234,
      url: 'https://dot.com',
      endTime: 56789,
      httpMessage: 'GET / HTTP 1/1\n\n',
      method: 'GET',
      headers: 'x-test: true',
      payload: 'test',
    }
    const result = new SentRequest(JSON.stringify(schema))
    assert.deepEqual(result.toJSON(), schema)
  })
})

test.group('Models > SentRequest > toJSON()', (group) => {
  let schema: ISentRequest
  let instance: SentRequest
  group.each.setup(() => {
    schema = {
      kind: HttpRequestKind,
      startTime: 1234,
      url: 'https://dot.com',
      endTime: 56789,
      httpMessage: 'GET / HTTP 1/1\n\n',
      method: 'GET',
      headers: 'x-test: true',
      payload: 'test',
    }
    instance = new SentRequest(schema)
  })

  test('serializes all properties from schema', ({ assert }) => {
    const result = instance.toJSON()
    assert.deepEqual(result, schema)
  })
})
