const { forEachField } = require('./utils');
const { maskErrors } = require('graphql-errors');
const errors = require('../errors');
const { Error: { ValidationError } } = require('mongoose');

// If an APIError happens in a mutation, then respond with `{errors: Array}`
// according to the schema.
const decorateWithMutationErrorHandler = field => {
  const fieldResolver = field.resolve;
  field.resolve = async (obj, args, ctx, info) => {
    try {
      return await fieldResolver(obj, args, ctx, info);
    } catch (err) {
      if (err instanceof errors.APIError) {
        return {
          errors: [err],
        };
      } else if (err instanceof ValidationError) {
        // TODO: wrap this with one of our internal errors.
        throw err;
      }

      throw err;
    }
  };
};

/**
 * Masks errors during production and handle mutation errors inside the schema.
 * @param  {GraphQLSchema} schema the schema to decorate
 * @return {void}
 */
const decorateWithErrorHandler = schema => {
  forEachField(schema, (field, typeName) => {
    // Handle mutation errors.
    if (typeName === 'RootMutation') {
      decorateWithMutationErrorHandler(field);
    }

    // If we are in production mode, don't show server errors to the front end.
    if (process.env.NODE_ENV === 'production') {
      // Mask errors that are thrown if we are in a production environment.
      maskErrors(field);
    }
  });
};

module.exports = {
  decorateWithErrorHandler,
};
