const express = require('express')
const router = express.Router()
const db = require('qmi-cloud-common/mongo');
const passport = require('../passport');
const fs = require('fs-extra');
const azurecli = require('qmi-cloud-common/azurecli');

import { queues, TF_APPLY_QUEUE, TF_APPLY_QSEOK_QUEUE, TF_DESTROY_QUEUE } from 'qmi-cloud-common/queues';

/**
 * @swagger
 * /users:
 *    get:
 *      description: Get all users
 *      summary: Get all users
 *      tags:
 *        - admin
 *      produces:
 *        - application/json
 *      responses:
 *        200:
 *          description: User
 */
router.get('/', passport.ensureAuthenticatedAndAdmin, async (req, res, next) => {
  try {
    const result = await db.user.get();
    return res.json(result);
  } catch (error) {
    next(error);
  }
});

/**
 * @swagger
 * /users/me:
 *    get:
 *      description: Get profile logged-in user
 *      summary: Get logged-in user
 *      produces:
 *        - application/json
 *      responses:
 *        200:
 *          description: User
 */
router.get('/me', passport.ensureAuthenticated, async (req, res, next) => {
  try {
    const result = await db.user.getById(req.user._id);
    return res.json(result);
  } catch (error) {
    next(error);
  }
});

/**
 * @swagger
 * /users/{userId}:
 *    get:
 *      description: Get profile for an user
 *      summary: Get profile for an user
 *      parameters:
 *        - name: userId
 *          in: path
 *          type: string
 *          required: true
 *      produces:
 *        - application/json
 *      responses:
 *        200:
 *          description: User
 */
router.get('/:userId', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
  try {
    const result = await db.user.getById(req.params.userId);
    return res.json(result);
  } catch (error) {
    next(error);
  }
});

/**
 * @swagger
 * /users/{userId}:
 *    put:
 *      description: Update profile for an user
 *      summary: Update profile for an user
 *      tags:
 *        - admin
 *      parameters:
 *        - name: userId
 *          in: path
 *          type: string
 *          required: true
 *        - in: body
 *          name: body
 *          description: User object
 *          required: true
 *      produces:
 *        - application/json
 *      responses:
 *        200:
 *          description: User
 */
router.put('/:userId', passport.ensureAuthenticatedAndAdmin, async (req, res, next) => {

  try {
    const result = await db.user.update(req.params.userId, req.body);
    return res.json(result);
  } catch (error) {
    next(error);
  }
});


/**
 * @swagger
 * /users/{userId}/provisions:
 *    post:
 *      description: Start a new Terraform provision
 *      summary: Start a new Terraform provision
 *      produces:
 *        - application/json
 *      parameters:
 *        - name: userId
 *          in: path
 *          type: string
 *          required: true
 *      requestBody:
 *        required: true
 *        content:
 *          application/json:
 *            schema:
 *              type: object
 *              properties:
 *                scenario:
 *                  type: string
 *                description:
 *                  type: string
 *                vmImage:
 *                  type: object
 *                  properties:
 *                    vm1:
 *                      type: object
 *                      properties:
 *                        vmType:
 *                          type: string
 *                        version:
 *                          type: object
 *                          properties:
 *                            name:
 *                              type: string
 *                            image:
 *                              type: string
 *      responses:
 *        200:
 *          description: Provision
 *        404:
 *          description: Scenario not found
 *        400:
 *          description: Invalid vmImage
 */
