import type { ErrorRequestHandler } from 'express';
import { MulterError } from 'multer';
import logger from '../config/logger.js';
import { errorResponse } from '../utils/response.js';
import { StorageNotConfiguredError } from '../utils/storage.js';
import { MAX_IMAGE_BYTES } from './upload.js';

// Image uploads (logo, photo, /uploads/images) allow 5 MB; project documents keep their 20MB message.
const IMAGE_UPLOAD_PATH = /\/(logo|avatar|uploads\/images)(\?|$)/;

interface AppError extends Error {
  type?: string;
  code?: string;
}

const errorHandler: ErrorRequestHandler = (error: AppError, req, res, next) => {
  if (res.headersSent) return next(error);

  if (error.type === 'entity.parse.failed') {
    return void errorResponse(res, 'Invalid JSON body', 400);
  }
  if (error.type === 'entity.too.large') {
    return void errorResponse(res, 'Request body is too large', 413);
  }
  if (error.type === 'file.invalid.type') {
    return void errorResponse(res, error.message, 400);
  }
  if (error instanceof MulterError) {
    if (error.code === 'LIMIT_FILE_SIZE') {
      if (IMAGE_UPLOAD_PATH.test(req.originalUrl)) {
        return void errorResponse(res, `Image is too large (max ${MAX_IMAGE_BYTES / (1024 * 1024)} MB)`, 413);
      }
      return void errorResponse(res, 'File is too large (max 20MB)', 413);
    }
    return void errorResponse(res, error.message, 400);
  }
  if (error instanceof StorageNotConfiguredError) {
    return void errorResponse(res, 'File uploads are not available yet: storage is not configured', 503);
  }
  if (error.code === 'P2002') {
    return void errorResponse(res, 'A record with this unique value already exists', 409);
  }
  if (error.code === 'P2025') {
    return void errorResponse(res, 'Record not found', 404);
  }
  if (error.code === 'P2003') {
    return void errorResponse(res, 'Referenced record does not exist', 400);
  }

  // Full error (with stack) goes to logs/error-*.log for debugging; the API
  // response itself stays generic so database details never reach clients.
  logger.error(`Unhandled error on ${req.method} ${req.originalUrl}`, {
    requestId: req.id,
    ip: req.ip,
    method: req.method,
    url: req.originalUrl,
    code: error.code,
    message: error.message,
    stack: error.stack,
  });
  return void errorResponse(res, 'Internal server error', 500);
};

export default errorHandler;
