import { test } from '@japa/runner'
import {
  ResponseRedirect,
  IResponseRedirect,
  Kind as ResponseRedirectKind,
} from '../../../src/models/ResponseRedirect.js'
import { HttpResponse, IHttpResponse } from '../../../src/models/HttpResponse.js'
import { Kind as RequestTimeKind } from '../../../src/models/RequestTime.js'
import { ResponseRedirect as LegacyRedirect } from '../../../src/models/legacy/request/ArcResponse.js'
import { HttpResponseKind } from '../../../src/models/kinds.js'

test.group('Models > ResponseRedirect > ResponseRedirect.fromValues()', (group) => {
  let response: IHttpResponse
  group.each.setup(() => {
    response = HttpResponse.fromValues(200, 'OK', 'content-type: text/plain').toJSON()
  })

  test('sets the kind', ({ assert }) => {
    const result = ResponseRedirect.fromValues('https://dot.com', response)
    assert.equal(result.kind, ResponseRedirectKind)
  })

  test('sets the url', ({ assert }) => {
    const result = ResponseRedirect.fromValues('https://dot.com', response)
    assert.equal(result.url, 'https://dot.com')
  })

  test('sets the response', ({ assert }) => {
    const result = ResponseRedirect.fromValues('https://dot.com', response)
    assert.typeOf(result.response, 'object', 'has the response')
    assert.isTrue(result.response instanceof HttpResponse, 'has the HttpResponse instance')
  })

  test('sets the default startTime', ({ assert }) => {
    const result = ResponseRedirect.fromValues('https://dot.com', response)
    assert.equal(result.startTime, 0)
  })

  test('sets the default endTime', ({ assert }) => {
    const result = ResponseRedirect.fromValues('https://dot.com', response)
    assert.equal(result.endTime, 0)
  })

  test('sets the startTime', ({ assert }) => {
    const result = ResponseRedirect.fromValues('https://dot.com', response, 1234)
    assert.equal(result.startTime, 1234)
  })

  test('sets the endTime', ({ assert }) => {
    const result = ResponseRedirect.fromValues('https://dot.com', response, 1234, 5678)
    assert.equal(result.endTime, 5678)
  })
})

test.group('Models > ResponseRedirect > ResponseRedirect.fromLegacy()', (group) => {
  let schema: LegacyRedirect
  group.each.setup(() => {
    schema = {
      startTime: 1234,
      endTime: 5678,
      url: 'https://rdr.com',
      timings: {
        blocked: 1,
        connect: 2,
        dns: 3,
        receive: 4,
        send: 5,
        wait: 6,
        ssl: 7,
      },
      response: {
        status: 307,
        statusText: 'Moved.',
        headers: 'location: https://rdr.com',
        payload: 'I am in a different location.',
      },
    }
  })

  test('sets the kind', async ({ assert }) => {
    const result = await ResponseRedirect.fromLegacy(schema)
    assert.equal(result.kind, ResponseRedirectKind)
  })

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

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

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

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

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

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

  test('sets the response', async ({ assert }) => {
    const result = await ResponseRedirect.fromLegacy(schema)
    const { response } = result
    assert.typeOf(response, 'object')
    assert.equal(response!.status, schema.response.status)
    assert.equal(response!.statusText, schema.response.statusText)
    assert.equal(response!.headers, schema.response.headers)
    assert.equal(response!.payload, 'I am in a different location.')
  })

  test('sets the default response', async ({ assert }) => {
    // @ts-expect-error Used in testing
    delete schema.response
    const result = await ResponseRedirect.fromLegacy(schema)
    const { response } = result
    assert.typeOf(response, 'object')
    assert.equal(response!.status, 0)
  })

  test('sets the timings', async ({ assert }) => {
    const result = await ResponseRedirect.fromLegacy(schema)
    const { timings } = result
    assert.typeOf(timings, 'object')
    assert.equal(timings!.blocked, schema.timings!.blocked)
    assert.equal(timings!.connect, schema.timings!.connect)
    assert.equal(timings!.dns, schema.timings!.dns)
    assert.equal(timings!.receive, schema.timings!.receive)
    assert.equal(timings!.send, schema.timings!.send)
    assert.equal(timings!.wait, schema.timings!.wait)
  })
})