router.post('/:userId/provisions', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
  try {
    
    req.body.user = req.params.userId;
    const scenarioSource = await db.scenario.getOne({name: req.body.scenario});

    if (!scenarioSource) {
      return res.status(404).json({"msg": "Scenario not found "});
    }

    if (!req.body.vmImage || !req.body.vmImage.vm1 || !req.body.vmImage.vm1.vmType ) {
      return res.status(400).json({"msg": "Invalid vmImage"});
    }
    req.body.scenarioVersion = scenarioSource.version;
    const mongoJob = await db.provision.add(req.body);
    
    
    if ( mongoJob.scenario === "azqmi-qseok" ){
      queues[TF_APPLY_QSEOK_QUEUE].add("tf_apply_qseok_job", {
        scenario: req.body.scenario,
        vmType: req.body.vmType,
        nodeCount: req.body.nodeCount,
        id: mongoJob._id,
        user: req.user,
        _scenario: scenarioSource
      });
    } else {
      queues[TF_APPLY_QUEUE].add("tf_apply_job", {
        scenario: req.body.scenario,
        vmType: req.body.vmType,
        nodeCount: req.body.nodeCount,
        id: mongoJob._id,
        user: req.user,
        _scenario: scenarioSource
      });
    }

    return res.status(200).json(mongoJob);

  } catch (error) {
    next(error);
  }
});

/**
 * @swagger
 * /users/{userId}/provisions/{id}:
 *    delete:
 *      description: Delete Provision by ID 
 *      summary: Delete a Terraform Provision by ID
 *      produces:
 *        - application/json
 *      parameters:
 *        - name: userId
 *          in: path
 *          type: string
 *          required: true
 *        - name: id
 *          in: path
 *          type: string
 *          required: true
 *      responses:
 *        200:
 *          description: Provision
 *        404:
 *          description: Not found
 *        
 */
router.delete('/:userId/provisions/:id', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
    try {

      const mongoJob = await db.provision.getById(req.params.id);
      if (!mongoJob){
        return res.status(404).json({"msg": "Not found privision with id "+req.params.id});
      }
      //var delDest = mongoJob.destroy._id;
      //if ( mongoJob.destroy ) {
      //  delDest = await db.destroy.del(mongoJob.destroy._id);
      //}
      const delProv = await db.provision.update(req.params.id, {"isDeleted": true});

      //Move folder 
      if (fs.existsSync(`/provisions/${mongoJob.scenario}_${req.params.id}`)) {
        fs.moveSync(`/provisions/${mongoJob.scenario}_${req.params.id}`, `/provisions/deleted/${mongoJob.scenario}_${req.params.id}`, { overwrite: true })
      }
      return res.json({"provision": delProv, "destroy": delProv.destroy});
    } catch (error) {
      next(error);
    }
  });

/**
 * @swagger
 * /users/{userId}/provisions/{id}/deallocatevms:
 *    post:
 *      description: Stop all VMs for this provision
 *      summary: Stop all VMs for this provision
 *      produces:
 *        - application/json
 *      parameters:
 *        - name: userId
 *          in: path
 *          type: string
 *          required: true
 *        - name: id
 *          in: path
 *          type: string
 *          required: true
 *      responses:
 *        200:
 *          description: Provision
 *        404:
 *          description: Not found
 *        
 */
router.post('/:userId/provisions/:id/deallocatevms', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
  try {

    let mongoJob = await db.provision.getById(req.params.id);
    if (!mongoJob){
      return res.status(404).json({"msg": "Not found provision with id "+req.params.id});
    }
    azurecli.deallocate(mongoJob);
    return res.json({"statusVms": "Stopping"});

  } catch (error) {
    db.provision.update(req.params.id, {"statusVms": "Error_Stopping"});
    next(error);
  }
});

/**
 * @swagger
 * /users/{userId}/provisions/{id}/startvms:
 *    post:
 *      description: Start all VMs for this provision
 *      summary: Start all VMs for this provision
 *      produces:
 *        - application/json
 *      parameters:
 *        - name: userId
 *          in: path
 *          type: string
 *          required: true
 *        - name: id
 *          in: path
 *          type: string
 *          required: true
 *      responses:
 *        200:
 *          description: Provision
 *        404:
 *          description: Not found
 *        
 */
router.post('/:userId/provisions/:id/startvms', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
  try {

    let mongoJob = await db.provision.getById(req.params.id);
    if (!mongoJob){
      return res.status(404).json({"msg": "Not found privision with id "+req.params.id});
    }
    
    azurecli.start(mongoJob);
    return res.json({"statusVms": "Starting"});

  } catch (error) {
    db.provision.update(req.params.id, {"statusVms": "Error_Starting"});
    next(error);
  }
});

