import express from 'express';
import _ from 'lodash';

import TemplateValidate from './validate/template';
import TemplateTreatmentModel from '../models/treatment_template';
import TemplateMeasurementModel from '../models/measurement_template';
import res400 from './validate/res400';
import IdValidate from './validate/id';

// TODO: remove f() for await

const router = express.Router();

router.get('/template/:collection(measurements|treatments)', (req, res, next) => {
  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;

  req.params.collection = req.params.collection.replace(/s$/g, '');
  model(req).find({}).lean().exec((err, data) => {
     if (err) next (err);
     res.json(_.compact(data.map(e => TemplateValidate.output(e, req.params.collection))));  // validate all and filter null values from validation errors
  });
});

router.get('/template/:collection(measurement|treatment)/' + IdValidate.parameter(), (req, res, next) => {
  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;

  model(req).findById(req.params.id).lean().exec((err, data) => {
    if (err) next (err);
    if (data) {
      res.json(TemplateValidate.output(data, req.params.collection));
    }
    else {
      res.status(404).json({status: 'Not found'});
    }
  });
});

router.put('/template/:collection(measurement|treatment)/' + IdValidate.parameter(), async (req, res, next) => {
  if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;

  const {error, value: template} = TemplateValidate.input(req.body, 'change', req.params.collection);
  if (error) return res400(error, res);

  const templateData = await model(req).findById(req.params.id).lean().exec().catch(err => {next(err);}) as any;
  if (templateData instanceof Error) return;
  if (!templateData) {
    res.status(404).json({status: 'Not found'});
  }

  if (_.has(template, 'number_prefix') && template.number_prefix !== templateData.number_prefix) {  // got new number_prefix
    if (!await numberPrefixCheck(template, req, res, next)) return;
  }

  if (!_.isEqual(_.pick(templateData, _.keys(template)), template)) {  // data was changed
    template.version = templateData.version + 1;
    await new (model(req))(_.assign({}, _.omit(templateData, ['_id', '__v']), template)).save((err, data) => {
      if (err) next (err);
      res.json(TemplateValidate.output(data.toObject(), req.params.collection));
    });
  }
  else {
    res.json(TemplateValidate.output(templateData, req.params.collection));
  }
});

// router.delete('/template/:collection(measurement|treatment)/:name', (req, res, next) => {
//   if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
//
//   (req.params.collection === 'treatment' ? TemplateTreatmentModel : TemplateMeasurementModel)
//     .findOneAndDelete({name: req.params.name}).lean().exec((err, data) => {
//     if (err) return next(err);
//     if (data) {
//       res.json({status: 'OK'})
//     }
//     else {
//       res.status(404).json({status: 'Not found'});
//     }
//   });
// });


module.exports = router;


async function numberPrefixCheck (template, req, res, next) {
  const data = await model(req).findOne({number_prefix: template.number_prefix}).lean().exec().catch(err => {next(err); return false;}) as any;
  if (data) {
    res.status(400).json({status: 'Number prefix already taken'});
    return false
  }
  return true;
}

function model (req) {
  return req.params.collection === 'treatment' ? TemplateTreatmentModel : TemplateMeasurementModel;
}