const logger = require("../config/logger");
const {
  isDevelopment,
  PG_ERROR_CODES,
  MULTER_ERROR_CODES,
  STATIC_ASSET_EXTENSIONS,
} = require("../config/constants");

class AppError extends Error {
  constructor(message, statusCode, isOperational = true) {
    super(message);
    this.statusCode = statusCode;
    this.isOperational = isOperational;
    this.timestamp = new Date().toISOString();
    Error.captureStackTrace(this, this.constructor);
  }
}

const ERROR_MAPPINGS = {
  [PG_ERROR_CODES.UNIQUE_VIOLATION]: {
    message: "Duplicate entry: Resource already exists",
    statusCode: 409,
  },
  [PG_ERROR_CODES.FOREIGN_KEY_VIOLATION]: {
    message: "Referenced resource does not exist",
    statusCode: 400,
  },
  [PG_ERROR_CODES.INVALID_TEXT]: {
    message: "Invalid data format",
    statusCode: 400,
  },
  [MULTER_ERROR_CODES.FILE_SIZE]: {
    message: "File too large. Maximum size is 5MB",
    statusCode: 400,
  },
  [MULTER_ERROR_CODES.FILE_COUNT]: {
    message: "Too many files. Maximum is 10 files per upload",
    statusCode: 400,
  },
};

// Global error handler middleware
const errorHandler = (err, req, res, next) => {
  let error = { ...err };
  error.message = err.message;
  error.statusCode = err.statusCode || 500;

  // Log error
  logger.error("Error occurred", {
    message: error.message,
    statusCode: error.statusCode,
    path: req.path,
    method: req.method,
    ip: req.ip,
    stack: err.stack,
  });

  // Map known error codes
  const errorMapping = ERROR_MAPPINGS[err.code];
  if (errorMapping) {
    error.message = errorMapping.message;
    error.statusCode = errorMapping.statusCode;
  }

  // SAFEGUARD: Don't send response if headers already sent
  if (res.headersSent) {
    logger.warn("Headers already sent in error handler", {
      path: req.path,
      error: error.message,
    });
    return next(err);
  }

  res.status(error.statusCode).json({
    success: false,
    message: error.message || "Server error",
    ...(isDevelopment() && {
      error: err.message,
      stack: err.stack,
    }),
  });
};

// 404 handler
const notFoundHandler = (req, res) => {
  const isStaticAsset = STATIC_ASSET_EXTENSIONS.test(req.path);

  if (!isStaticAsset) {
    logger.warn("Route not found", {
      path: req.path,
      method: req.method,
      ip: req.ip,
    });
  } else {
    logger.debug("Static asset not found", {
      path: req.path,
      method: req.method,
    });
  }

  // SAFEGUARD: Check if response already sent
  if (res.headersSent) {
    logger.warn("Headers already sent in 404 handler", { path: req.path });
    return;
  }

  res.status(404).json({
    success: false,
    message: "Route not found",
    path: req.path,
  });
};

// Async handler wrapper to catch errors in async routes
const asyncHandler = (fn) => (req, res, next) => {
  Promise.resolve(fn(req, res, next)).catch(next);
};

module.exports = {
  AppError,
  errorHandler,
  notFoundHandler,
  asyncHandler,
};
