import { test } from '@japa/runner'
import fs from 'fs'
import { IResponse, Response, CoreEngine, HttpCertificate, createLogger } from '../../../../src/index.js'

const logger = createLogger()

// TODO: Move to generating certs on the fly.
test.group('Client certificate', (group) => {
  let alicePem: HttpCertificate
  let aliceP12: HttpCertificate
  let alicePassword: HttpCertificate
  let bobP12: HttpCertificate
  group.setup(() => {
    alicePem = {
      cert: {
        data: fs.readFileSync('./tests/resources/ssl/cert-auth-server/alice_cert.pem', 'utf8'),
      },
      certKey: {
        data: fs.readFileSync('./tests/resources/ssl/cert-auth-server/alice_key.pem', 'utf8'),
      },
      type: 'pem',
      key: '1',
      kind: 'Core#Certificate',
      name: 'Alice PEM',
    }
    aliceP12 = {
      cert: {
        data: fs.readFileSync('./tests/resources/ssl/cert-auth-server/alice.p12'),
        passphrase: '',
      },
      type: 'p12',
      key: '2',
      kind: 'Core#Certificate',
      name: 'Alice p12',
    }
    alicePassword = {
      cert: {
        data: fs.readFileSync('./tests/resources/ssl/cert-auth-server/alice-password.p12'),
        passphrase: 'test',
      },
      type: 'p12',
      key: '3',
      kind: 'Core#Certificate',
      name: 'Alice password',
    }
    bobP12 = {
      cert: {
        data: fs.readFileSync('./tests/resources/ssl/cert-auth-server/bob.p12'),
        passphrase: 'test',
      },
      type: 'p12',
      key: '4',
      kind: 'Core#Certificate',
      name: 'Bob p12',
    }
  })

  test('makes connection without a certificate', async ({ assert, httpConfig }) => {
    const request = new CoreEngine(
      {
        url: `https://localhost:${httpConfig.certsPort}/`,
        method: 'GET',
        headers: 'host: localhost',
      },
      {
        timeout: 10000,
        logger,
      }
    )

    const data = await request.send()
    assert.ok(data.response, 'has the response')
    const response = new Response(data.response as IResponse)
    const payload = (await response.readPayload('buffer')) as Buffer

    const payloadString = payload.toString()
    const body = JSON.parse(payloadString)
    assert.isFalse(body.authenticated)
  }).tags(['@http-engine', '@cert'])

  test('makes a connection with p12 client certificate', async ({ assert, httpConfig }) => {
    const request = new CoreEngine(
      {
        url: `https://localhost:${httpConfig.certsPort}/`,
        method: 'GET',
        headers: 'host: localhost',
      },
      {
        certificates: [aliceP12],
        logger,
      }
    )

    const data = await request.send()
    assert.ok(data.response, 'has the response')
    const response = new Response(data.response as IResponse)
    const payload = (await response.readPayload('buffer')) as Buffer
    const payloadString = payload.toString()
    const body = JSON.parse(payloadString)
    assert.isTrue(body.authenticated)
    assert.equal(body.name, 'Alice')
    assert.equal(body.issuer, 'localhost')
  }).tags(['@http-engine', '@cert'])

  test('makes a connection with p12 client certificate and password', async ({ assert, httpConfig }) => {
    const request = new CoreEngine(
      {
        url: `https://localhost:${httpConfig.certsPort}/`,
        method: 'GET',
        headers: 'host: localhost',
      },
      {
        certificates: [alicePassword],
        logger,
      }
    )

    const data = await request.send()
    const response = new Response(data.response as IResponse)
    const payload = (await response.readPayload('buffer')) as Buffer

    const payloadString = payload.toString()
    const body = JSON.parse(payloadString)
    assert.isTrue(body.authenticated)
    assert.equal(body.name, 'Alice')
    assert.equal(body.issuer, 'localhost')
  }).tags(['@http-engine', '@cert'])

  test('ignores untrusted valid certificates', async ({ assert, httpConfig }) => {
    const request = new CoreEngine(
      {
        url: `https://localhost:${httpConfig.certsPort}/`,
        method: 'GET',
        headers: 'host: localhost',
      },
      {
        certificates: [bobP12],
        logger,
      }
    )

    const data = await request.send()

    const response = new Response(data.response as IResponse)
    const payload = (await response.readPayload('buffer')) as Buffer

    const payloadString = payload.toString()
    const body = JSON.parse(payloadString)
    assert.isFalse(body.authenticated)
    assert.equal(body.name, 'Bob')
    // Bob has self-signed cert
    assert.equal(body.issuer, 'Bob')
  }).tags(['@http-engine', '@cert'])

  test('makes a connection with pem client certificate', async ({ assert, httpConfig }) => {
    const request = new CoreEngine(
      {
        url: `https://localhost:${httpConfig.certsPort}/`,
        method: 'GET',
        headers: 'host: localhost',
      },
      {
        certificates: [alicePem],
        logger,
      }
    )

    const data = await request.send()

    const response = new Response(data.response as IResponse)
    const payload = (await response.readPayload('buffer')) as Buffer

    const payloadString = payload.toString()
    const body = JSON.parse(payloadString)
    assert.isTrue(body.authenticated)
    assert.equal(body.name, 'Alice')
    assert.equal(body.issuer, 'localhost')
  }).tags(['@http-engine', '@cert'])
})
