const express = require('express')
const router = express.Router()
const mw = require('../../middleware/middleware')
const errorMsgs = require('../../middleware/errorMessages')
const controller = require('./cve-id.controller')
const { param, query } = require('express-validator')
const { parseGetParams, parsePostParams, parseError } = require('./cve-id.middleware')
const getConstants = require('../../constants').getConstants
const CONSTANTS = getConstants()
const toDate = require('../../utils/utils').toDate

const CHOICES = [CONSTANTS.CVE_STATES.REJECTED, CONSTANTS.CVE_STATES.PUBLISHED, CONSTANTS.CVE_STATES.RESERVED]
const MODIFYTARGETS = [CONSTANTS.CVE_STATES.REJECTED, CONSTANTS.CVE_STATES.RESERVED]

router.get('/cve-id',
  /*
  #swagger.tags = ['CVE ID']
  #swagger.operationId = 'cveIdGetFiltered'
  #swagger.summary = "Retrieves information about CVE IDs after applying the query parameters as filters (accessible to all registered users)"
  #swagger.description = "
        <h2>Access Control</h2>
        <p>All registered users can access this endpoint</p>
        <h2>Expected Behavior</h2>
        <p><b>Regular, CNA & Admin Users:</b> Retrieves filtered CVE IDs owned by the user's organization</p>
        <p><b>Secretariat:</b> Retrieves filtered CVE IDs owned by any organization</p>
  #swagger.parameters['$ref'] = [
    '#/components/parameters/cveIdGetFilteredState',
    '#/components/parameters/cveIdGetFilteredCveIdYear',
    '#/components/parameters/cveIdGetFilteredTimeReservedLt',
    '#/components/parameters/cveIdGetFilteredTimeReservedGt',
    '#/components/parameters/cveIdGetFilteredTimeModifiedLt',
    '#/components/parameters/cveIdGetFilteredTimeModifiedGt',
    '#/components/parameters/pageQuery',
    '#/components/parameters/apiEntityHeader',
    '#/components/parameters/apiUserHeader',
    '#/components/parameters/apiSecretHeader'
  ]
  #swagger.responses[200] = {
    description: 'A filtered list of information about CVE IDs owned by the organization, along with pagination fields if results span multiple pages of data',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/cve-id/list-cve-ids-response.json' }
      }
    }
  }
  #swagger.responses[400] = {
    description: 'Bad Request',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/bad-request.json' }
      }
    }
  }
  #swagger.responses[401] = {
    description: 'Not Authenticated',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[403] = {
    description: 'Forbidden',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[404] = {
    description: 'Not Found',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[500] = {
    description: 'Internal Server Error',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  */
  mw.validateUser,
  query().custom((query) => { return mw.validateQueryParameterNames(query, ['page', 'state', 'cve_id_year', 'time_reserved.lt', 'time_reserved.gt', 'time_modified.lt', 'time_modified.gt']) }),
  query(['page']).optional().isInt({ min: CONSTANTS.PAGINATOR_PAGE }),
  query(['state']).optional().isString().trim().escape().customSanitizer(val => { return val.toUpperCase() }).isIn(CHOICES).withMessage(errorMsgs.ID_STATES),
  query(['cve_id_year']).optional().isNumeric().matches(/^[0-9]{4}$/),
  query(['time_reserved.lt']).optional().isString().trim().escape().customSanitizer(val => { return toDate(val) }).not().isEmpty().withMessage(errorMsgs.TIMESTAMP_FORMAT),
  query(['time_reserved.gt']).optional().isString().trim().escape().customSanitizer(val => { return toDate(val) }).not().isEmpty().withMessage(errorMsgs.TIMESTAMP_FORMAT),
  query(['time_modified.lt']).optional().isString().trim().escape().customSanitizer(val => { return toDate(val) }).not().isEmpty().withMessage(errorMsgs.TIMESTAMP_FORMAT),
  query(['time_modified.gt']).optional().isString().trim().escape().customSanitizer(val => { return toDate(val) }).not().isEmpty().withMessage(errorMsgs.TIMESTAMP_FORMAT),
  parseError,
  parseGetParams,
  controller.CVEID_GET_FILTER)