/**
 * @swagger
 * /users/{userId}/provisions/{id}/extend:
 *    post:
 *      description: Extend this provision Running more time
 *      summary: Extend this provision Running more time
 *      produces:
 *        - application/json
 *      parameters:
 *        - name: userId
 *          in: path
 *          type: string
 *          required: true
 *        - name: id
 *          in: path
 *          type: string
 *          required: true
 *      responses:
 *        200:
 *          description: Provision
 *        404:
 *          description: Not found
 *        
 */
router.post('/:userId/provisions/:id/extend', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
  try {

    let mongoJob = await db.provision.getById(req.params.id);
    if (!mongoJob){
      return res.status(404).json({"msg": "Not found privision with id "+req.params.id});
    }
    
    /*if ( mongoJob.countExtend === 5 ) {
      return res.status(200).json({"msg": "You have reached the limit for the number of times to extend the Running VMs period."});
    }*/

    let timeRunning = db.utils.getNewTimeRunning(mongoJob);
    let countExtend = db.utils.getNewCountExtend(mongoJob);
    mongoJob = await db.provision.update(req.params.id, {"runningFrom":new Date(), "timeRunning": timeRunning, "countExtend": countExtend, "pendingNextAction": undefined});
    
    return res.json(mongoJob);

  } catch (error) {
    next(error);
  }
});

/**
 * @swagger
 * /users/{userId}/provisions/{id}/destroy:
 *    post:
 *      description: Destroy a Terraform Provision
 *      summary: Destroy a Terraform Provision
 *      produces:
 *        - application/json
 *      parameters:
 *        - name: userId
 *          in: path
 *          type: string
 *          required: true
 *        - name: id
 *          in: path
 *          type: string
 *          required: true
 *      responses:
 *        200:
 *          description: Provision
 *        404:
 *          description: Not found
 *        
 */
router.post('/:userId/provisions/:id/destroy', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
  
  try {
    
    let mongoJob = await db.provision.getById(req.params.id);
    if (!mongoJob){
      return res.status(404).json({"msg": "Not found privision with id "+req.params.id});
    }

    const destroyJob = await db.destroy.add({ "user": req.params.userId });
    mongoJob = await db.provision.update(req.params.id, {"destroy": destroyJob._id});
    const scenarioSource = await db.scenario.getOne({name: mongoJob.scenario});

    queues[TF_DESTROY_QUEUE].add("tf_destroy_job", {
      scenario: mongoJob.scenario,
      provId: mongoJob._id,
      user: req.user,
      id: destroyJob._id,
      _scenario: scenarioSource
    });

    return res.status(200).json(mongoJob);

  } catch (error) {
    return res.status(error.output.statusCode).json({"err":error});
  }
});

/**
 * @swagger
 * /users/{userId}/provisions:
 *    get:
 *      description: Get all Provisions for an User
 *      summary: Get all Provisions for an User
 *      produces:
 *        - application/json
 *      parameters:
 *        - name: userId
 *          in: path
 *          type: string
 *          required: true
 *      responses:
 *        200:
 *          description: JSON Array
 */
router.get('/:userId/provisions', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {

  try {
    const filter = {"user": req.params.userId, "isDeleted": false};
    const result = await db.provision.get(filter);
    return res.json(result);
  } catch (error) {
    next(error);
  }
});


/**
 * @swagger
 * /users/{userId}/destroyprovisions:
 *    get:
 *      description: Get all Destroy Provisions for an User
 *      summary: Get all Destroy Provisions for an User
 *      produces:
 *        - application/json
 *      parameters:
 *        - name: userId
 *          in: path
 *          type: string
 *          required: true
 *      responses:
 *        200:
 *          description: JSON Array
 */
router.get('/:userId/destroyprovisions', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {

  try {
    const result = await db.destroy.get({"user": req.params.userId});
    return res.json(result);
  } catch (error) {
    next(error);
  }
});


module.exports = router;