/*
 * File: helpers.ts
 * Description: General helper functions for common operations
 * Design & Developed by Tech4Biz Solutions
 * Copyright (c) Spurrin Innovations. All rights reserved.
 */

import { AlertPriority, PatientStatus } from '../types';

// ============================================================================
// ARRAY HELPERS - Functions for array manipulation and processing
// ============================================================================

/**
 * chunk Function
 * 
 * Purpose: Split an array into smaller chunks of specified size
 * 
 * @param array - The array to be chunked
 * @param size - The size of each chunk
 * @returns Array of arrays, each containing up to 'size' elements
 * 
 * Example:
 * chunk([1, 2, 3, 4, 5, 6], 2) → [[1, 2], [3, 4], [5, 6]]
 * 
 * Use case: Pagination, displaying data in groups
 */
export const chunk = <T>(array: T[], size: number): T[][] => {
  const chunks: T[][] = [];
  for (let i = 0; i < array.length; i += size) {
    chunks.push(array.slice(i, i + size));
  }
  return chunks;
};

/**
 * groupBy Function
 * 
 * Purpose: Group array elements by a specified key function
 * 
 * @param array - The array to be grouped
 * @param key - Function that returns the grouping key for each element
 * @returns Object with keys as group names and values as arrays of grouped items
 * 
 * Example:
 * groupBy(patients, patient => patient.department)
 * → { 'Emergency': [patient1, patient2], 'ICU': [patient3] }
 * 
 * Use case: Organizing patients by department, status, or priority
 */
export const groupBy = <T, K extends keyof any>(
  array: T[],
  key: (item: T) => K
): Record<K, T[]> => {
  return array.reduce((groups, item) => {
    const group = key(item);
    if (!groups[group]) {
      groups[group] = [];
    }
    groups[group].push(item);
    return groups;
  }, {} as Record<K, T[]>);
};

// ============================================================================
// OBJECT HELPERS - Functions for object manipulation and transformation
// ============================================================================

/**
 * pick Function
 * 
 * Purpose: Create a new object with only specified properties from the original
 * 
 * @param obj - The source object
 * @param keys - Array of property names to include
 * @returns New object containing only the specified properties
 * 
 * Example:
 * pick({ name: 'John', age: 30, id: 1 }, ['name', 'age'])
 * → { name: 'John', age: 30 }
 * 
 * Use case: Extracting specific patient data fields
 */
export const pick = <T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> => {
  const result = {} as Pick<T, K>;
  keys.forEach(key => {
    if (key in obj) {
      result[key] = obj[key];
    }
  });
  return result;
};

/**
 * omit Function
 * 
 * Purpose: Create a new object excluding specified properties from the original
 * 
 * @param obj - The source object
 * @param keys - Array of property names to exclude
 * @returns New object without the specified properties
 * 
 * Example:
 * omit({ name: 'John', age: 30, id: 1 }, ['id'])
 * → { name: 'John', age: 30 }
 * 
 * Use case: Removing sensitive data before sending to API
 */
export const omit = <T, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> => {
  const result = { ...obj };
  keys.forEach(key => {
    delete result[key];
  });
  return result;
};

// ============================================================================
// STRING HELPERS - Functions for string manipulation and formatting
// ============================================================================

/**
 * capitalize Function
 * 
 * Purpose: Capitalize the first letter of a string and lowercase the rest
 * 
 * @param str - The string to capitalize
 * @returns Capitalized string
 * 
 * Example:
 * capitalize('john doe') → 'John doe'
 * 
 * Use case: Formatting patient names, department names
 */
export const capitalize = (str: string): string => {
  return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
};

/**
 * truncate Function
 * 
 * Purpose: Truncate a string to specified length and add ellipsis
 * 
 * @param str - The string to truncate
 * @param length - Maximum length before truncation
 * @returns Truncated string with ellipsis if needed
 * 
 * Example:
 * truncate('Very long diagnosis text', 15) → 'Very long diagn...'
 * 
 * Use case: Displaying long text in limited space (diagnoses, notes)
 */
export const truncate = (str: string, length: number): string => {
  if (str.length <= length) return str;
  return str.slice(0, length) + '...';
};

// ============================================================================
// NUMBER HELPERS - Functions for number manipulation and validation
// ============================================================================

/**
 * clamp Function
 * 
 * Purpose: Constrain a number between minimum and maximum values
 * 
 * @param value - The number to clamp
 * @param min - Minimum allowed value
 * @param max - Maximum allowed value
 * @returns Clamped value within the specified range
 * 
 * Example:
 * clamp(150, 0, 100) → 100
 * clamp(-10, 0, 100) → 0
 * 
 * Use case: Validating vital signs, age ranges, scores
 */
export const clamp = (value: number, min: number, max: number): number => {
  return Math.min(Math.max(value, min), max);
};