router.post('/cve-id',
  /*
  #swagger.tags = ['CVE ID']
  #swagger.operationId = 'cveIdReserve'
  #swagger.summary = "Reserves CVE IDs for the organization provided in the short_name query parameter (accessible to CNAs and Secretariat)"
  #swagger.description = "
  <h2>Access Control</h2>
        <p>User must belong to an organization with the <b>CNA</b> or <b>Secretariat</b> role</p>
        <h2>Expected Behavior</h2>
        <p><b>CNA:</b> Reserves CVE IDs for the CNA</p>
        <p><b>Secretariat:</b> Reserves CVE IDs for any organization</p>"
  #swagger.parameters['$ref'] = [
    '#/components/parameters/amount',
    '#/components/parameters/batch_type',
    '#/components/parameters/cve_year',
    '#/components/parameters/short_name',
    '#/components/parameters/apiEntityHeader',
    '#/components/parameters/apiUserHeader',
    '#/components/parameters/apiSecretHeader'
  ]
  #swagger.responses[200] = {
    description: 'A list of the newly reserved CVE IDs',
    content: {
      'application/json': {
        schema: { $ref: '../schemas/cve-id/create-cve-ids-response.json' }
      }
    }
  }
  #swagger.responses[206] = {
    description: 'A partial list of the CVE IDs the IDR service managed to reserve before encountering a case where no more CVE IDs could be reserved',
    content: {
      'application/json': {
        schema: { $ref: '../schemas/cve-id/create-cve-ids-partial-response.json' }
      }
    }
  }
  #swagger.responses[400] = {
    description: 'Bad Request',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/bad-request.json' }
      }
    }
  }
  #swagger.responses[401] = {
    description: 'Not Authenticated',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[403] = {
    description: 'Forbidden',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[404] = {
    description: 'Not Found',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[500] = {
    description: 'Internal Server Error',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  */
  mw.validateUser,
  mw.onlyCnas,
  query().custom((query) => { return mw.validateQueryParameterNames(query, ['amount', 'batch_type', 'short_name', 'cve_year']) }),
  query(['amount']).isInt(),
  query(['batch_type']).optional().isString().trim().escape().customSanitizer(val => { return val.toLowerCase() }),
  query(['short_name']).isString().trim().escape().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }),
  query(['cve_year']).isNumeric().matches(/^[0-9]{4}$/),
  parseError,
  parsePostParams,
  controller.CVEID_RESERVE)

router.get('/cve-id/:id',
  /*
  #swagger.tags = ['CVE ID']
  #swagger.operationId = 'cveIdGetSingle'
  #swagger.summary = "Retrieves information about the specified CVE ID (accessible to all users)"
  #swagger.description = "
        <h2>Access Control</h2>
        <p>Endpoint is accessible to all</p>
        <h2>Expected Behavior</h2>
        <p><b>Regular, CNA & Admin Users: </b>Retrieves full information about a CVE ID owned by their organization; partial information about a CVE ID owned by other organizations</p>
        <p><b>Unauthenticated Users: </b>Retrieves partial information about a CVE ID
        <p><b>Secretariat: </b>Retrieves full information about a CVE ID owned by any organization</p>
        <p><i><b>Note - </b>The owning organization of RESERVED CVE IDs is redacted for all users other than those in the owning organization or Secretariat</i></p>
  #swagger.parameters['id'] = { description: 'The id of the CVE ID information to retrieve' }
  #swagger.parameters['$ref'] = [
    '#/components/parameters/apiEntityHeader',
    '#/components/parameters/apiUserHeader',
    '#/components/parameters/apiSecretHeader'
  ]
  #swagger.responses[200] = {
    description: 'The requested CVE ID information is returned',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/cve-id/get-cve-id-response.json' }
      }
    }
  }
  #swagger.responses[400] = {
    description: 'Bad Request',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/bad-request.json' }
      }
    }
  }
  #swagger.responses[401] = {
    description: 'Not Authenticated',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[403] = {
    description: 'Forbidden',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[404] = {
    description: 'Not Found',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[429] = {
    description: 'Too Many Requests',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[500] = {
    description: 'Internal Server Error',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  */
  mw.rateLimiter,
  mw.optionallyValidateUser,
  param(['id']).isString().matches(CONSTANTS.CVE_ID_REGEX),
  parseError,
  parseGetParams,
  controller.CVEID_GET_SINGLE)

