import { HttpException, HttpStatus } from '@nestjs/common';
import { CustomException } from '.';

/**
 * Utility function to safely handle service requests with standardized error handling.
 * Wraps asynchronous operations to provide consistent error formatting and logging.
 *
 * This function:
 * 1. Executes the provided promise
 * 2. Catches any errors that occur
 * 3. Logs errors for debugging
 * 4. Converts all errors to CustomException format for consistent API responses
 * 5. Preserves original HttpException data when available
 *
 * @template T - The expected return type of the promise
 * @param promise - The asynchronous operation to execute
 * @returns A promise that resolves with the service response
 * @throws {CustomException} Always throws a CustomException on error
 *
 * @example
 * // Basic usage
 * const user = await handleServiceRequest(userService.findById(userId));
 *
 * @example
 * // With database operation
 * const result = await handleServiceRequest(
 *   this.userRepository.save(userData)
 * );
 *
 * @example
 * // With API call
 * const response = await handleServiceRequest(
 *   httpService.get('https://api.example.com/data')
 * );
 */
export async function handleServiceRequest<T>(promise: Promise<T>): Promise<T> {
  try {
    // Execute the provided promise
    // This could be any async operation: database query, HTTP request, file operation, etc.
    return await promise;
  } catch (error: any) {
    // Log the original error for debugging and monitoring
    // In production, consider using a structured logger instead of console.error
    console.error('Service Error:', error);

    // Check if the error is already an HttpException (NestJS HTTP error)
    if (error instanceof HttpException) {
      // Extract the response body from HttpException
      const response = error.getResponse();

      /**
       * Convert to CustomException while preserving the original error details
       * The response could be:
       * - A string: Simple error message
       * - An object: Structured error response from another HttpException
       * - undefined: Fallback to default message
       */
      throw new CustomException(
        response || 'An unexpected error occurred.',
        error.getStatus(), // Preserve original HTTP status code
      );
    }

    /**
     * Handle non-HttpException errors (TypeError, DatabaseError, network errors, etc.)
     * Convert to CustomException with appropriate message
     */
    throw new CustomException(
      error.message || 'An unexpected error occurred.',
      HttpStatus.INTERNAL_SERVER_ERROR, // Default to 500 for unhandled errors
    );
  }
}

/**
 * Usage Benefits:
 * 1. Consistent error responses across all services
 * 2. Automatic error logging
 * 3. Proper error type conversion
 * 4. Centralized error handling logic
 * 5. Easier testing with predictable error formats
 *
 * Error Response Examples:
 *
 * Original HttpException (404):
 * throw new HttpException('Not Found', HttpStatus.NOT_FOUND);
 *
 * Becomes CustomException:
 * {
 *   "success": false,
 *   "errors": { "message": "Not Found" },
 *   "data": null
 * }
 *
 * Database Error:
 * Error: Connection refused
 *
 * Becomes CustomException:
 * {
 *   "success": false,
 *   "errors": { "message": "Connection refused" },
 *   "data": null
 * }
 */
