<?php
/**
 * Helper Functions and Utilities
 * Common functions used across the application
 */

namespace Core;

class Helpers {
    
    /**
     * Calculate distance between two coordinates using Haversine formula
     * Returns distance in kilometers
     */
    public static function calculateDistance($lat1, $lng1, $lat2, $lng2) {
        $earthRadius = 6371; // Earth's radius in km
        
        $dLat = deg2rad($lat2 - $lat1);
        $dLng = deg2rad($lng2 - $lng1);
        
        $a = sin($dLat/2) * sin($dLat/2) +
             cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * 
             sin($dLng/2) * sin($dLng/2);
             
        $c = 2 * atan2(sqrt($a), sqrt(1-$a));
        
        return round($earthRadius * $c, 2);
    }
    
    /**
     * Calculate delivery fee based on distance
     * Uses the economic model: max(DELIVERY_MIN, round(distance_km * DELIVERY_PER_KM))
     */
    public static function calculateDeliveryFee($distanceKm) {
        $deliveryMin = (int)getConfigValue('DELIVERY_MIN', DELIVERY_MIN);
        $deliveryPerKm = (int)getConfigValue('DELIVERY_PER_KM', DELIVERY_PER_KM);
        
        return max($deliveryMin, round($distanceKm * $deliveryPerKm));
    }
    
    /**
     * Calculate total order cost breakdown
     */
    public static function calculateOrderTotal($medicinePrice, $distanceKm) {
        $serviceFee = (int)getConfigValue('SERVICE_FEE', SERVICE_FEE);
        $deliveryFee = self::calculateDeliveryFee($distanceKm);
        
        return [
            'medicine_price' => $medicinePrice,
            'service_fee' => $serviceFee,
            'delivery_fee' => $deliveryFee,
            'total' => $medicinePrice + $serviceFee + $deliveryFee
        ];
    }
    
    /**
     * Calculate payment distribution for completed order
     */
    public static function calculatePaymentDistribution($medicinePrice, $deliveryFee) {
        $serviceFee = (int)getConfigValue('SERVICE_FEE', SERVICE_FEE);
        $pharmacyBonus = (int)getConfigValue('PHARMACY_BONUS_FROM_DELIVERY', PHARMACY_BONUS_FROM_DELIVERY);
        
        return [
            'mediflash' => $serviceFee,
            'pharmacy' => $medicinePrice + $pharmacyBonus,
            'courier' => $deliveryFee - $pharmacyBonus
        ];
    }
    
    /**
     * Format price in FCFA
     */
    public static function formatPrice($amount) {
        return number_format($amount, 0, ',', ' ') . ' FCFA';
    }
    
    /**
     * Format distance
     */
    public static function formatDistance($km) {
        if ($km < 1) {
            return round($km * 1000) . ' m';
        }
        
        return number_format($km, 1) . ' km';
    }
    
    /**
     * Generate unique order ID
     */
    public static function generateOrderId() {
        return 'SOS' . strtoupper(substr(uniqid(), -6)) . sprintf('%03d', mt_rand(1, 999));
    }
    
