/**
 * Error handling utilities for The Order services
 */

import { FastifyError, FastifyReply, FastifyRequest } from 'fastify';

/**
 * Custom application error class
 */
export class AppError extends Error {
  constructor(
    public statusCode: number,
    public code: string,
    message: string,
    public details?: unknown,
    public retryable = false,
    public timestamp = new Date()
  ) {
    super(message);
    this.name = 'AppError';
    Error.captureStackTrace(this, this.constructor);
  }

  /**
   * Check if error is retryable
   */
  isRetryable(): boolean {
    return this.retryable;
  }

  /**
   * Get error context
   */
  getContext(): Record<string, unknown> {
    return {
      statusCode: this.statusCode,
      code: this.code,
      message: this.message,
      details: this.details,
      retryable: this.retryable,
      timestamp: this.timestamp.toISOString(),
    };
  }
}

/**
 * Global error handler for Fastify
 */
export async function errorHandler(
  error: FastifyError,
  request: FastifyRequest,
  reply: FastifyReply
): Promise<void> {
  request.log.error({
    err: error,
    url: request.url,
    method: request.method,
    statusCode: error.statusCode || 500,
  });

  if (error instanceof AppError) {
    return reply.status(error.statusCode).send({
      error: {
        code: error.code,
        message: error.message,
        details: error.details,
      },
    });
  }

  // Handle validation errors
  if (error.validation) {
    return reply.status(400).send({
      error: {
        code: 'VALIDATION_ERROR',
        message: 'Validation failed',
        details: error.validation,
      },
    });
  }

  // Don't expose internal errors in production
  const isProduction = process.env.NODE_ENV === 'production';
  const statusCode = error.statusCode || 500;
  
  // Log error details for monitoring
  request.log.error({
    error: {
      message: error.message,
      stack: error.stack,
      code: error.code || 'INTERNAL_ERROR',
      statusCode,
    },
    request: {
      method: request.method,
      url: request.url,
      headers: request.headers,
    },
  });

  return reply.status(statusCode).send({
    error: {
      code: 'INTERNAL_ERROR',
      message: isProduction ? 'Internal server error' : error.message,
      ...(isProduction ? {} : { stack: error.stack }),
      ...(error instanceof AppError && error.retryable ? { retryable: true } : {}),
    },
  });
}

/**
 * Create a standardized error response
 */
export function createErrorResponse(
  statusCode: number,
  code: string,
  message: string,
  details?: unknown,
  retryable = false
): AppError {
  return new AppError(statusCode, code, message, details, retryable);
}

/**
 * Create a retryable error
 */
export function createRetryableError(
  statusCode: number,
  code: string,
  message: string,
  details?: unknown
): AppError {
  return new AppError(statusCode, code, message, details, true);
}

/**
 * Create a non-retryable error
 */
export function createNonRetryableError(
  statusCode: number,
  code: string,
  message: string,
  details?: unknown
): AppError {
  return new AppError(statusCode, code, message, details, false);
}