test.group('Models > ResponseRedirect > constructor()', () => {
  test('creates a default instance', ({ assert }) => {
    const result = new ResponseRedirect()
    assert.equal(result.kind, ResponseRedirectKind)
    assert.equal(result.endTime, 0)
    assert.equal(result.startTime, 0)
    assert.equal(result.url, '')
    assert.equal(result.response!.status, 0)
  })

  test('creates an instance from the schema', ({ assert }) => {
    const schema: IResponseRedirect = {
      kind: ResponseRedirectKind,
      startTime: 1234,
      endTime: 5678,
      url: 'https://dot.com',
      response: {
        status: 200,
        statusText: 'OK',
      },
      timings: {
        blocked: 1,
        connect: 2,
        dns: 3,
        receive: 4,
        send: 5,
        wait: 6,
        ssl: 7,
      },
    }
    const result = new ResponseRedirect(schema)
    assert.equal(result.kind, ResponseRedirectKind)
    assert.equal(result.startTime, 1234)
    assert.equal(result.endTime, 5678)
    assert.equal(result.url, 'https://dot.com')
    assert.equal(result.response!.status, 200)
    assert.equal(result.response!.statusText, 'OK')
    assert.equal(result.timings!.blocked, schema.timings!.blocked)
    assert.equal(result.timings!.connect, schema.timings!.connect)
  })

  test('the timings is optional', ({ assert }) => {
    const schema: IResponseRedirect = {
      kind: ResponseRedirectKind,
      startTime: 1234,
      endTime: 5678,
      url: 'https://dot.com',
      response: {
        status: 200,
        statusText: 'OK',
      },
    }
    const result = new ResponseRedirect(schema)
    assert.isUndefined(result.timings)
  })

  test('creates an instance from the JSON schema string', ({ assert }) => {
    const schema: IResponseRedirect = {
      kind: ResponseRedirectKind,
      startTime: 1234,
      endTime: 5678,
      url: 'https://dot.com',
      response: {
        status: 200,
        statusText: 'OK',
      },
    }
    const result = new ResponseRedirect(JSON.stringify(schema))
    assert.equal(result.kind, ResponseRedirectKind)
    assert.equal(result.startTime, 1234)
    assert.equal(result.endTime, 5678)
    assert.equal(result.url, 'https://dot.com')
    assert.equal(result.response!.status, 200)
    assert.equal(result.response!.statusText, 'OK')
  })
})

test.group('Models > ResponseRedirect > toJSON()', (group) => {
  let schema: IResponseRedirect
  let instance: ResponseRedirect
  group.each.setup(() => {
    schema = {
      kind: ResponseRedirectKind,
      startTime: 1234,
      endTime: 5678,
      url: 'https://dot.com',
      response: {
        kind: HttpResponseKind,
        status: 200,
        statusText: 'OK',
      },
      timings: {
        kind: RequestTimeKind, // Added kind for timings as it's likely a typed object
        blocked: 1,
        connect: 2,
        dns: 3,
        receive: 4,
        send: 5,
        wait: 6,
        ssl: 7,
      },
    }
    instance = new ResponseRedirect(schema)
  })

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

  test('serializes the startTime', ({ assert }) => {
    const result = instance.toJSON()
    assert.equal(result.startTime, schema.startTime)
  })

  test('serializes the endTime', ({ assert }) => {
    const result = instance.toJSON()
    assert.equal(result.endTime, schema.endTime)
  })

  test('serializes the url', ({ assert }) => {
    const result = instance.toJSON()
    assert.equal(result.url, schema.url)
  })

  test('serializes the response', ({ assert }) => {
    const result = instance.toJSON()
    assert.deepEqual(result.response, schema.response)
  })

  test('serializes the default response', ({ assert }) => {
    delete instance.response
    const result = instance.toJSON()
    assert.deepEqual(result.response, {
      kind: HttpResponseKind,
      status: 0,
    })
  })

  test('serializes the timings', ({ assert }) => {
    const result = instance.toJSON()
    // Assuming timings in schema also includes kind after serialization by RequestTime model
    assert.deepEqual(result.timings, schema.timings)
  })

  test('does not serialize the timings when missing', ({ assert }) => {
    delete instance.timings
    const result = instance.toJSON()
    assert.isUndefined(result.timings)
  })
})
