/**
 * API Helper Utilities
 * Common utilities for API endpoints including query parameter parsing
 */

import { NextRequest } from 'next/server';

export interface QueryOptions {
  page?: number;
  limit?: number;
  offset?: number;
  includeDeleted?: boolean;
  sort?: string;
  order?: 'ASC' | 'DESC';
  filters?: Record<string, any>;
}

export interface PaginationInfo {
  page: number;
  limit: number;
  offset: number;
  total: number;
  totalPages: number;
  hasMore: boolean;
  hasPrevious: boolean;
}

/**
 * Parse query parameters from Next.js request
 * @param request Next.js request object
 * @param defaults Default values for query options
 * @returns Parsed query options
 */
export function parseQueryParams(
  request: NextRequest,
  defaults: Partial<QueryOptions> = {}
): QueryOptions {
  const searchParams = request.nextUrl.searchParams;

  // Parse pagination
  const page = parseInt(searchParams.get('page') || String(defaults.page || 1));
  const limit = parseInt(searchParams.get('limit') || String(defaults.limit || 100));
  const offset = (page - 1) * limit;

  // Parse includeDeleted flag
  const includeDeletedParam = searchParams.get('includeDeleted');
  const includeDeleted = includeDeletedParam !== null
    ? includeDeletedParam === 'true'
    : defaults.includeDeleted || false;

  // Parse sorting
  const sort = searchParams.get('sort') || defaults.sort || 'id';
  const orderParam = searchParams.get('order')?.toUpperCase();
  const order = (orderParam === 'ASC' || orderParam === 'DESC') ? orderParam : (defaults.order || 'ASC');

  // Parse filters
  const filters: Record<string, any> = { ...defaults.filters };
  
  // Get all search params and treat unknown params as filters
  searchParams.forEach((value, key) => {
    // Skip known pagination/sorting params
    if (['page', 'limit', 'includeDeleted', 'sort', 'order'].includes(key)) {
      return;
    }

    // Parse filter value
    filters[key] = parseFilterValue(value);
  });

  return {
    page,
    limit,
    offset,
    includeDeleted,
    sort,
    order,
    filters,
  };
}

/**
 * Parse filter value to appropriate type
 * @param value String value from query parameter
 * @returns Parsed value (boolean, number, or string)
 */
function parseFilterValue(value: string): any {
  // Boolean
  if (value === 'true') return true;
  if (value === 'false') return false;
  
  // Number
  if (/^\d+$/.test(value)) return parseInt(value);
  if (/^\d+\.\d+$/.test(value)) return parseFloat(value);
  
  // Null
  if (value === 'null') return null;
  
  // String (default)
  return value;
}

/**
 * Build WHERE clause from filters
 * @param filters Filter object
 * @param includeDeleted Whether to include deleted records
 * @returns WHERE clause object
 */
export function buildWhereClause(
  filters: Record<string, any>,
  includeDeleted: boolean = false
): Record<string, any> {
  const where: Record<string, any> = { ...filters };

  // Always exclude soft-deleted records unless explicitly requested
  if (!includeDeleted) {
    where.is_deleted = false;
  }

  return where;
}

/**
 * Build ORDER BY clause
 * @param sort Sort field
 * @param order Sort order (ASC/DESC)
 * @returns ORDER BY string
 */
export function buildOrderByClause(sort: string, order: 'ASC' | 'DESC'): string {
  // Sanitize sort field to prevent SQL injection
  const sanitizedSort = sort.replace(/[^a-zA-Z0-9_]/g, '');
  return `${sanitizedSort} ${order}`;
}

/**
 * Create pagination info object
 * @param page Current page number
 * @param limit Records per page
 * @param total Total record count
 * @returns Pagination information
 */
export function createPaginationInfo(
  page: number,
  limit: number,
  total: number
): PaginationInfo {
  const offset = (page - 1) * limit;
  const totalPages = Math.ceil(total / limit);

  return {
    page,
    limit,
    offset,
    total,
    totalPages,
    hasMore: page < totalPages,
    hasPrevious: page > 1,
  };
}

/**
 * Validate query parameters
 * @param options Query options to validate
 * @throws Error if validation fails
 */
export function validateQueryParams(options: QueryOptions): void {
  if (options.page && options.page < 1) {
    throw new Error('Page must be greater than 0');
  }

  if (options.limit && (options.limit < 1 || options.limit > 1000)) {
    throw new Error('Limit must be between 1 and 1000');
  }

  if (options.sort && !/^[a-zA-Z0-9_]+$/.test(options.sort)) {
    throw new Error('Invalid sort field');
  }
}

/**
 * Format API response with data and pagination
 * @param data Data array
 * @param pagination Pagination info
 * @param meta Additional metadata
 * @returns Formatted response object
 */
export function formatApiResponse<T>(
  data: T[],
  pagination: PaginationInfo,
  meta?: Record<string, any>
) {
  return {
    data,
    pagination,
    meta: {
      timestamp: new Date().toISOString(),
      ...meta,
    },
  };
}

/**
 * Handle API errors consistently
 * @param error Error object
 * @param context Error context
 * @returns Error response object
 */
export function handleApiError(error: any, context?: string) {
  console.error(`API Error${context ? ` (${context})` : ''}:`, error);

  const message = error instanceof Error ? error.message : 'An unexpected error occurred';
  const statusCode = error.statusCode || 500;

  return {
    error: message,
    context,
    timestamp: new Date().toISOString(),
    statusCode,
  };
}