router.put('/cve-id/:id',
  /*
  #swagger.tags = ['CVE ID']
  #swagger.operationId = 'cveIdUpdateSingle'
  #swagger.summary = "Updates information related to the specified CVE ID (accessible to CNAs and Secretariat)"
  #swagger.description = "
        <h2>Access Control</h2>
        <p>User must belong to an organization with the <b>CNA</b> or <b>Secretariat</b> role</p>
        <h2>Expected Behavior</h2>
        <p><b>CNA:</b> Updates information related to a CVE ID owned by the CNA</p>
        <p><b>Secretariat:</b> Updates a CVE ID owned by any organization</p>"
  #swagger.parameters['id'] = { description: 'The id of the CVE ID to update' }
  #swagger.parameters['$ref'] = [
    '#/components/parameters/org`,
    '#/components/parameters/state',
    '#/components/parameters/apiEntityHeader',
    '#/components/parameters/apiUserHeader',
    '#/components/parameters/apiSecretHeader'
  ]
  #swagger.responses[200] = {
    description: 'The updated CVE ID information is returned',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/cve-id/update-cve-id-response.json' }
      }
    }
  }
  #swagger.responses[400] = {
    description: 'Bad Request',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/bad-request.json' }
      }
    }
  }
  #swagger.responses[401] = {
    description: 'Not Authenticated',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[403] = {
    description: 'Forbidden',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[404] = {
    description: 'Not Found',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[500] = {
    description: 'Internal Server Error',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  */
  mw.validateUser,
  mw.onlyCnas,
  param(['id']).isString().matches(CONSTANTS.CVE_ID_REGEX),
  query().custom((query) => { return mw.validateQueryParameterNames(query, ['state', 'org']) }),
  query(['state']).optional().isString().trim().escape().customSanitizer(val => { return val.toUpperCase() }).isIn(MODIFYTARGETS).withMessage(errorMsgs.ID_MODIFY_STATES),
  query(['org']).optional().isString().trim().escape(),
  parseError,
  parsePostParams,
  mw.cnaMustOwnID,
  controller.CVEID_UPDATE_SINGLE)

router.post('/cve-id-range/:year',
  /*
  #swagger.tags = ['CVE ID']
  #swagger.operationId = 'cveIdRangeCreate'
  #swagger.summary = "Creates a CVE-ID-Range for the specified year (accessible to Secretariat)"
  #swagger.description = "
        <h2>Access Control</h2>
        <p>User must belong to an organization with the <b>Secretariat</b> role</p>
        <h2>Expected Behavior</h2>
        <p><b>Secretariat:</b> Creates a CVE-ID-Range for the specified year</p>"
  #swagger.parameters['year'] = {
    description: 'The year of the CVE-ID-Range',
    schema: {
      type: 'integer'
    }
  }
  #swagger.parameters['$ref'] = [
    '#/components/parameters/apiEntityHeader',
    '#/components/parameters/apiUserHeader',
    '#/components/parameters/apiSecretHeader'
  ]
  #swagger.responses[200] = {
    description: 'The CVE-ID-Range was created',
  }
  #swagger.responses[400] = {
    description: 'Bad Request',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/bad-request.json' }
      }
    }
  }
  #swagger.responses[401] = {
    description: 'Not Authenticated',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[403] = {
    description: 'Forbidden',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[404] = {
    description: 'Not Found',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[500] = {
    description: 'Internal Server Error',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  */
  mw.validateUser,
  mw.onlySecretariat,
  param(['year']).isNumeric().matches(/^[0-9]{4}$/),
  parseError,
  parsePostParams,
  controller.CVEID_RANGE_CREATE)

module.exports = router
