import { API } from "../lib/api.js";
import logging from "../lib/logging.js";
import assert from "assert";
import { User } from "../lib/models.js";
import { send_reset, send_reset_finished } from '../lib/queues.js';
import differenceInHours from 'date-fns/differenceInHours/index.js';

const rules_request = {
  email: 'required|email',
}

const rules_finish = {
  code: 'required',
  password: 'required|same:password_repeat',
  password_repeat: 'required',
}

const log = logging.create("/api/password_reset.js");
// this doesn't change so just do it here

const RESET_MAX = 10;
const RESET_HOURS_MAX = 10;

export const post = async (req, res) => {
  const api = new API(req, res);
  const finalize = req.body.finalize;
  const rules = finalize ? rules_finish : rules_request
  const form = api.validate(rules);

  try {
    if(!form._valid) {
      // abort with errors
      return api.validation_error(res, form);
    } else {
      assert(form._valid, "Form is invalid but shouldn't be.");
      const { email } = form;
      const user = await User.first({email});

      if(!user) {
        return api.error(400, "User with that email doesn't exist.");
      } else if(finalize) {
        const { code, password } = form;

        if(user.reset_count > RESET_MAX) {
          return api.error(400, "Too many reset attempts in a short time. Contact support to unlock your account.");
        } else if(user.reset_code !== code.trim()) {
          await User.update({id: user.id}, { reset_count: user.reset_count + 1 });
          return api.error(400, "Reset code doesn't match.");
        } else {
          // SECURITY: encrypt the password here so that it's not left in the queue unencrypted
          user.password = User.encrypt_password(password);
          send_reset_finished(user, req.ip, req.headers['user-agent']);
          return api.reply(200, {message: "OK"});
        }
      } else if(user.reset_sent_at && differenceInHours(Date.now(), user.reset_sent_at) < RESET_HOURS_MAX) {
        return api.error(400, `Only one request every ${RESET_HOURS_MAX} hours allowed.`);
      } else {
        // new request, send out a code
        const user_req = { email, id: user.id};
        send_reset(user_req, req.ip, req.headers['user-agent']);
        return api.reply(200, {message: "OK"});
      }
    }
  } catch(error) {
    log.error(error);
    return api.error(500, "Internal Server Error");
  }
}
