"use strict";

var config = require('config');
const db = require('../../models/db');
const uuidv4 = require('uuid/v4');
const os = require('os');

var mailer = require('../../helpers/mailer');
var uploader = require('../../helpers/uploader');
var importer = require('../../helpers/importer');

var bcrypt = require('bcryptjs');
var crypto = require('crypto');
var swig = require('swig');
var async = require('async');
var _ = require('underscore');
var fs = require('fs');
var request = require('request');
var gm = require('gm');
var validator = require('validator');
var URL = require('url').URL;

var express = require('express');
var router = express.Router();
var glob = require('glob');

router.get('/current', function(req, res, next) {
  if (req.user) {
    var u = _.clone(req.user.dataValues);
    delete u.password_hash;
    delete u.password_reset_token;
    delete u.confirmation_token;
    u.token = req.cookies['sdsession'];

    console.log(u);
    
    res.status(200).json(u);
  } else {
    res.status(401).json({"error":"user_not_found"});
  }
});

// create user
router.post('/', function(req, res) {
  if (!req.body["email"] || !req.body["password"]) {
    res.status(400).json({"error":"email or password missing"});
    return;
  }
  
  var email = req.body["email"].toLowerCase();
  var nickname = req.body["nickname"];
  var password = req.body["password"];
  var password_confirmation = req.body["password_confirmation"];
  var invite_code = req.body["invite_code"];

  if (password_confirmation != password) {
    res.status(400).json({"error":"password_confirmation"});
    return;
  }
  
  if (config.invite_code && invite_code != config.invite_code) {
    res.status(400).json({"error":"Invalid Invite Code."});
    return;
  }
  
  if (!validator.isEmail(email)) {
    res.status(400).json({"error":"email_invalid"});
    return;
  }
  
  var createUser = function() {
    bcrypt.genSalt(10, function(err, salt) {
      bcrypt.hash(password, salt, function(err, hash) {
        crypto.randomBytes(16, function(ex, buf) {
          var token = buf.toString('hex');

          var u = {
            _id: uuidv4(),
            email: email,
            account_type: "email",
            nickname: nickname,
            password_hash: hash,
            prefs_language: req.i18n.locale,
            confirmation_token: token
          };

          db.User.create(u)
            .error(err => {
              res.sendStatus(400);
            })
            .then(u => {
              var homeFolder = {
                _id: uuidv4(),
                name: req.i18n.__("home"),
                space_type: "folder",
                creator_id: u._id
              };
              db.Space.create(homeFolder)
                .error(err => {
                  res.sendStatus(400);
                })
                .then(homeFolder => {
                  u.home_folder_id = homeFolder._id;
                  u.save()
                    .then(() => {
                      // home folder created,
                      // auto accept pending invites
                      db.Membership.update({
                        "state": "active"
                      }, {
                        where: {
                          "email_invited": u.email,
                          "state": "pending"
                        }
                      });
                      res.status(201).json({});          
                    })
                    .error(err => {
                      res.status(400).json(err);
                    });
                })
            });
        });
      });
    });
  };
  
  db.User.findAll({where: {email: email}})
    .then(users => {
      if (users.length == 0) {
        createUser();
      } else {
        res.status(400).json({"error":"user_email_already_used"});
      }
    })
});

router.get('/current', function(req, res, next) {
  if (req.user) {
    res.status(200).json(req.user);
  } else {
    res.status(401).json({"error":"user_not_found"});
  }
});

router.put('/:id', function(req, res, next) {
  // TODO explicit whitelisting
  var user = req.user;
  if (user._id == req.params.id) {
    var newAttr = req.body;
    newAttr.updated_at = new Date();
    delete newAttr['_id'];

    db.User.update(newAttr, {where: {"_id": user._id}}).then(function(updatedUser) {
      res.status(200).json(newAttr);
    });
  } else {
    res.sendStatus(403);
  }
});

