"use strict";

const _ = require("lodash");
const httpStatus = require("http-status");
const Sequelize = require("sequelize");

////////////////////////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS
////////////////////////////////////////////////////////////////////////////////

function buildErrorLog(err) {
  if (err instanceof Sequelize.ValidationError) {
    return {
      message: err.message,
      httpCode: httpStatus.UNPROCESSABLE_ENTITY, // <- datos no válidos
      code: err.parent ? err.parent.code : "",
      payload: err.fields,
    };
  }
  return buildErrorLogOriginal(err);
}

function buildErrorLogOriginal(err) {
  let errorLog;
  if (_.isUndefined(err)) {
    errorLog = "Error not defined";
  } else if (!_.isUndefined(err.message)) {
    errorLog = err.message;
  } else if (!_.isUndefined(err.stack)) {
    errorLog = err.stack;
  } else {
    errorLog = JSON.stringify(err);
  }
  return errorLog;
}

function buildErrorResponse(nameController, nameMethod, error) {
  const errorDescription = buildErrorLog(error);

  const jsonResultFailed = {
    statusCode: errorDescription.httpCode ? errorDescription.httpCode : httpStatus.INTERNAL_SERVER_ERROR,
    message: errorDescription.message ? errorDescription.message : "Internal Server Error",
    code: errorDescription.code ? errorDescription.code : "Undefined",
    description: `Internal Application Error in ${nameController}:${nameMethod}.`,
    payload: errorDescription,
  };
  return jsonResultFailed;
}

function getTotalCount(result) {
  const toType = function (obj) {
    return {}.toString
      .call(obj)
      .match(/\s([a-zA-Z]+)/)[1]
      .toLowerCase();
  };

  switch (toType(result)) {
    case "boolean":
      return 1;
    case "object":
      return 1;
    case "array":
      return result.length;
    case "null":
      return 0;
    default:
      return 0;
  }
}

function setPaginationInfo(totalCount, res) {
  res.set({
    "X-Total-Count": totalCount,
  });

  const params = extractParamsFromRequest(null, res);

  //console.log('>>>>>>>>>>>>>>>>>>>>>>>>> params antes de setPaginationInfo');
  //console.log(params);
  if (params.paginate) {
    const page = params.paginate && params.paginate.page ? params.paginate.page : null,
      limit = params.paginate && params.paginate.limit ? params.paginate.limit : null,
      count = limit ? Math.ceil(totalCount / limit) : null;

    /*if (params.paginate.hasNextPages(count)) {
            const nextPage = params.paginate.href();
            res.set('Link-Next-Page', nextPage + '; rel=next');
            res.set('Pagination-Next-Page', true);
        } else {
            res.set('Pagination-Next-Page', false);
        }*/

    res.set({
      "Pagination-Count": count,
      "Pagination-Page": page,
      "Pagination-Limit": limit,
    });
  }
}

////////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS
////////////////////////////////////////////////////////////////////////////////

function extractParamsFromRequest(req, res, extraParams = {}) {
  const result = {};

  result.route = req && req.route ? req.route.path : null;
  result.params = req && req.params ? req.params : null;
  result.query = req && req.query ? req.query : null;

  if (res && res.locals) {
    Object.keys(res.locals).forEach((key) => {
      result[key] = res.locals[key];
    });
  }

  return {
    ...result,
    ...extraParams,
  };
}

function handleErrorResponse(controllerName, methodName, error, res) {
  console.error(error);
  const jsonResultFailed = buildErrorResponse(controllerName, methodName, error);
  res.status(jsonResultFailed.statusCode).send(jsonResultFailed);
}

function handleResultResponse(result, totalCount = null, params, res, statusCode = httpStatus.OK) {
  setPaginationInfo(totalCount ? totalCount : getTotalCount(result), res);
  res.status(statusCode).send(typeof result == "number" ? result.toString() : result);
}

////////////////////////////////////////////////////////////////////////////////
// MODULE EXPORTS
////////////////////////////////////////////////////////////////////////////////

module.exports = {
  extractParamsFromRequest,
  handleErrorResponse,
  handleResultResponse,
  // for testing
  buildErrorLog,
  buildErrorResponse,
  httpStatus,
};
