/**
 * Centralized Error Handling Middleware
 * Handles all errors throughout the application with consistent formatting
 */

const logger = require("../utils/logger");

// Custom error class for application-specific errors
class AppError extends Error {
  constructor(message, statusCode) {
    super(message);
    this.statusCode = statusCode;
    this.isOperational = true;
    Error.captureStackTrace(this, this.constructor);
  }
}

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

  // Log error for debugging
  logger.error(`Request error: ${err.message}`, err, {
    path: req.path,
    method: req.method,
    userId: req.user?.id,
  });

  // CouchDB document not found
  if (err.name === "NotFoundError" || err.statusCode === 404) {
    const message = "Resource not found";
    error = new AppError(message, 404);
  }

  // CouchDB conflict error (duplicate)
  if (err.name === "ConflictError" || err.statusCode === 409) {
    const message = "Duplicate field value entered";
    error = new AppError(message, 400);
  }

  // CouchDB validation error
  if (err.name === "ValidationError" || err.statusCode === 400) {
    const message = err.message || "Validation failed";
    error = new AppError(message, 400);
  }

  // JWT errors
  if (err.name === "JsonWebTokenError") {
    const message = "Invalid token";
    error = new AppError(message, 401);
  }

  if (err.name === "TokenExpiredError") {
    const message = "Token expired";
    error = new AppError(message, 401);
  }

  // Send error response
  res.status(error.statusCode || 500).json({
    success: false,
    error: error.message || "Server Error",
    ...(process.env.NODE_ENV === "development" && { stack: err.stack }),
  });
};

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

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