    /**
     * Generate UUID v4
     */
    public static function generateUuid() {
        return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
            mt_rand(0, 0xffff), mt_rand(0, 0xffff),
            mt_rand(0, 0xffff),
            mt_rand(0, 0x0fff) | 0x4000,
            mt_rand(0, 0x3fff) | 0x8000,
            mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
        );
    }
    
    /**
     * Validate phone number (basic Ivorian format)
     */
    public static function validatePhone($phone) {
        // Remove spaces and dashes
        $phone = preg_replace('/[\s-]/', '', $phone);
        
        // Check for Ivorian phone number patterns
        return preg_match('/^(\+225)?[0-9]{8,10}$/', $phone);
    }
    
    /**
     * Format phone number
     */
    public static function formatPhone($phone) {
        $phone = preg_replace('/[\s-]/', '', $phone);
        
        if (strpos($phone, '+225') === 0) {
            return $phone;
        }
        
        if (strlen($phone) === 8) {
            return '+225 ' . $phone;
        }
        
        return $phone;
    }
    
    /**
     * Validate coordinates
     */
    public static function validateCoordinates($lat, $lng) {
        $lat = (float)$lat;
        $lng = (float)$lng;
        
        // Check if coordinates are in Côte d'Ivoire bounds (approximately)
        return ($lat >= 4.0 && $lat <= 10.5) && ($lng >= -8.5 && $lng <= -2.5);
    }
    
    /**
     * Sanitize text input
     */
    public static function sanitizeText($text) {
        return htmlspecialchars(trim($text), ENT_QUOTES, 'UTF-8');
    }
    
    /**
     * Generate random string
     */
    public static function randomString($length = 10) {
        return substr(str_shuffle(str_repeat('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/62))), 1, $length);
    }
    
    /**
     * Check if request is AJAX
     */
    public static function isAjax() {
        return !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && 
               strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
    }
    
    /**
     * Get client IP address
     */
    public static function getClientIp() {
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            return $_SERVER['HTTP_CLIENT_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            return $_SERVER['HTTP_X_FORWARDED_FOR'];
        } else {
            return $_SERVER['REMOTE_ADDR'];
        }
    }
    
    /**
     * Log to file
     */
    public static function log($message, $level = 'info', $file = 'app.log') {
        $logFile = LOG_PATH . $file;
        $timestamp = date('Y-m-d H:i:s');
        $ip = self::getClientIp();
        
        $logMessage = "[{$timestamp}] {$level}: {$message} | IP: {$ip}" . PHP_EOL;
        
        file_put_contents($logFile, $logMessage, FILE_APPEND | LOCK_EX);
    }
    
    /**
     * Send JSON response
     */
    public static function jsonResponse($data, $code = 200) {
        http_response_code($code);
        header('Content-Type: application/json');
        echo json_encode($data);
        exit();
    }
    
    /**
     * Redirect to URL
     */
    public static function redirect($url, $code = 302) {
        header("Location: {$url}", true, $code);
        exit();
    }
    
    /**
     * Get time ago string in French
     */
    public static function timeAgo($datetime) {
        $now = new \DateTime();
        $time = new \DateTime($datetime);
        $diff = $now->diff($time);
        
        if ($diff->y > 0) {
            return $diff->y . ' an' . ($diff->y > 1 ? 's' : '');
        } elseif ($diff->m > 0) {
            return $diff->m . ' mois';
        } elseif ($diff->d > 0) {
            return $diff->d . ' jour' . ($diff->d > 1 ? 's' : '');
        } elseif ($diff->h > 0) {
            return $diff->h . ' heure' . ($diff->h > 1 ? 's' : '');
        } elseif ($diff->i > 0) {
            return $diff->i . ' minute' . ($diff->i > 1 ? 's' : '');
        } else {
            return 'À l\'instant';
        }
    }
    
    /**
     * Generate CSRF token
     */
    public static function generateCsrfToken() {
        if (!isset($_SESSION['csrf_token'])) {
            $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        }
        
        return $_SESSION['csrf_token'];
    }
    
    /**
     * Validate CSRF token
     */
    public static function validateCsrfToken($token) {
        return isset($_SESSION['csrf_token']) && 
               hash_equals($_SESSION['csrf_token'], $token);
    }
    
    /**
     * Create directory if it doesn't exist
     */
    public static function ensureDirectory($path) {
        if (!is_dir($path)) {
            mkdir($path, 0755, true);
        }
        
        return $path;
    }
    
    /**
     * Get order status in French
     */
    public static function getOrderStatusText($status) {
        $statuses = [
            'CREATED' => 'Créée',
            'PHARMACY_CONFIRMED' => 'Confirmée par la pharmacie',
            'COURIER_ASSIGNED' => 'Livreur assigné',
            'PICKED_UP' => 'Récupérée',
            'DELIVERED' => 'Livrée',
            'CLOSED' => 'Terminée'
        ];
        
        return $statuses[$status] ?? $status;
    }
    
    /**
     * Get order status color class
     */
    public static function getOrderStatusColor($status) {
        $colors = [
            'CREATED' => 'text-blue-600 bg-blue-100',
            'PHARMACY_CONFIRMED' => 'text-green-600 bg-green-100',
            'COURIER_ASSIGNED' => 'text-purple-600 bg-purple-100',
            'PICKED_UP' => 'text-yellow-600 bg-yellow-100',
            'DELIVERED' => 'text-green-700 bg-green-200',
            'CLOSED' => 'text-gray-600 bg-gray-100'
        ];
        
        return $colors[$status] ?? 'text-gray-600 bg-gray-100';
    }
}
?>