router.post('/:id/password', function(req, res, next) {
  var user = req.user;
  var old_password = req.body.old_password;
  var pass = req.body.new_password;

  if (pass.length >= 6) {
    if (user._id == req.params.id) {
      if (bcrypt.compareSync(old_password, user.password_hash)) {
        bcrypt.genSalt(10, function(err, salt) {
          bcrypt.hash(pass, salt, function(err, hash) {
            user.password_hash = hash;
            user.save().then(function() {
              res.sendStatus(204);
            });
          });
        });
      } else {
        res.status(403).json({"error": "Please enter the correct current password."});
      }
    } else {
      res.status(403).json({"error": "Access denied."});
    }
  } else {
    res.status(400).json({"error": "Please choose a new password with at least 6 characters."});
  }
});

router.delete('/:id',  (req, res, next) => {
  const user = req.user;
  if (user._id == req.params.id) {
    if (bcrypt.compareSync(req.query.password, user.password_hash)) {

      // TODO: this doesn't currently work.
      // all objects (indirectly) belonging to the user have
      // to be walked and deleted first.
      
      user.destroy().then(err => {
        if(err)res.status(400).json(err);
        else res.sendStatus(204);
      });
    } else {
      res.bad_request("Please enter the correct current password.");
    }
  } else {
    res.status(403).json({error: "Access denied."});
  }
});

router.put('/:user_id/confirm', (req, res) => {
  const token = req.body.token;
  const user = req.user;

  if (user.confirmation_token === token) {
    user.confirmation_token = null;
    user.confirmed_at = new Date();
    user.save(function(err, updatedUser) {
      if(err) {
        res.sendStatus(400);
      } else {
        res.status(200).json(updatedUser);
      }
    });
  } else {
    res.sendStatus(400);
  }
});

router.post('/:user_id/avatar', (req, res, next) => {
  const user = req.user;
  const filename = "u"+req.user._id+"_"+(new Date().getTime())+".jpeg"

  const localFilePath = os.tmpdir()+"/"+filename;
  const localResizedFilePath = os.tmpdir()+"/resized_"+filename;
  const writeStream = fs.createWriteStream(localFilePath);
  const stream = req.pipe(writeStream);

  req.on('end', function() {
    gm(localFilePath).resize(200, 200).autoOrient().write(localResizedFilePath, (err) => {
      if (err) res.status(400).json(err);
      else {
        uploader.uploadFile(filename, "image/jpeg", localResizedFilePath, (err, url) => {
          if (err) res.status(400).json(err);
          else {
            user.avatar_thumb_uri = url;
            user.save().then(() => {
              fs.unlink(localResizedFilePath, (err) => {
                if (err) {
                  console.error(err);
                  res.status(400).json(err);
                } else {
                  res.status(200).json(user);
                }
              });
            });
          }
        });
      }
    });
  });
});

router.post('/password_reset_requests', (req, res, next) => {
  const email = req.query.email;
  db.User.findOne({where: {"email": email}}).then((user) => {
    if (user) {
      crypto.randomBytes(16, (ex, buf) => {
        user.password_reset_token = buf.toString('hex');
        user.save().then(updatedUser => {
          mailer.sendMail(email, req.i18n.__("password_reset_subject"), req.i18n.__("password_reset_body"), {action: {
            link: config.endpoint + "/password-confirm/" + user.password_reset_token,
            name: req.i18n.__("password_reset_action")
          }});
          res.status(201).json({});
        });
      });
    } else {
      res.status(404).json({"error": "error_unknown_email"});
    }
  });
});

router.post('/password_reset_requests/:confirm_token/confirm', function(req, res, next) {
  var password = req.body.password;

  db.User
    .findOne({where: {"password_reset_token": req.params.confirm_token}})
    .then((user) => {
      if (user) {
        bcrypt.genSalt(10, (err, salt) => {
          bcrypt.hash(password, salt, function(err, hash) {
            user.password_hash = hash;
            user.password_token = null;
            user.save().then(function(updatedUser) {
              res.sendStatus(201);
            });
          });
        });
      } else {
        res.sendStatus(404);
      }
    });
});

router.post('/:user_id/confirm', function(req, res, next) {
  mailer.sendMail(req.user.email, req.i18n.__("confirm_subject"), req.i18n.__("confirm_body"), { action:{
    link: config.endpoint + "/confirm/" + req.user.confirmation_token,
    name: req.i18n.__("confirm_action")
  }});
  res.sendStatus(201);
});

module.exports = router;