/**
 * roundToDecimal Function
 * 
 * Purpose: Round a number to specified decimal places
 * 
 * @param value - The number to round
 * @param decimals - Number of decimal places
 * @returns Rounded number
 * 
 * Example:
 * roundToDecimal(3.14159, 2) → 3.14
 * 
 * Use case: Formatting vital signs, medication dosages, scores
 */
export const roundToDecimal = (value: number, decimals: number): number => {
  return Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals);
};

// ============================================================================
// BOOLEAN HELPERS - Functions for boolean operations and validation
// ============================================================================

/**
 * isTruthy Function
 * 
 * Purpose: Check if a value is truthy (converts to true)
 * 
 * @param value - The value to check
 * @returns Boolean indicating if value is truthy
 * 
 * Example:
 * isTruthy('hello') → true
 * isTruthy(0) → false
 * 
 * Use case: Validating form inputs, checking optional fields
 */
export const isTruthy = (value: any): boolean => {
  return Boolean(value);
};

/**
 * isFalsy Function
 * 
 * Purpose: Check if a value is falsy (converts to false)
 * 
 * @param value - The value to check
 * @returns Boolean indicating if value is falsy
 * 
 * Example:
 * isFalsy('') → true
 * isFalsy(null) → true
 * 
 * Use case: Checking for empty or null values
 */
export const isFalsy = (value: any): boolean => {
  return !Boolean(value);
};

// ============================================================================
// FUNCTION HELPERS - Functions for function manipulation and optimization
// ============================================================================

/**
 * debounce Function
 * 
 * Purpose: Create a debounced version of a function that delays execution
 * 
 * @param func - The function to debounce
 * @param delay - Delay in milliseconds
 * @returns Debounced function
 * 
 * Example:
 * const debouncedSearch = debounce(searchPatients, 300);
 * // Only executes search after 300ms of no input
 * 
 * Use case: Search inputs, API calls, form validation
 */
export const debounce = <T extends (...args: any[]) => any>(
  func: T,
  delay: number
): ((...args: Parameters<T>) => void) => {
  let timeoutId: NodeJS.Timeout;
  return (...args: Parameters<T>) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func(...args), delay);
  };
};

/**
 * throttle Function
 * 
 * Purpose: Create a throttled version of a function that limits execution frequency
 * 
 * @param func - The function to throttle
 * @param delay - Minimum time between executions in milliseconds
 * @returns Throttled function
 * 
 * Example:
 * const throttledScroll = throttle(handleScroll, 100);
 * // Only executes once every 100ms maximum
 * 
 * Use case: Scroll events, resize events, real-time updates
 */
export const throttle = <T extends (...args: any[]) => any>(
  func: T,
  delay: number
): ((...args: Parameters<T>) => void) => {
  let lastCall = 0;
  return (...args: Parameters<T>) => {
    const now = Date.now();
    if (now - lastCall >= delay) {
      lastCall = now;
      func(...args);
    }
  };
};

// ============================================================================
// MEDICAL HELPERS - Healthcare-specific utility functions
// ============================================================================

/**
 * getPriorityColor Function
 * 
 * Purpose: Get the appropriate color for alert priority levels
 * 
 * @param priority - The alert priority level
 * @returns Hex color code for the priority
 * 
 * Color Mapping:
 * - CRITICAL: Red (#F44336) - Immediate attention required
 * - HIGH: Orange (#FF9800) - High priority attention
 * - MEDIUM: Blue (#2196F3) - Normal priority
 * - LOW: Green (#4CAF50) - Low priority
 * - Default: Gray (#9E9E9E) - Unknown priority
 * 
 * Use case: Color-coding alerts, patient cards, status indicators
 */
export const getPriorityColor = (priority: AlertPriority): string => {
  switch (priority) {
    case 'CRITICAL':
      return '#F44336';  // Red for critical alerts
    case 'HIGH':
      return '#FF9800';  // Orange for high priority
    case 'MEDIUM':
      return '#2196F3';  // Blue for medium priority
    case 'LOW':
      return '#4CAF50';  // Green for low priority
    default:
      return '#9E9E9E';  // Gray for unknown priority
  }
};

/**
 * getStatusColor Function
 * 
 * Purpose: Get the appropriate color for patient status levels
 * 
 * @param status - The patient status
 * @returns Hex color code for the status
 * 
 * Color Mapping:
 * - CRITICAL: Red (#F44336) - Critical patient condition
 * - ACTIVE: Blue (#2196F3) - Currently under care
 * - PENDING: Orange (#FF9800) - Waiting for treatment
 * - DISCHARGED: Green (#4CAF50) - Successfully discharged
 * - TRANSFERRED: Gray (#9E9E9E) - Transferred to another facility
 * 
 * Use case: Color-coding patient cards, status badges, dashboard indicators
 */
