/* eslint-disable no-unused-expressions */
const chai = require('chai')
chai.use(require('chai-http'))
const expect = chai.expect
const { faker } = require('@faker-js/faker')

const constants = require('../constants.js')
const app = require('../../../src/index.js')
const getConstants = require('../../../src/constants').getConstants
const argon2 = require('argon2')
const _ = require('lodash')
const User = require('../../../src/model/user')
const cryptoRandomString = require('crypto-random-string')

const shortName = { shortname: 'win_5' }

describe('Testing user post endpoint', () => {
  let orgUuid
  context('Positive Tests', () => {
    it('Allows creation of user', async () => {
      await chai.request(app)
        .post('/api/org/win_5/user')
        .set({ ...constants.headers, ...shortName })
        .send({
          username: 'fakeuser999',
          name: {
            first: 'Dave',
            last: 'FakeLastName',
            middle: 'Cool',
            suffix: 'Mr.'
          },
          authority: {
            active_roles: [
              'ADMIN'
            ]
          }
        })
        .then((res, err) => {
          expect(err).to.be.undefined
          orgUuid = res.body.created.org_UUID
        })
    })
  })
  context('Negitive Test', () => {
    it('Fails creation of user for bad long first name', async () => {
      await chai.request(app)
        .post('/api/org/win_5/user')
        .set({ ...constants.headers, ...shortName })
        .send({
          username: 'fakeuser9999',
          name: {
            first: 'VerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnm1',
            last: 'FakeLastName',
            middle: 'Cool',
            suffix: 'Mr.'
          },
          authority: {
            active_roles: [
              'ADMIN'
            ]
          }
        })
        .then((res, err) => {
          expect(res).to.have.status(400)
          expect(_.some(res.body.details, { msg: 'Invalid name.first. Name must be between 1 and 100 characters in length.' })).to.be.true
          expect(err).to.be.undefined
        })
    })
    it('Fails creation of user for bad long last name', async () => {
      await chai.request(app)
        .post('/api/org/win_5/user')
        .set({ ...constants.headers, ...shortName })
        .send({
          username: 'fakeuser1000',
          name: {
            first: 'FirstName',
            last: 'VerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnm1',
            middle: 'Cool',
            suffix: 'Mr.'
          },
          authority: {
            active_roles: [
              'ADMIN'
            ]
          }
        })
        .then((res, err) => {
          expect(res).to.have.status(400)
          expect(_.some(res.body.details, { msg: 'Invalid name.last. Name must be between 1 and 100 characters in length.' })).to.be.true
          expect(err).to.be.undefined
        })
    })
    it('Fails creation of user for bad long middle name', async () => {
      await chai.request(app)
        .post('/api/org/win_5/user')
        .set({ ...constants.headers, ...shortName })
        .send({
          username: 'fakeuser1001',
          name: {
            first: 'FirstName',
            last: 'LastName',
            middle: 'VerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnm1',
            suffix: 'Mr.'
          },
          authority: {
            active_roles: [
              'ADMIN'
            ]
          }
        })
        .then((res, err) => {
          expect(res).to.have.status(400)
          expect(_.some(res.body.details, { msg: 'Invalid name.middle. Name must be between 1 and 100 characters in length.' })).to.be.true
          expect(err).to.be.undefined
        })
    })
    it('Fails creation of user for bad long suffix name', async () => {
      await chai.request(app)
        .post('/api/org/win_5/user')
        .set({ ...constants.headers, ...shortName })
        .send({
          username: 'fakeuser1002',
          name: {
            first: 'FirstName',
            last: 'LastName',
            middle: 'MiddleName',
            suffix: 'VerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnm1'
          },
          authority: {
            active_roles: [
              'ADMIN'
            ]
          }
        })
        .then((res, err) => {
          expect(res).to.have.status(400)
          expect(_.some(res.body.details, { msg: 'Invalid name.suffix. Name must be between 1 and 100 characters in length.' })).to.be.true
          expect(err).to.be.undefined
        })
    })
    it('Fails creation of user for trying to add the 101th user', async () => {
      const numberOfUsers = await User.where({ org_UUID: orgUuid }).countDocuments().exec()
      for (let i = 0; i < (100 - numberOfUsers); i++) {
        const newUser = new User()

        newUser.name.first = faker.name.firstName()
        newUser.name.last = faker.name.lastName()
        newUser.username = faker.internet.userName({ firstName: newUser.name.first, lastName: newUser.name.last })
        newUser.org_UUID = orgUuid
        newUser.UUID = faker.datatype.uuid()
        const randomKey = cryptoRandomString({ length: getConstants().CRYPTO_RANDOM_STRING_LENGTH })
        newUser.secret = await argon2.hash(randomKey)

        newUser.authority = {
          active_roles: [
            'ADMIN'
          ]
        }

        await User.findOneAndUpdate().byUserNameAndOrgUUID(newUser.userName, newUser.org_UUID).updateOne(newUser).setOptions({ upsert: true })
      }

      await chai.request(app)
        .post('/api/org/win_5/user')
        .set({ ...constants.headers, ...shortName })
        .send({
          username: 'Fake101User',
          name: {
            first: 'Dave',
            last: 'FakeLastName',
            middle: 'Cool',
            suffix: 'Mr.'
          },
          authority: {
            active_roles: [
              'ADMIN'
            ]
          }
        })
        .then((res, err) => {
          expect(err).to.be.undefined
          expect(res).to.have.status(400)
          expect(res.body.error).to.contain('NUMBER_OF_USERS_IN_ORG_LIMIT_REACHED')
        })
    })
  })
})
