/* eslint-disable no-unused-expressions */

const chai = require('chai')
chai.use(require('chai-http'))
const helpers = require('../helpers.js')

const expect = chai.expect

const constants = require('../constants.js')
const app = require('../../../src/index.js')
const currentDate = new Date().toISOString()

describe('Testing Get cve_cursor endpoint', () => {
  let cveIds = []
  before(async () => {
    cveIds = await helpers.cveIdBulkReserveHelper(5, '2023', constants.headers['CVE-API-ORG'], 'sequential')
    for (const cveId of cveIds) {
      await helpers.cveRequestAsSecHelper(cveId)
    }
  })
  const TOTAL_COUNT = 119

  context('Positive Tests', () => {
    it('Get cve_cursor should return all records when no parameters are specifed', async () => {
      await chai.request(app)
        .get('/api/cve_cursor')
        .set(constants.headers)
        .then((res, err) => {
          expect(err).to.be.undefined
          expect(res).to.have.status(200)
          expect(res.body.cveRecords.length).to.equal(TOTAL_COUNT)
        })
    })
    it('Get cve_cursor should return 2 records when limit parameter is set to 2', async () => {
      const limit = 2
      await chai.request(app)
        .get('/api/cve_cursor?limit=2')
        .set(constants.headers)
        .then((res, err) => {
          expect(err).to.be.undefined
          expect(res).to.have.status(200)
          expect(res.body.cveRecords.length).to.equal(limit)
        })
    })
    it('Get cve_cursor should not return duplicate records when records are modified between page calls with time_modified.gt ', async () => {
      let next = null
      let prev = null
      let pageOneRec1 = null
      let pageOneRec2 = null
      let pageTwoRec1 = null
      let pageTwoRec2 = null

      const requester = chai.request(app).keepOpen()

      // Request page 1
      await requester.get('/api/cve_cursor?limit=2&time_modified.gt=' + currentDate)
        .set(constants.headers)
        .then(async (res, err) => {
          expect(err).to.be.undefined
          expect(res).to.have.status(200)

          // Check that we're on the first page
          expect(res.body.hasNext).to.be.true
          expect(res.body.hasPrevious).to.be.false

          // Save both records from page 1
          pageOneRec1 = res.body.cveRecords[0]
          pageOneRec2 = res.body.cveRecords[1]
          next = res.body.next
        })

      // Request page 2
      await requester.get('/api/cve_cursor?limit=2&next_page=' + next + '&time_modified.gt=' + currentDate)
        .set(constants.headers)
        .then((res, err) => {
          expect(err).to.be.undefined
          expect(res).to.have.status(200)

          // Check that we're not on the first page
          expect(res.body.hasNext).to.be.true
          expect(res.body.hasPrevious).to.be.true

          // Store records from page 2
          pageTwoRec1 = res.body.cveRecords[0]
          pageTwoRec2 = res.body.cveRecords[1]
          prev = res.body.previous
        })

      // Create new CVE record, which would appear at the beginning, but data should not be moved
      const newcveId = await helpers.cveIdBulkReserveHelper(1, '2023', constants.headers['CVE-API-ORG'], 'sequential')
      await helpers.cveRequestAsSecHelper(newcveId)

      // Request page 2 again using same next_page string, should see no change in results
      await requester.get('/api/cve_cursor?limit=2&next_page=' + next + '&time_modified.gt=' + currentDate)
        .set(constants.headers)
        .then((res, err) => {
          expect(err).to.be.undefined
          expect(res).to.have.status(200)

          expect(res.body.cveRecords[0]).to.deep.equal(pageTwoRec1)
          expect(res.body.cveRecords[1]).to.deep.equal(pageTwoRec2)
        })

      // Request page 1 again using prev_page string from first page 2 request, should see no change in results
      await requester.get('/api/cve_cursor?limit=2&previous_page=' + prev + '&time_modified.gt=' + currentDate)
        .set(constants.headers)
        .then((res, err) => {
          expect(err).to.be.undefined
          expect(res).to.have.status(200)

          expect(res.body.cveRecords[0]).to.deep.equal(pageOneRec1)
          expect(res.body.cveRecords[1]).to.deep.equal(pageOneRec2)
        })

      // Request page 1 again without next/prev, should see new record
      await requester.get('/api/cve_cursor?limit=2&time_modified.gt=' + currentDate)
        .set(constants.headers)
        .then((res, err) => {
          expect(err).to.be.undefined
          expect(res).to.have.status(200)

          // Newly created record appears at the front, shifting other records
          expect(res.body.cveRecords[0]).to.not.deep.equal(pageOneRec1)
          expect(res.body.cveRecords[1]).to.deep.equal(pageOneRec1)
        })

      requester.close()
    }).timeout(1000000)
    it('Get cve_cursor should not miss records when records are modified between page calls with time_modified.lt ', async () => {
      let next = null
      let prev = null
      let pageOneRec1 = null
      let pageOneRec2 = null
      let pageTwoRec1 = null
      let pageTwoRec2 = null

      const requester = chai.request(app).keepOpen()

      // Request page 1
      await requester.get('/api/cve_cursor?limit=2&time_modified.lt=' + currentDate)
        .set(constants.headers)
        .then(async (res, err) => {
          expect(err).to.be.undefined
          expect(res).to.have.status(200)

          // Check that we're on the first page
          expect(res.body.hasNext).to.be.true
          expect(res.body.hasPrevious).to.be.false

          // Save both records from page 1
          pageOneRec1 = res.body.cveRecords[0]
          pageOneRec2 = res.body.cveRecords[1]
          next = res.body.next
        })

      // Request page 2
      await requester.get('/api/cve_cursor?limit=2&next_page=' + next + '&time_modified.lt=' + currentDate)
        .set(constants.headers)
        .then((res, err) => {
          expect(err).to.be.undefined
          expect(res).to.have.status(200)

          // Check that we're not on the first page
          expect(res.body.hasNext).to.be.true
          expect(res.body.hasPrevious).to.be.true

          // Store records from page 2
          pageTwoRec1 = res.body.cveRecords[0]
          pageTwoRec2 = res.body.cveRecords[1]
          prev = res.body.previous
        })

      // Modify page 1 CVE record, which would remove it, but data should not be moved
      await helpers.cveUpdateAsSecHelper(pageOneRec1.cveMetadata.cveId, constants.testCve)

      // Request page 2 again using same next_page string, should see no change in results
      await requester.get('/api/cve_cursor?limit=2&next_page=' + next + '&time_modified.lt=' + currentDate)
        .set(constants.headers)
        .then((res, err) => {
          expect(err).to.be.undefined
          expect(res).to.have.status(200)

          expect(res.body.cveRecords[0]).to.deep.equal(pageTwoRec1)
          expect(res.body.cveRecords[1]).to.deep.equal(pageTwoRec2)
        })

      // Request page 1 again using prev_page string from first page 2 request, should have 1 record because modified one is filtered out
      await requester.get('/api/cve_cursor?limit=2&previous_page=' + prev + '&time_modified.lt=' + currentDate)
        .set(constants.headers)
        .then((res, err) => {
          expect(err).to.be.undefined
          expect(res).to.have.status(200)

          expect(res.body.cveRecords.length).to.equal(1)
          expect(res.body.cveRecords[0]).to.deep.equal(pageOneRec2)
        })

      // Request page 1 again without next/prev, should see 2 records, record from page 2 shifted over
      await requester.get('/api/cve_cursor?limit=2&time_modified.lt=' + currentDate)
        .set(constants.headers)
        .then((res, err) => {
          expect(err).to.be.undefined
          expect(res).to.have.status(200)
          expect(res.body.cveRecords.length).to.equal(2)

          // Newly created record appears at the front, shifting other records
          expect(res.body.cveRecords[0]).to.deep.equal(pageOneRec2)
          expect(res.body.cveRecords[1]).to.deep.equal(pageTwoRec1)
        })

      requester.close()
    }).timeout(1000000)
  })
})
