const { StatusCodes } = require("http-status-codes");
const { sum, sumBy } = require("lodash");
const db = require("../db");

/**
 * Get status code that should be returned in the API response.
 * - OK (200) in case everything is healthy
 * - SERVICE_UNAVAILABLE (503) in case of any failures or if disabled
 */
function getStatusCode() {
  // check whether the portal has been manually disabled
  const disabled = getDisabled();

  if (disabled) {
    return StatusCodes.SERVICE_UNAVAILABLE;
  }

  // grab the most recent critical entry element from DB
  const entry = getMostRecentCriticalEntry();

  // in case there is no entry yet or at least one check failed in the most recent entry
  if (!entry || entry.checks.some(({ up }) => !up)) {
    return StatusCodes.SERVICE_UNAVAILABLE;
  }

  return StatusCodes.OK;
}

/**
 * Get the sample of most recent critical entries and
 * calculate the average response time of all of them
 */
function getAverageResponseTime() {
  // get most recent 10 successfull checks for the calculation
  const sample = db
    .get("critical")
    .orderBy("date", "desc")
    .filter(({ checks }) => checks.every(({ up }) => up))
    .take(10)
    .value();

  // calculate average time of response
  return Math.round(sum(sample.map(({ checks }) => sumBy(checks, "time"))) / sample.size);
}

/**
 * Get one, most current critical entry
 */
function getMostRecentCriticalEntry() {
  return db.get("critical").orderBy("date", "desc").head().value();
}

/**
 * Get the disabled flag state (manual portal disable)
 */
function getDisabled() {
  return db.get("disabled").value();
}

module.exports = (req, res) => {
  const statusCode = getStatusCode();
  const timeout = statusCode === StatusCodes.OK ? getAverageResponseTime() : 0;

  // We want to delay the response for the load balancer to be able to prioritize
  // servers based on the successful response time of this endpoint. Load balancer
  // will pull the server if the response is an error so there is no point in delaying
  // failures, hence 0 timeout on those.
  setTimeout(() => {
    // include some health information in the response body
    const entry = getMostRecentCriticalEntry();
    const disabled = getDisabled();

    res.status(statusCode).send({ disabled, entry });
  }, timeout);
};
