/**
 * Global Error Handler Middleware
 * Catches all errors and returns consistent JSON responses
 */

import { AppwriteException } from 'node-appwrite'

export class AppError extends Error {
  constructor(message, statusCode = 500, code = 'INTERNAL_ERROR') {
    super(message)
    this.statusCode = statusCode
    this.code = code
    this.isOperational = true
    Error.captureStackTrace(this, this.constructor)
  }
}

export class ValidationError extends AppError {
  constructor(message, fields = {}) {
    super(message, 400, 'VALIDATION_ERROR')
    this.fields = fields
  }
}

export class AuthenticationError extends AppError {
  constructor(message = 'Nicht authentifiziert') {
    super(message, 401, 'AUTHENTICATION_ERROR')
  }
}

export class AuthorizationError extends AppError {
  constructor(message = 'Keine Berechtigung') {
    super(message, 403, 'AUTHORIZATION_ERROR')
  }
}

export class NotFoundError extends AppError {
  constructor(resource = 'Ressource') {
    super(`${resource} nicht gefunden`, 404, 'NOT_FOUND')
  }
}

export class RateLimitError extends AppError {
  constructor(message = 'Zu viele Anfragen') {
    super(message, 429, 'RATE_LIMIT_EXCEEDED')
  }
}

/**
 * Error handler middleware
 */
export function errorHandler(err, req, res, next) {
  // Log error
  console.error(`[ERROR] ${new Date().toISOString()}`, {
    method: req.method,
    path: req.path,
    error: err.message,
    stack: process.env.NODE_ENV === 'development' ? err.stack : undefined,
  })

  // Default error values (AppwriteException uses numeric err.code — do not reuse as JSON "code" string)
  let statusCode =
    typeof err.statusCode === 'number' ? err.statusCode : undefined
  let code = typeof err.code === 'string' && err.code ? err.code : 'INTERNAL_ERROR'
  let message = err.message || 'Ein Fehler ist aufgetreten'

  if (
    err instanceof AppwriteException &&
    typeof err.code === 'number' &&
    err.code >= 400 &&
    err.code < 600
  ) {
    statusCode = err.code
    code = err.type || 'APPWRITE_ERROR'
    message = err.message || message
    err.isOperational = true
  }

  if (statusCode === undefined) {
    statusCode = 500
  }

  // Handle specific error types
  if (err.name === 'ValidationError') {
    statusCode = 400
    code = 'VALIDATION_ERROR'
  }

  if (err.name === 'JsonWebTokenError') {
    statusCode = 401
    code = 'INVALID_TOKEN'
    message = 'Ungültiger Token'
  }

  if (err.name === 'TokenExpiredError') {
    statusCode = 401
    code = 'TOKEN_EXPIRED'
    message = 'Token abgelaufen'
  }

  // Don't expose internal errors in production
  if (!err.isOperational && process.env.NODE_ENV === 'production') {
    message = 'Ein interner Fehler ist aufgetreten'
  }

  // Send response
  res.status(statusCode).json({
    success: false,
    error: {
      code,
      message,
      ...(err.fields && { fields: err.fields }),
      ...(process.env.NODE_ENV === 'development' && { stack: err.stack }),
    },
  })
}

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