/**
 * API Response Utilities
 *
 * Standardized response builders for consistent API behavior
 * Follows REST best practices and enterprise error handling patterns
 *
 * @module lib/utils/api-response.util
 */

import { NextResponse } from 'next/server';

/**
 * Standard API error response structure
 */
export interface APIError {
  error: string;
  code?: string;
  details?: Record<string, any>;
}

/**
 * Standard API success response structure
 */
export interface APISuccess<T = any> {
  success: true;
  data?: T;
  message?: string;
}

/**
 * HTTP status codes enumeration for type safety
 */
export const HTTP_STATUS = {
  OK: 200,
  CREATED: 201,
  BAD_REQUEST: 400,
  UNAUTHORIZED: 401,
  FORBIDDEN: 403,
  NOT_FOUND: 404,
  TOO_MANY_REQUESTS: 429,
  INTERNAL_SERVER_ERROR: 500,
} as const;

/**
 * API Response Builder Class
 *
 * Provides fluent interface for building standardized API responses
 *
 * @class APIResponse
 */
export class APIResponse {
  /**
   * Create success response with optional data
   *
   * @param data - Response data
   * @param message - Optional success message
   * @param status - HTTP status code (default: 200)
   * @returns NextResponse with success payload
   *
   * @example
   * ```typescript
   * return APIResponse.success(
   *   { userId: '123', email: 'user@example.com' },
   *   'Account created successfully',
   *   HTTP_STATUS.CREATED
   * );
   * ```
   */
  static success<T = any>(
    data?: T,
    message?: string,
    status: number = HTTP_STATUS.OK
  ): NextResponse {
    const response: APISuccess<T> = {
      success: true,
      ...(data && { data }),
      ...(message && { message }),
    };

    return NextResponse.json(response, { status });
  }

  /**
   * Create error response with details
   *
   * @param error - Error message
   * @param status - HTTP status code
   * @param code - Error code for client handling
   * @param details - Additional error details
   * @returns NextResponse with error payload
   *
   * @example
   * ```typescript
   * return APIResponse.error(
   *   'Invalid email address',
   *   HTTP_STATUS.BAD_REQUEST,
   *   'INVALID_EMAIL',
   *   { field: 'email', pattern: '/^.+@.+\..+$/' }
   * );
   * ```
   */
  static error(
    error: string,
    status: number = HTTP_STATUS.BAD_REQUEST,
    code?: string,
    details?: Record<string, any>
  ): NextResponse {
    const response: APIError = {
      error,
      ...(code && { code }),
      ...(details && { details }),
    };

    return NextResponse.json(response, { status });
  }

  /**
   * Validation error response (400)
   *
   * @param message - Validation error message
   * @param field - Field that failed validation (optional)
   * @returns NextResponse with validation error
   */
  static validationError(message: string, field?: string): NextResponse {
    return this.error(
      message,
      HTTP_STATUS.BAD_REQUEST,
      'VALIDATION_ERROR',
      field ? { field } : undefined
    );
  }

  /**
   * Unauthorized error response (401)
   *
   * @param message - Error message (default: 'Unauthorized')
   * @returns NextResponse with unauthorized error
   */
  static unauthorized(message: string = 'Unauthorized'): NextResponse {
    return this.error(message, HTTP_STATUS.UNAUTHORIZED, 'UNAUTHORIZED');
  }

  /**
   * Not found error response (404)
   *
   * @param resource - Resource that wasn't found
   * @returns NextResponse with not found error
   */
  static notFound(resource: string = 'Resource'): NextResponse {
    return this.error(
      `${resource} not found`,
      HTTP_STATUS.NOT_FOUND,
      'NOT_FOUND'
    );
  }

