import { test } from '@japa/runner'
import { DataTestHelper } from './DataTestHelper.js'
import { ArcExportObject, ArcPouchTransformer } from '../../../src/legacy.js'
import pouchData from './data/pouch-data-export.json' with { type: 'json' }
import arcData from './data/arc-pouchdb.json' with { type: 'json' }

test.group('ArcPouchTransformer: previous version', (group) => {
  let result: ArcExportObject
  group.setup(async () => {
    const transformer = new ArcPouchTransformer(structuredClone(pouchData))
    result = await transformer.transform()
  })

  test('normalizes the data', ({ assert }) => {
    assert.typeOf(result, 'object')
  })

  test('contains export object properties', ({ assert }) => {
    assert.typeOf(result.createdAt, 'string')
    assert.equal(result.version, '9.14.64.305')
    assert.equal(result.kind, 'ARC#Import')
    assert.typeOf(result.projects!, 'array')
    assert.typeOf(result.requests!, 'array')
    assert.typeOf(result.history, 'array')
    assert.typeOf(result.variables, 'array')
    assert.typeOf(result.cookies, 'array')
    assert.typeOf(result.websocketurlhistory, 'array')
    assert.typeOf(result.urlhistory, 'array')
    assert.typeOf(result.authdata, 'array')
    assert.typeOf(result.hostrules, 'array')
  })

  test('has all the data', ({ assert }) => {
    assert.lengthOf(result.projects!, 2, 'has 2 projects')
    assert.lengthOf(result.requests!, 5, 'has 5 saved')
    assert.lengthOf(result.history!, 3, 'has 3 history')
    assert.lengthOf(result.variables!, 4, 'has 4 variables')
    assert.lengthOf(result.cookies!, 2, 'has 2 cookies')
    assert.lengthOf(result.websocketurlhistory!, 1, 'has 1 websocket url')
    assert.lengthOf(result.urlhistory!, 5, 'has 5 history urls')
    assert.lengthOf(result.authdata!, 1, 'has 1 auth data')
    assert.lengthOf(result.hostrules!, 1, 'has 1 host rules')
  })

  test('has valid request objects', ({ assert }) => {
    DataTestHelper.assertRequestObject(result.requests![0], assert)
    DataTestHelper.assertRequestObject(result.requests![1], assert)
    DataTestHelper.assertRequestObject(result.requests![2], assert)
    DataTestHelper.assertRequestObject(result.requests![3], assert)
  })

  test('has valid project objects', ({ assert }) => {
    DataTestHelper.assertProjectObject(result.projects![0], assert)
    DataTestHelper.assertProjectObject(result.projects![1], assert)
  })

  test('has valid history objects', ({ assert }) => {
    DataTestHelper.assertHistoryObject(result.history![0], assert)
    DataTestHelper.assertHistoryObject(result.history![1], assert)
    DataTestHelper.assertHistoryObject(result.history![2], assert)
  })

  test('has request values', ({ assert }) => {
    let request = result.requests![0]
    let compare = pouchData.requests[0]
    assert.equal(request.url, compare.url)
    assert.equal(request.method, compare.method)
    assert.equal(request.headers, compare.headers)
    assert.equal(request.payload, compare.payload)
    assert.equal(request.created, compare.updated, 'the created is the previous updated')
    assert.equal(request.updated, compare.updated, 'has the updated property')
    assert.equal(request.name, compare.name)
    assert.equal(request.type, compare.type)
    assert.equal(request.kind, 'ARC#HttpRequest')

    request = result.requests![1]
    compare = pouchData.requests[1]
    assert.equal(request.url, compare.url)
    assert.equal(request.method, compare.method)
    assert.equal(request.headers, '')
    assert.equal(request.payload, '')
    assert.equal(request.created, compare.created, 'has the created property')
    assert.typeOf(request.updated, 'number', 'has the generated updated property')
    assert.equal(request.name, compare.name)
    assert.equal(request.type, compare.type)
    assert.equal(request.kind, 'ARC#HttpRequest')

    request = result.requests![3]
    compare = pouchData.requests[3]
    assert.equal(request.url, compare.url)
    assert.equal(request.method, compare.method)
    assert.equal(request.headers, compare.headers)
    assert.equal(request.payload, compare.payload)
    assert.equal(request.created, compare.updated, 'the created is the previous updated')
    assert.equal(request.name, compare.name)
    assert.equal(request.type, compare.type)
    assert.equal(request.kind, 'ARC#HttpRequest')
  })

  test('has project values', ({ assert }) => {
    let project = result.projects![0]
    let compare = pouchData.projects![0]
    assert.equal(project.name, compare.name, 'name is set')
    assert.equal(project.created, compare.created, 'created is set')
    assert.strictEqual(project.order, compare.order, 'order is set')
    assert.equal(project.kind, 'ARC#ProjectData')

    project = result.projects![1]
    compare = pouchData.projects![1]
    assert.equal(project.name, compare.name, 'name is set')
    assert.equal(project.created, compare.created, 'created is set')
    assert.strictEqual(project.order, compare.order, 'order is set')
    assert.equal(project.kind, 'ARC#ProjectData')
  })

  test('associates requests with projects', ({ assert }) => {
    assert.isUndefined(result.requests![0].projects)
    assert.isUndefined(result.requests![1].projects)
    assert.typeOf(result.requests![2].projects!, 'array')
    assert.lengthOf(result.requests![2].projects!, 1)
    assert.typeOf(result.requests![3].projects!, 'array')
    assert.lengthOf(result.requests![3].projects!, 1)
  })

  test('associates projects with requests', ({ assert }) => {
    const p1 = result.projects![0]
    assert.typeOf(p1.requests!, 'array')
    assert.lengthOf(p1.requests!, 1)
    const p2 = result.projects![0]
    assert.typeOf(p2.requests!, 'array')
    assert.lengthOf(p2.requests!, 1)
  })

  test('sets correct project ID', ({ assert }) => {
    const p1id = result.projects![0].key
    const p2id = result.projects![1].key
    assert.equal(result.requests![2].projects![0], p1id)
    assert.equal(result.requests![3].projects![0], p2id)
  })

  test('transforms variable objects', ({ assert }) => {
    result.variables!.forEach((item, index) => {
      const processed = { ...item }
      const original = { ...pouchData.variables[index] }
      assert.typeOf(processed.name, 'string', 'processed item has name property')
      assert.equal(processed.name, original.variable, 'processed item has name value from the original variable')
      delete (processed as unknown as Record<string, unknown>).name
      // @ts-expect-error For testing only
      delete original.variable
      assert.deepEqual(processed, original, 'has all properties')
    })
  })

  test('does not transform cookies object', ({ assert }) => {
    assert.deepEqual(result.cookies, pouchData.cookies)
  })

  test('sets websocketurlhistory object without transformation', ({ assert }) => {
    assert.deepEqual(result.websocketurlhistory, pouchData['websocket-url-history'])
  })

  test('sets urlhistory object without transformation', ({ assert }) => {
    assert.deepEqual(result.urlhistory, pouchData['url-history'])
  })

  test('sets authdata object without transformation', ({ assert }) => {
    assert.deepEqual(result.authdata, pouchData['auth-data'])
  })

  test('sets hostrules object without transformation', ({ assert }) => {
    assert.deepEqual(result.hostrules, pouchData['host-rules'])
  })

  test('transforms client certificates', ({ assert }) => {
    assert.lengthOf(result.clientcertificates!, 1)
  })

  test('sets client certificates data', ({ assert }) => {
    const [item] = result.clientcertificates!
    assert.equal(item.name, 'Bob pem', 'has the name')
    assert.equal(item.type, 'pem', 'has the type')
    assert.equal(item.dataKey, '2bcf5d24-744b-4002-ad80-5e3b9bfead18', 'has the dataKey')
    assert.equal(item.created, 1577999288834, 'has the created')
    assert.equal(item.key, '60547629-570a-4b4a-8529-55723cd3f80d', 'has the key')
    assert.equal(item.kind, 'ARC#ClientCertificate', 'has the kind')
    assert.typeOf(item.cert, 'object', 'has the cert')
    assert.typeOf(item.pKey, 'object', 'has the pKey')
  })
})

