var express = require('express');
var createError = require('http-errors')
const bcrypt = require('bcryptjs');

const models = require('../../../models');
const utils = require('../../../libs/utils');
const auth = require('../../../libs/auth');

const router = express.Router();



router.get('/pager/headers', auth.need('read:own', 'user'), utils.pager.getHeadersBuilder(models.User));

router.get('/pager', auth.need('read:own', 'user'), (req, res, next) => {
  (async () => {
    if (!req.ac) throw createError(403, 'NO AC');
    /**@type {AccessControl} */
    let ac = req.ac;
    let readAny = ac.can('user').readAny('user').granted;
    if (readAny) next()
    else {
      req.query.base = { createBy: req.session.user._id };
      next();
    }
  })().catch(next);
}, utils.pager.getListBuilder(models.User, [
  { path: 'createBy', select: 'username' },
  { path: 'roles', select: 'name' },
], (item, req) => { return item.createBy && (item.createBy._id == req.session.user._id) }
));


/**
 * user-create
 */
router.post('/', auth.need('create:own', 'user'), function (req, res, next) {
  (async function () {
    let { username, password, name, phone, email, roles } = req.body;
    if (!username || !password || !phone || !email || !name) throw createError(400, '缺少参数');
    utils.validators.validatePhone(phone);
    utils.validators.validateUsername(username);
    utils.validators.validatePassword(password);
    let doc = await models.User.findOne({ $or: [{ username }, { phone }, { email }] }).select('username phone')
      .lean()
      .exec();
    if (doc) throw createError(400, '用户名或手机号或邮箱已被占用');
    let salt = await bcrypt.genSalt(10);
    password = await bcrypt.hash(password, salt);
    let createBy = req.session.user._id;
    let ipLastSignin = req.ip;
    let user = new models.User({ username, password, name, phone, email, roles, createBy, ipLastSignin });
    await user.save();
    res.json({
      msg: 'ok',
    })
  })().catch(next)
});


router.get('/select/options', function (req, res, next) {
  (async function () {
    let docs = await models.User.find().select('username').lean();
    docs = docs.map(u => ({ label: u.username, value: u._id }));
    res.json(docs);
  })().catch(next)
});



router.get('/:id', auth.need('read:own', 'user'), function (req, res, next) {
  (async function () {
    utils.validators.validateId(req.params.id);
    let doc = await models.User.findById(req.params.id).select('-password').lean();
    if (!doc) throw createError(404, 'Not found!');
    if (!auth.can.readAny(req, 'user') && doc.createBy != req.session.user._id) throw createError(403, '权限不足');
    res.json(doc);
  })().catch(next)
});



router.patch('/:id', auth.need('update:own', 'user'), function (req, res, next) {
  (async function () {
    utils.validators.validateId(req.params.id);
    let doc = await models.User.findById(req.params.id);
    if (!doc) throw createError(404, 'Not found!');
    let updates = {};
    let editableFields = ['name', 'email', 'roles', 'epgs', 'phone', 'disabled'];
    Object.keys(req.body).filter(key => editableFields.includes(key)).forEach(key => {
      updates[key] = req.body[key];
    })
    doc.set(updates);
    console.log('user update:', doc.getChanges());
    await doc.save();

    if (doc.disabled === true) {
      await utils.session.destroyUser(req, doc._id); //清空用户session
    }
    //await utils.async.delay(1000);
    res.json({ msg: 'ok' });
  })().catch(next)
});


/** patch-password */
router.patch('/:id/password', auth.need('update:own', 'user'), function (req, res, next) {
  (async function () {
    utils.validators.validateId(req.params.id);
    let doc = await models.User.findById(req.params.id);
    if (!doc) throw createError(404, 'Not found!');
    let password = randomPassword();
    let salt = await bcrypt.genSalt(10);
    doc.password = await bcrypt.hash(password, salt);
    await utils.session.destroyUser(req, doc._id);
    await doc.save();
    res.json({
      name: doc.name,
      username: doc.username,
      password,
    });
  })().catch(next)
});



/**
 * 检查username占用
 */
router.post('/check/username', auth.need('create:own', 'user'), function (req, res, next) {
  (async function () {
    let { id, username } = req.body;
    if (!username) throw createError(400, 'Invalid request');
    let doc = await models.User.findOne({ username }).select('username').lean().exec();
    if (doc && doc._id != id) throw createError(400, '已占用');
    res.json({ msg: 'ok' })
  })().catch(next)
});

/**
 * 检查手机号占用
 */
router.post('/check/phone', auth.need('create:own', 'user'), function (req, res, next) {
  (async function () {
    let { id, phone } = req.body;
    if (!phone) throw createError(400, 'Invalid request');
    let doc = await models.User.findOne({ phone }).select('phone').lean().exec();
    if (doc && doc._id != id) throw createError(400, '已占用');
    res.json({ msg: 'ok' })
  })().catch(next)
});


/**
 * 检查邮箱占用
 */
router.post('/check/email', auth.need('create:own', 'user'), function (req, res, next) {
  (async function () {
    let { id, email } = req.body;
    if (!email) throw createError(400, 'Invalid request');
    let doc = await models.User.findOne({ email }).select('email').lean().exec();
    if (doc && doc._id != id) throw createError(400, '已占用');
    res.json({ msg: 'ok' })
  })().catch(next)
});

router.get('/session/list', auth.need('read:any', 'user'), function (req, res, next) {
  (async function () {
    let sessions = await utils.session.all(req);
    let data = sessions.map(s => {
      s.user.sesid = s.id;
      return s.user;
    });
    res.json({ data });
  })().catch(next)
});


router.delete('/session/:id', auth.need('delete:any', 'user'), function (req, res, next) {
  (async function () {
    /**@type {any[]} */
    let sessions = await utils.session.all(req);
    let ses = sessions.find(s => s.id == req.params.id);
    if (!ses) throw createError(404, 'session不存在');
    //await utils.async.delay(1000);
    if (ses.id == req.session.id) throw createError(400, '不能删除你自己的session');
    await utils.session.destroy(req, req.params.id);
    res.json({ msg: 'ok' });
  })().catch(next)
});




function randomPassword() {
  let wishlist = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@-#$';
  let pass = Array(20).fill(0).map(() => {
    return wishlist.charAt(Math.floor(Math.random() * wishlist.length))
  }).join('');
  console.log('pass', pass);
  return pass;
}



module.exports = router;