  /**
   * Rate limit exceeded response (429)
   *
   * @param message - Rate limit message
   * @param retryAfter - Seconds until retry allowed (optional)
   * @returns NextResponse with rate limit error
   */
  static rateLimitExceeded(message?: string, retryAfter?: number): NextResponse {
    const response = this.error(
      message || 'Too many requests. Please try again later.',
      HTTP_STATUS.TOO_MANY_REQUESTS,
      'RATE_LIMIT_EXCEEDED',
      retryAfter ? { retryAfter } : undefined
    );

    if (retryAfter) {
      response.headers.set('Retry-After', retryAfter.toString());
    }

    return response;
  }

  /**
   * Internal server error response (500)
   *
   * @param message - Error message (default: generic message)
   * @param logError - Whether to log error to console
   * @param errorObject - Original error object for logging
   * @returns NextResponse with server error
   */
  static internalError(
    message?: string,
    logError: boolean = true,
    errorObject?: Error
  ): NextResponse {
    if (logError && errorObject) {
      console.error('[APIResponse] Internal error:', errorObject);
    }

    return this.error(
      message || 'Internal server error. Please try again later.',
      HTTP_STATUS.INTERNAL_SERVER_ERROR,
      'INTERNAL_ERROR'
    );
  }

  /**
   * Forbidden error response (403)
   *
   * @param message - Error message (default: 'Forbidden')
   * @returns NextResponse with forbidden error
   *
   * @example
   * ```typescript
   * if (!hasPermission) {
   *   return APIResponse.forbidden('You do not have permission to access this resource');
   * }
   * ```
   */
  static forbidden(message: string = 'Forbidden'): NextResponse {
    return this.error(message, HTTP_STATUS.FORBIDDEN, 'FORBIDDEN');
  }

  /**
   * Conflict error response (409)
   *
   * Used for duplicate entries or conflicting states
   *
   * @param message - Error message
   * @param details - Conflict details
   * @returns NextResponse with conflict error
   *
   * @example
   * ```typescript
   * return APIResponse.conflict(
   *   'Email already exists',
   *   { email: 'user@example.com' }
   * );
   * ```
   */
  static conflict(message: string, details?: Record<string, any>): NextResponse {
    return this.error(message, 409, 'CONFLICT', details);
  }

  /**
   * Validation error response with multiple field errors
   *
   * @param errors - Map of field names to error messages
   * @returns NextResponse with validation errors
   *
   * @example
   * ```typescript
   * return APIResponse.validationErrors({
   *   email: 'Invalid email format',
   *   password: 'Password must be at least 8 characters',
   * });
   * ```
   */
  static validationErrors(errors: Record<string, string>): NextResponse {
    return this.error(
      'Validation failed',
      HTTP_STATUS.BAD_REQUEST,
      'VALIDATION_ERROR',
      { fields: errors }
    );
  }

  /**
   * Success response with created resource (201)
   *
   * @param data - Created resource data
   * @param message - Success message
   * @returns NextResponse with created status
   *
   * @example
   * ```typescript
   * return APIResponse.created(
   *   { id: 'user-123', email: 'user@example.com' },
   *   'User created successfully'
   * );
   * ```
   */
  static created<T = any>(data: T, message?: string): NextResponse {
    return this.success(data, message, HTTP_STATUS.CREATED);
  }

  /**
   * No content success response (204)
   *
   * Used for successful DELETE or UPDATE operations with no response body
   *
   * @returns NextResponse with no content status
   *
   * @example
   * ```typescript
   * await deleteResource(id);
   * return APIResponse.noContent();
   * ```
   */
  static noContent(): NextResponse {
    return new NextResponse(null, { status: 204 });
  }
}

/**
 * Convenience function for success responses
 *
 * @param data - Response data
 * @param message - Optional success message
 * @returns NextResponse with success payload
 */
export function successResponse<T = any>(
  data?: T,
  message?: string
): NextResponse {
  return APIResponse.success(data, message);
}

/**
 * Convenience function for error responses
 *
 * @param message - Error message
 * @param status - HTTP status code (default: 400)
 * @param field - Optional field name for validation errors
 * @returns NextResponse with error payload
 */
