const ResultDAO = require("../../dao/result");
const UserDAO = require("../../dao/user");
// const PublicStatsDAO = require("../../dao/public-stats");
const {
  validateObjectValues,
  validateResult,
} = require("../../handlers/validation");
const { stdDev, roundTo2 } = require("../../handlers/misc");

class ResultController {
  static async getResults(req, res, next) {
    try {
      const { uid } = req.decodedToken;
      const results = await ResultDAO.getResults(uid);
      return res.status(200).json(results);
    } catch (e) {
      next(e);
    }
  }

  static async addResult(req, res, next) {
    try {
      const { uid } = req.decodedToken;
      const { result } = req.body;
      if (validateObjectValues(result) > 0)
        return res.status(400).json({ message: "Bad input" });
      if (
        result.wpm <= 0 ||
        result.wpm > 350 ||
        result.acc < 50 ||
        result.acc > 100 ||
        result.consistency > 100
      ) {
        return res.status(400).json({ message: "Bad input" });
      }
      if (
        (result.mode === "time" && result.mode2 < 15 && result.mode2 > 0) ||
        (result.mode === "time" &&
          result.mode2 == 0 &&
          result.testDuration < 15) ||
        (result.mode === "words" && result.mode2 < 10 && result.mode2 > 0) ||
        (result.mode === "words" &&
          result.mode2 == 0 &&
          result.testDuration < 15) ||
        (result.mode === "custom" &&
          result.customText !== undefined &&
          !result.customText.isWordRandom &&
          !result.customText.isTimeRandom &&
          result.customText.textLen < 10) ||
        (result.mode === "custom" &&
          result.customText !== undefined &&
          result.customText.isWordRandom &&
          !result.customText.isTimeRandom &&
          result.customText.word < 10) ||
        (result.mode === "custom" &&
          result.customText !== undefined &&
          !result.customText.isWordRandom &&
          result.customText.isTimeRandom &&
          result.customText.time < 15)
      ) {
        return res.status(400).json({ message: "Test too short" });
      }
      if (!validateResult(result)) {
        return res
          .status(400)
          .json({ message: "Result data doesn't make sense" });
      }

      result.keySpacingStats = {
        average:
          result.keySpacing.reduce(
            (previous, current) => (current += previous)
          ) / result.keySpacing.length,
        sd: stdDev(result.keySpacing),
      };

      result.keyDurationStats = {
        average:
          result.keyDuration.reduce(
            (previous, current) => (current += previous)
          ) / result.keyDuration.length,
        sd: stdDev(result.keyDuration),
      };

      const user = await UserDAO.getUser(uid);
      result.name = user.name;

      //check keyspacing and duration here for bots
      if (
        result.mode === "time" &&
        result.wpm > 130 &&
        result.testDuration < 122
      ) {
        if (user.verified === false || user.verified === undefined) {
          if (
            result.keySpacingStats !== null &&
            result.keyDurationStats !== null
          ) {
            if (
              result.keySpacingStats.sd <= 15 ||
              result.keyDurationStats.sd <= 10 ||
              result.keyDurationStats.average < 15 ||
              (result.wpm > 200 && result.consistency < 70)
            ) {
              //possible bot
              return res.status(400).json({ message: "Possible bot detected" });
            }
            if (
              (result.keySpacingStats.sd > 15 &&
                result.keySpacingStats.sd <= 25) ||
              (result.keyDurationStats.sd > 10 &&
                result.keyDurationStats.sd <= 15) ||
              (result.keyDurationStats.average > 15 &&
                result.keyDurationStats.average <= 20)
            ) {
              //close to the bot detection threshold
            }
          } else {
            return res.status(400).json({ message: "Missing key data" });
          }
        }
      }

      delete result.keySpacing;
      delete result.keyDuration;

      result.keyDurationStats.average = roundTo2(
        result.keyDurationStats.average
      );
      result.keyDurationStats.sd = roundTo2(result.keyDurationStats.sd);
      result.keySpacingStats.average = roundTo2(result.keySpacingStats.average);
      result.keySpacingStats.sd = roundTo2(result.keySpacingStats.sd);

      const isPb = await UserDAO.checkIfPb(uid, result);
      const tagPbs = await UserDAO.checkIfTagPb(uid, result);

      if (result.mode === "time" && String(result.mode2) === "60") {
        UserDAO.incrementBananas(uid, result.wpm);
      }

      let tt = 0;
      let afk = result.afkDuration;
      if (afk == undefined) {
        afk = 0;
      }
      tt = result.testDuration + result.incompleteTestSeconds - afk;

      await UserDAO.updateTypingStats(uid, result.restartCount, tt);

      await ResultDAO.addResult(uid, result);

      return res
        .status(200)
        .json({ message: "Result saved", isPb, name: result.name, tagPbs });
    } catch (e) {
      next(e);
    }
  }
}

module.exports = ResultController;