test.group('ArcPouchTransformer: PouchDB export system', (group) => {
  let exportObject: ArcExportObject
  group.setup(async () => {
    const transformer = new ArcPouchTransformer(structuredClone(arcData))
    exportObject = await transformer.transform()
  })

  test('does not process saved requests data', async ({ assert }) => {
    assert.typeOf(exportObject.requests!, 'array', 'created requests array')
    assert.equal(exportObject.requests!.length, arcData.requests.length, 'has the same number of requests')
    const [srcRequest] = exportObject.requests!
    const [trgRequest] = arcData.requests
    assert.equal(srcRequest.url, trgRequest.url, 'the URL is set')
    assert.equal(srcRequest.method, trgRequest.method, 'the method is set')
    assert.equal(srcRequest.headers, trgRequest.headers, 'the headers is set')
    assert.equal(srcRequest.created, trgRequest.created, 'the created is set')
    assert.equal(srcRequest.updated, trgRequest.updated, 'the updated is set')
    assert.equal(srcRequest.type, trgRequest.type, 'the type is set')
    assert.equal(srcRequest.name, trgRequest.name, 'the name is set')
    assert.equal(srcRequest.midnight, trgRequest.midnight, 'the midnight is set')
    // @ts-expect-error For testing only
    assert.equal(srcRequest.description, trgRequest.description, 'the description is set')
    assert.notStrictEqual(trgRequest.payload, undefined, 'the payload is set')
    assert.equal(srcRequest.key, trgRequest.key, 'the key is set')
    assert.equal(trgRequest.kind, 'ARC#RequestData', 'the kind is set')
    const [project] = arcData.projects
    assert.typeOf(project.created, 'number', 'the project has the created property')
    assert.typeOf(project.updated, 'number', 'the project has the updated property')
    assert.deepEqual(exportObject.projects![0], project)
  })

  test('does not process the history requests data', async ({ assert }) => {
    assert.deepEqual(exportObject.history, arcData.history)
  })

  test('does not process the ws url data', async ({ assert }) => {
    assert.deepEqual(exportObject.websocketurlhistory, arcData.websocketurlhistory)
  })

  test('does not process the url history data', async ({ assert }) => {
    assert.deepEqual(exportObject.urlhistory, arcData.urlhistory)
  })

  test('does not process the url history data', async ({ assert }) => {
    assert.deepEqual(exportObject.variables, arcData.variables)
  })

  test('does not process the authorization data', async ({ assert }) => {
    assert.deepEqual(exportObject.authdata, arcData.authdata)
  })

  test('does not process the host rules data', async ({ assert }) => {
    assert.deepEqual(exportObject.hostrules, arcData.hostrules)
  })
})