export function errorResponse(
  message: string,
  status: number = HTTP_STATUS.BAD_REQUEST,
  field?: string
): NextResponse {
  if (field) {
    return APIResponse.validationError(message, field);
  }
  return APIResponse.error(message, status);
}

/**
 * Convenience function for validation error responses
 *
 * @param errors - Validation errors (single field or multiple fields)
 * @returns NextResponse with validation error
 *
 * @example
 * ```typescript
 * // Single field error
 * return validationErrorResponse('Invalid email', 'email');
 *
 * // Multiple field errors
 * return validationErrorResponse({
 *   email: 'Invalid email format',
 *   password: 'Too short',
 * });
 * ```
 */
export function validationErrorResponse(
  errors: string | Record<string, string>,
  field?: string
): NextResponse {
  if (typeof errors === 'string') {
    return APIResponse.validationError(errors, field);
  }
  return APIResponse.validationErrors(errors);
}

/**
 * Try-catch wrapper for API route handlers
 *
 * Automatically handles errors and returns appropriate responses
 *
 * @param handler - Async handler function
 * @returns NextResponse
 *
 * @example
 * ```typescript
 * export async function GET(request: NextRequest) {
 *   return withErrorHandling(async () => {
 *     const data = await fetchSomeData();
 *     return APIResponse.success(data);
 *   });
 * }
 * ```
 */
export async function withErrorHandling(
  handler: () => Promise<NextResponse>
): Promise<NextResponse> {
  try {
    return await handler();
  } catch (error) {
    console.error('[API] Unhandled error:', error);

    if (error instanceof Error) {
      // Check for specific error types
      if (error.message.includes('unauthorized') || error.message.includes('Unauthorized')) {
        return APIResponse.unauthorized();
      }

      if (error.message.includes('not found') || error.message.includes('Not found')) {
        return APIResponse.notFound();
      }

      if (error.message.includes('validation') || error.message.includes('invalid')) {
        return APIResponse.validationError(error.message);
      }
    }

    return APIResponse.internalError();
  }
}

/**
 * Paginated response structure
 */
export interface PaginatedResponse<T> {
  success: true;
  data: T[];
  pagination: {
    page: number;
    pageSize: number;
    totalCount: number;
    totalPages: number;
    hasNextPage: boolean;
    hasPreviousPage: boolean;
  };
}

/**
 * Create paginated success response
 *
 * @param data - Array of items
 * @param page - Current page number (1-indexed)
 * @param pageSize - Items per page
 * @param totalCount - Total number of items
 * @returns NextResponse with paginated data
 *
 * @example
 * ```typescript
 * const users = await prisma.users.findMany({
 *   skip: (page - 1) * pageSize,
 *   take: pageSize,
 * });
 * const totalCount = await prisma.users.count();
 *
 * return paginatedResponse(users, page, pageSize, totalCount);
 * ```
 */
/**
 * Convenience alias used by some API routes
 */
export const ApiResponses = {
  unauthorized: (msg?: string) => APIResponse.unauthorized(msg),
  notFound: (msg?: string) => APIResponse.notFound(msg),
  forbidden: (msg?: string) => APIResponse.forbidden(msg),
  badRequest: (msg: string) => APIResponse.error(msg, HTTP_STATUS.BAD_REQUEST),
  serverError: (msg?: string) => APIResponse.internalError(msg),
};

export function paginatedResponse<T>(
  data: T[],
  page: number,
  pageSize: number,
  totalCount: number
): NextResponse {
  const totalPages = Math.ceil(totalCount / pageSize);

  const response: PaginatedResponse<T> = {
    success: true,
    data,
    pagination: {
      page,
      pageSize,
      totalCount,
      totalPages,
      hasNextPage: page < totalPages,
      hasPreviousPage: page > 1,
    },
  };

  return NextResponse.json(response);
}
