const path = require("path");
const joi = require("@hapi/joi");
const {sprintf} = require("sprintf-js");
import jsonSchemaValidator from "../../jsonSchema/jsonSchemaValidationService";
const MSG_SCHEMA_FAILED = "Failed json schema on %s, errors: %s";
const deref = require("json-schema-deref-sync");

export default class RouteResponseJsonSchemaValidator {
  async callback(req, res, next) {
    const {config: {route}} = req;

    if (!route.hasOwnProperty("responseJsonSchema")) {
      return next();
    }

    const origionalJson = res.json;

    res.json = (data) => {
      // We only needed to intercept the json data, now we can
      // restore json back to the original for future calls.
      res.json = origionalJson;

      const error = this.validateData(route, data);

      if (error) {
        return next(error);
      }

      res.json(data);
    };

    next();
  }

  validateData(route, data) {
    try {
      joi.assert(
          route,
          joi.object().keys({
            responseJsonSchema: joi.string().required(),
          }).unknown(true),
      );

      const schema = this._buildResponseJsonSchema(
          route.responseJsonSchema,
      );

      if (schema) {
        const error = jsonSchemaValidator(schema, data);

        if (error) {
          return sprintf(MSG_SCHEMA_FAILED, "response", error)
              .trim("\n");
        }
      }
    }
    catch (error) {
      if (error.hasOwnProperty("details")) {
        console.debug(
            `Skipping route "${route.id}" due to ${error.details[0].message}`);
      }

      return error.message;
    }
  }

  _buildResponseJsonSchema(responseJsonSchema) {
    const querySchemaPath = path.join(
        process.cwd(),
        responseJsonSchema,
    );
    const schema = require(querySchemaPath);

    return deref(schema);
  }
}
