import logger from './logger.js';
import objection from 'objection';
import * as Sentry from './sentry.ee.js';
const {
  NotFoundError,
  DataError,
  ForeignKeyViolationError,
  ValidationError,
  UniqueViolationError,
} = objection;
import NotAuthorizedError from '../errors/not-authorized.js';
import HttpError from '../errors/http.js';
import {
  renderObjectionError,
  renderUniqueViolationError,
} from './renderer.js';

// Do not remove `next` argument as the function signature will not fit for an error handler middleware
// eslint-disable-next-line no-unused-vars
const errorHandler = (error, request, response, next) => {
  if (error.message === 'Not Found' || error instanceof NotFoundError) {
    response.status(404).end();
  }

  if (notFoundAppError(error)) {
    response.status(404).end();
  }

  if (error instanceof ValidationError) {
    renderObjectionError(response, error, 422);
  }

  if (error instanceof UniqueViolationError) {
    renderUniqueViolationError(response, error);
  }

  if (error instanceof ForeignKeyViolationError) {
    response.status(500).end();
  }

  if (error instanceof DataError) {
    response.status(400).end();
  }

  if (error instanceof HttpError) {
    const httpErrorPayload = {
      errors: JSON.parse(error.message),
      meta: {
        type: 'HttpError',
      },
    };

    response.status(422).json(httpErrorPayload);
  }

  if (error instanceof NotAuthorizedError) {
    response.status(403).end();
  }

  const statusCode = error.statusCode || 500;

  logger.error(request.method + ' ' + request.url + ' ' + statusCode);
  logger.error(error.stack);

  Sentry.captureException(error, {
    tags: { rest: true },
    extra: {
      url: request?.url,
      method: request?.method,
      params: request?.params,
    },
  });

  response.status(statusCode).end();
};

const notFoundAppError = (error) => {
  return (
    error.message.includes('An application with the') &&
    error.message.includes("key couldn't be found.")
  );
};

export default errorHandler;