export const getStatusColor = (status: PatientStatus): string => {
  switch (status) {
    case 'CRITICAL':
      return '#F44336';  // Red for critical patients
    case 'ACTIVE':
      return '#2196F3';  // Blue for active patients
    case 'PENDING':
      return '#FF9800';  // Orange for pending patients
    case 'DISCHARGED':
      return '#4CAF50';  // Green for discharged patients
    case 'TRANSFERRED':
      return '#9E9E9E';  // Gray for transferred patients
    default:
      return '#9E9E9E';  // Gray for unknown status
  }
};

/**
 * calculateAge Function
 * 
 * Purpose: Calculate age from date of birth
 * 
 * @param dateOfBirth - The patient's date of birth
 * @returns Age in years
 * 
 * Logic:
 * - Calculates year difference
 * - Adjusts for month and day to get accurate age
 * - Handles leap years and month length variations
 * 
 * Example:
 * calculateAge(new Date('1990-05-15')) → 33 (if current year is 2023)
 * 
 * Use case: Displaying patient age, age-based calculations, demographics
 */
export const calculateAge = (dateOfBirth: Date): number => {
  const today = new Date();
  let age = today.getFullYear() - dateOfBirth.getFullYear();
  const monthDiff = today.getMonth() - dateOfBirth.getMonth();
  
  // Adjust age if birthday hasn't occurred this year
  if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < dateOfBirth.getDate())) {
    age--;
  }
  
  return age;
};

// ============================================================================
// VALIDATION HELPERS - Functions for data validation
// ============================================================================

/**
 * isValidEmail Function
 * 
 * Purpose: Validate email address format
 * 
 * @param email - The email address to validate
 * @returns Boolean indicating if email is valid
 * 
 * Validation Rules:
 * - Must contain @ symbol
 * - Must have text before and after @
 * - Must have domain extension
 * 
 * Use case: Login forms, user registration, contact information
 */
export const isValidEmail = (email: string): boolean => {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
};

/**
 * isValidPhone Function
 * 
 * Purpose: Validate phone number format
 * 
 * @param phone - The phone number to validate
 * @returns Boolean indicating if phone number is valid
 * 
 * Validation Rules:
 * - Minimum 10 digits
 * - Allows +, spaces, hyphens, parentheses
 * - International format supported
 * 
 * Use case: Contact information, emergency contacts
 */
export const isValidPhone = (phone: string): boolean => {
  const phoneRegex = /^\+?[\d\s\-\(\)]{10,}$/;
  return phoneRegex.test(phone);
};

/**
 * isValidMRN Function
 * 
 * Purpose: Validate Medical Record Number format
 * 
 * @param mrn - The MRN to validate
 * @returns Boolean indicating if MRN is valid
 * 
 * Validation Rules:
 * - 6-12 characters long
 * - Alphanumeric only (A-Z, 0-9)
 * - No special characters or spaces
 * 
 * Use case: Patient identification, medical record lookup
 */
export const isValidMRN = (mrn: string): boolean => {
  const mrnRegex = /^[A-Z0-9]{6,12}$/;
  return mrnRegex.test(mrn);
};

// ============================================================================
// ASYNC HELPERS - Functions for asynchronous operations
// ============================================================================

/**
 * sleep Function
 * 
 * Purpose: Create a delay for specified milliseconds
 * 
 * @param ms - Milliseconds to delay
 * @returns Promise that resolves after the delay
 * 
 * Example:
 * await sleep(1000); // Wait for 1 second
 * 
 * Use case: Rate limiting, loading states, animation delays
 */
export const sleep = (ms: number): Promise<void> => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

/**
 * retry Function
 * 
 * Purpose: Retry an async function with exponential backoff
 * 
 * @param fn - The async function to retry
 * @param retries - Number of retry attempts (default: 3)
 * @param delay - Initial delay in milliseconds (default: 1000)
 * @returns Promise that resolves with function result or rejects after all retries
 * 
 * Retry Strategy:
 * - Exponential backoff (delay doubles after each failure)
 * - Stops after specified number of retries
 * - Throws error if all retries fail
 * 
 * Example:
 * const result = await retry(fetchPatientData, 3, 1000);
 * 
 * Use case: API calls, network requests, database operations
 */
export const retry = async <T>(
  fn: () => Promise<T>,
  retries: number = 3,
  delay: number = 1000
): Promise<T> => {
  try {
    return await fn();
  } catch (error) {
    if (retries > 0) {
      await sleep(delay);
      return retry(fn, retries - 1, delay * 2);  // Exponential backoff
    }
    throw error;
  }
};

/*
 * End of File: helpers.ts
 * Design & Developed by Tech4Biz Solutions
 * Copyright (c) Spurrin Innovations. All rights reserved.
 */ 