<?php
/**
 * Enterprise HRM ERP System - Core Functions
 */

// Prevent direct access
if (!defined('HRM_ACCESS')) {
    die('Direct access not allowed');
}

/**
 * Get system setting from database
 */
function getSetting($key, $default = null) {
    static $settings_cache = [];
    
    if (isset($settings_cache[$key])) {
        return $settings_cache[$key];
    }
    
    try {
        $db = getDB();
        $stmt = $db->prepare("SELECT setting_value, setting_type FROM system_settings WHERE setting_key = ?");
        $stmt->execute([$key]);
        $setting = $stmt->fetch();
        
        if ($setting) {
            $value = $setting['setting_value'];
            
            // Convert based on type
            switch ($setting['setting_type']) {
                case 'number':
                    $value = is_numeric($value) ? (strpos($value, '.') !== false ? (float)$value : (int)$value) : $default;
                    break;
                case 'boolean':
                    $value = filter_var($value, FILTER_VALIDATE_BOOLEAN);
                    break;
                case 'json':
                    $value = json_decode($value, true);
                    break;
            }
            
            $settings_cache[$key] = $value;
            return $value;
        }
    } catch (Exception $e) {
        error_log("Error getting setting {$key}: " . $e->getMessage());
    }
    
    return $default;
}

/**
 * Set system setting
 */
function setSetting($key, $value, $type = 'string', $category = null, $description = null) {
    try {
        $db = getDB();
        
        // Convert value based on type
        if ($type === 'json') {
            $value = json_encode($value);
        } elseif ($type === 'boolean') {
            $value = $value ? '1' : '0';
        }
        
        $stmt = $db->prepare("
            INSERT INTO system_settings (setting_key, setting_value, setting_type, setting_category, setting_description, updated_by)
            VALUES (?, ?, ?, ?, ?, ?)
            ON DUPLICATE KEY UPDATE 
                setting_value = VALUES(setting_value),
                setting_type = VALUES(setting_type),
                updated_by = VALUES(updated_by),
                updated_at = CURRENT_TIMESTAMP
        ");
        
        $user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
        $stmt->execute([$key, $value, $type, $category, $description, $user_id]);
        
        return true;
    } catch (Exception $e) {
        error_log("Error setting setting {$key}: " . $e->getMessage());
        return false;
    }
}

/**
 * Sanitize input
 */
function sanitize($data) {
    if (is_array($data)) {
        return array_map('sanitize', $data);
    }
    return htmlspecialchars(strip_tags(trim($data)), ENT_QUOTES, 'UTF-8');
}

/**
 * Validate email
 */
function validateEmail($email) {
    return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

/**
 * Format date
 */
function formatDate($date, $format = null) {
    if (empty($date) || $date === '0000-00-00' || $date === '0000-00-00 00:00:00') {
        return '';
    }
    
    if ($format === null) {
        $format = getSetting('DATE_FORMAT', 'Y-m-d');
    }
    
    try {
        $dateObj = new DateTime($date);
        return $dateObj->format($format);
    } catch (Exception $e) {
        return '';
    }
}

/**
 * Format datetime
 */
function formatDateTime($datetime, $format = null) {
    if (empty($datetime) || $datetime === '0000-00-00 00:00:00') {
        return '';
    }
    
    if ($format === null) {
        $format = getSetting('DATETIME_FORMAT', 'Y-m-d H:i:s');
    }
    
    try {
        $dateObj = new DateTime($datetime);
        return $dateObj->format($format);
    } catch (Exception $e) {
        return '';
    }
}

/**
 * Format currency based on system currency setting
 */
function formatCurrency($amount, $currencyCode = null) {
    // Get currency code from settings if not provided
    if ($currencyCode === null) {
        try {
            $db = getDB();
            // Try settings table first (used by admin/settings.php)
            $stmt = $db->prepare("SELECT setting_value FROM settings WHERE setting_key = 'CURRENCY' LIMIT 1");
            $stmt->execute();
            $result = $stmt->fetch();
            if (!$result) {
                // Try system_settings table as fallback
                $stmt = $db->prepare("SELECT setting_value FROM system_settings WHERE setting_key = 'CURRENCY' LIMIT 1");
                $stmt->execute();
                $result = $stmt->fetch();
            }
            $currencyCode = $result ? $result['setting_value'] : 'USD';
        } catch (Exception $e) {
            $currencyCode = 'USD';
        }
    }
    
    // Currency symbols mapping
    $currencySymbols = [
        'USD' => '$',
        'INR' => '₹',
        'EUR' => '€',
        'GBP' => '£',
        'JPY' => '¥',
        'AUD' => 'A$',
        'CAD' => 'C$',
        'CHF' => 'CHF',
        'CNY' => '¥',
        'SGD' => 'S$',
        'HKD' => 'HK$',
        'AED' => 'د.إ',
        'SAR' => '﷼',
        'MYR' => 'RM',
        'THB' => '฿',
        'PKR' => '₨',
        'BRL' => 'R$',
        'ZAR' => 'R',
        'MXN' => '$',
        'KRW' => '₩',
        'NZD' => 'NZ$',
        'SEK' => 'kr',
        'NOK' => 'kr',
        'DKK' => 'kr',
        'PLN' => 'zł',
        'RUB' => '₽',
        'TRY' => '₺',
    ];
    
    $symbol = $currencySymbols[$currencyCode] ?? $currencyCode;
    
    // Format amount (2 decimal places for most currencies, 0 for JPY)
    $decimals = in_array($currencyCode, ['JPY', 'KRW']) ? 0 : 2;
    
    return $symbol . number_format((float)$amount, $decimals);
}

/**
 * Get current system currency code
 */
function getSystemCurrency() {
    try {
        $db = getDB();
        // Try settings table first (used by admin/settings.php)
        $stmt = $db->prepare("SELECT setting_value FROM settings WHERE setting_key = 'CURRENCY' LIMIT 1");
        $stmt->execute();
        $result = $stmt->fetch();
        if (!$result) {
            // Try system_settings table as fallback
            $stmt = $db->prepare("SELECT setting_value FROM system_settings WHERE setting_key = 'CURRENCY' LIMIT 1");
            $stmt->execute();
            $result = $stmt->fetch();
        }
        return $result ? $result['setting_value'] : 'USD';
    } catch (Exception $e) {
        return 'USD';
    }
}

/**
 * Calculate days between dates
 */
function calculateDays($startDate, $endDate) {
    try {
        $start = new DateTime($startDate);
        $end = new DateTime($endDate);
        $diff = $start->diff($end);
        return $diff->days + 1; // Include both start and end date
    } catch (Exception $e) {
        return 0;
    }
}

/**
 * Check if user has permission (with branch-wise support)
 */
function hasPermission($permissionCode) {
    if (!isset($_SESSION['user_id'])) {
        return false;
    }
    
    // Super admin has all permissions
    $roleCode = strtolower($_SESSION['role_code'] ?? '');
    if ($roleCode === 'super_admin') {
        return true;
    }
    
    $siteId = getCurrentSiteId();
    $roleId = $_SESSION['role_id'] ?? 0;
    
    // Check branch-specific permissions first
    if ($siteId && $roleId) {
        try {
            $db = getDB();
            
            // Check if branch permissions table exists
            $stmt = $db->query("SHOW TABLES LIKE 'site_role_permissions'");
            if ($stmt->rowCount() > 0) {
                // Check for branch-specific permission
                $stmt = $db->prepare("
                    SELECT COUNT(*) 
                    FROM site_role_permissions srp
                    INNER JOIN permissions p ON srp.permission_id = p.permission_id
                    WHERE srp.site_id = ? AND srp.role_id = ? AND p.permission_code = ?
                ");
                $stmt->execute([$siteId, $roleId, $permissionCode]);
                $branchPermissionCount = $stmt->fetchColumn();
                
                // If branch-specific permissions exist for this role, use only those
                if ($branchPermissionCount > 0) {
                    return $branchPermissionCount > 0;
                }
            }
        } catch (Exception $e) {
            error_log("Error checking branch permissions: " . $e->getMessage());
        }
    }
    
    // HR admin has all permissions (unless branch-specific restrictions apply)
    if ($roleCode === 'hr_admin') {
        // If branch permissions table exists and has entries for this role, check them
        if ($siteId && $roleId) {
            try {
                $db = getDB();
                $stmt = $db->query("SHOW TABLES LIKE 'site_role_permissions'");
                if ($stmt->rowCount() > 0) {
                    // Check if any branch-specific permissions exist for this role
                    $stmt = $db->prepare("SELECT COUNT(*) FROM site_role_permissions WHERE site_id = ? AND role_id = ?");
                    $stmt->execute([$siteId, $roleId]);
                    $hasBranchPermissions = $stmt->fetchColumn() > 0;
                    
                    // If branch-specific permissions exist, check them; otherwise allow all
                    if ($hasBranchPermissions) {
                        $stmt = $db->prepare("
                            SELECT COUNT(*) 
                            FROM site_role_permissions srp
                            INNER JOIN permissions p ON srp.permission_id = p.permission_id
                            WHERE srp.site_id = ? AND srp.role_id = ? AND p.permission_code = ?
                        ");
                        $stmt->execute([$siteId, $roleId, $permissionCode]);
                        return $stmt->fetchColumn() > 0;
                    }
                }
            } catch (Exception $e) {
                error_log("Error checking HR admin branch permissions: " . $e->getMessage());
            }
        }
        return true; // Default: HR admin has all permissions
    }
    
    // Check if permissions are set in session
    if (!isset($_SESSION['permissions'])) {
        // Try to load permissions from database
        try {
            $db = getDB();
            $stmt = $db->prepare("
                SELECT p.permission_code
                FROM permissions p
                INNER JOIN role_permissions rp ON p.permission_id = rp.permission_id
                WHERE rp.role_id = ?
            ");
            $stmt->execute([$roleId]);
            $_SESSION['permissions'] = $stmt->fetchAll(PDO::FETCH_COLUMN);
        } catch (Exception $e) {
            error_log("Error loading permissions: " . $e->getMessage());
            $_SESSION['permissions'] = [];
        }
    }
    
    return in_array($permissionCode, $_SESSION['permissions'] ?? []);
}

/**
 * Require permission or redirect
 */
function requirePermission($permissionCode) {
    // Super admin and HR admin have all permissions
    $allowedRoles = ['super_admin', 'hr_admin'];
    $roleCode = strtolower($_SESSION['role_code'] ?? '');
    if (!empty($roleCode) && in_array($roleCode, $allowedRoles)) {
        return;
    }
    
    if (!hasPermission($permissionCode)) {
        $_SESSION['error'] = 'You do not have permission to access this resource.';
        header('Location: ' . BASE_URL . '/dashboard.php');
        exit;
    }
}

/**
 * Check if user has admin access (super_admin or hr_admin)
 */
function hasAdminAccess() {
    startSession();
    if (!isset($_SESSION['user_id'])) {
        return false;
    }
    
    // Get role_code from session or load from database
    $roleCode = $_SESSION['role_code'] ?? '';
    
    // If role_code not in session, try to load it
    if (empty($roleCode) && isset($_SESSION['role_id'])) {
        try {
            $db = getDB();
            $stmt = $db->prepare("SELECT role_code FROM roles WHERE role_id = ?");
            $stmt->execute([$_SESSION['role_id']]);
            $role = $stmt->fetch();
            if ($role) {
                $roleCode = $role['role_code'];
                $_SESSION['role_code'] = $roleCode;
            }
        } catch (Exception $e) {
            error_log("Error loading role_code: " . $e->getMessage());
        }
    }
    
    // Allow super_admin and hr_admin (case-insensitive)
    $roleCodeLower = strtolower($roleCode);
    return in_array($roleCodeLower, ['super_admin', 'hr_admin']);
}

/**
 * Refresh user permissions in session
 * Call this after role or permission changes
 */
function refreshUserPermissions($userId = null) {
    startSession();
    
    if ($userId === null) {
        $userId = $_SESSION['user_id'] ?? null;
    }
    
    if (!$userId) {
        return false;
    }
    
    try {
        $db = getDB();
        
        // Get role_id
        $stmt = $db->prepare("SELECT role_id FROM users WHERE user_id = ?");
        $stmt->execute([$userId]);
        $user = $stmt->fetch();
        
        if (!$user || !$user['role_id']) {
            return false;
        }
        
        // Get permissions
        $stmt = $db->prepare("
            SELECT p.permission_code
            FROM permissions p
            INNER JOIN role_permissions rp ON p.permission_id = rp.permission_id
            WHERE rp.role_id = ?
        ");
        $stmt->execute([$user['role_id']]);
        $permissions = $stmt->fetchAll(PDO::FETCH_COLUMN);
        
        // Update session
        $_SESSION['permissions'] = $permissions;
        
        // Also update role_code if needed
        $stmt = $db->prepare("SELECT role_code FROM roles WHERE role_id = ?");
        $stmt->execute([$user['role_id']]);
        $role = $stmt->fetch();
        if ($role) {
            $_SESSION['role_code'] = $role['role_code'];
        }
        
        return true;
    } catch (Exception $e) {
        error_log("Error refreshing permissions: " . $e->getMessage());
        return false;
    }
}

/**
 * Log audit trail
 */
function logAudit($action, $tableName = null, $recordId = null, $oldValues = null, $newValues = null) {
    try {
        $db = getDB();
        $stmt = $db->prepare("
            INSERT INTO audit_logs (site_id, user_id, action, table_name, record_id, old_values, new_values, ip_address, user_agent)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        ");
        
        $siteId = isset($_SESSION['site_id']) ? $_SESSION['site_id'] : null;
        $userId = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
        $ipAddress = $_SERVER['REMOTE_ADDR'] ?? null;
        $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? null;
        
        $oldValuesJson = $oldValues ? json_encode($oldValues) : null;
        $newValuesJson = $newValues ? json_encode($newValues) : null;
        
        $stmt->execute([
            $siteId,
            $userId,
            $action,
            $tableName,
            $recordId,
            $oldValuesJson,
            $newValuesJson,
            $ipAddress,
            $userAgent
        ]);
        
        return true;
    } catch (Exception $e) {
        error_log("Error logging audit: " . $e->getMessage());
        return false;
    }
}

/**
 * Generate unique code
 */
function generateCode($prefix, $table, $codeColumn, $siteId = null) {
    try {
        $db = getDB();
        
        $year = date('Y');
        $month = date('m');
        
        // Try to get the last code
        $sql = "SELECT {$codeColumn} FROM {$table} WHERE {$codeColumn} LIKE ?";
        $params = ["{$prefix}{$year}{$month}%"];
        
        if ($siteId !== null) {
            $sql .= " AND site_id = ?";
            $params[] = $siteId;
        }
        
        $sql .= " ORDER BY {$codeColumn} DESC LIMIT 1";
        
        $stmt = $db->prepare($sql);
        $stmt->execute($params);
        $lastCode = $stmt->fetchColumn();
        
        if ($lastCode) {
            // Extract sequence number
            $sequence = (int)substr($lastCode, -4) + 1;
        } else {
            $sequence = 1;
        }
        
        return sprintf("%s%s%s%04d", $prefix, $year, $month, $sequence);
    } catch (Exception $e) {
        error_log("Error generating code: " . $e->getMessage());
        return $prefix . time();
    }
}

/**
 * Redirect with message
 */
function redirect($url, $message = null, $type = 'success') {
    // Clear any output buffers before redirecting
    while (ob_get_level() > 0) {
        ob_end_clean();
    }
    
    if ($message) {
        $_SESSION[$type] = $message;
    }
    
    // Only send header if headers haven't been sent
    if (!headers_sent()) {
        header('Location: ' . $url);
        exit;
    } else {
        // If headers already sent, use JavaScript redirect
        echo '<script>window.location.href = "' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '";</script>';
        exit;
    }
}

/**
 * Set flash message (helper used by modules)
 */
function setFlashMessage($type, $message) {
    // Sessions are started in init.php; assume already active here
    $_SESSION[$type] = $message;
}

/**
 * Get flash message
 */
function getFlashMessage($type = 'success') {
    if (isset($_SESSION[$type])) {
        $message = $_SESSION[$type];
        unset($_SESSION[$type]);
        return $message;
    }
    return null;
}

/**
 * Validate password strength
 */
function validatePassword($password) {
    $errors = [];
    
    if (strlen($password) < PASSWORD_MIN_LENGTH) {
        $errors[] = "Password must be at least " . PASSWORD_MIN_LENGTH . " characters long.";
    }
    
    if (PASSWORD_REQUIRE_UPPERCASE && !preg_match('/[A-Z]/', $password)) {
        $errors[] = "Password must contain at least one uppercase letter.";
    }
    
    if (PASSWORD_REQUIRE_LOWERCASE && !preg_match('/[a-z]/', $password)) {
        $errors[] = "Password must contain at least one lowercase letter.";
    }
    
    if (PASSWORD_REQUIRE_NUMBER && !preg_match('/[0-9]/', $password)) {
        $errors[] = "Password must contain at least one number.";
    }
    
    if (PASSWORD_REQUIRE_SPECIAL && !preg_match('/[^A-Za-z0-9]/', $password)) {
        $errors[] = "Password must contain at least one special character.";
    }
    
    return $errors;
}

/**
 * Hash password
 */
function hashPassword($password) {
    return password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
}

/**
 * Verify password
 */
function verifyPassword($password, $hash) {
    return password_verify($password, $hash);
}

/**
 * Generate asset URL (CSS, JS, images)
 * Ensures correct path generation for both root and subdirectory installations
 * Works reliably on both XAMPP (localhost) and cPanel (live hosting)
 */
function assetUrl($path) {
    // Remove leading slash from path if present (we'll add it)
    $path = ltrim($path, '/');
    
    // Get BASE_URL (should already be defined in config.php)
    $baseUrl = defined('BASE_URL') ? BASE_URL : '';
    
    // Fallback: If BASE_URL is not set, try to detect it
    if ($baseUrl === '' && !defined('BASE_URL')) {
        // Try to detect from current script location
        if (isset($_SERVER['SCRIPT_NAME'])) {
            $scriptDir = dirname($_SERVER['SCRIPT_NAME']);
            $scriptDir = str_replace('\\', '/', $scriptDir);
            if ($scriptDir !== '/' && $scriptDir !== '.' && $scriptDir !== '') {
                $baseUrl = rtrim($scriptDir, '/');
            }
        }
    }
    
    // Build the URL
    if (!empty($baseUrl)) {
        // Ensure BASE_URL starts with / and doesn't end with /
        if (substr($baseUrl, 0, 1) !== '/') {
            $baseUrl = '/' . $baseUrl;
        }
        $baseUrl = rtrim($baseUrl, '/');
        return $baseUrl . '/' . $path;
    } else {
        // Root installation - return absolute path starting with /
        return '/' . $path;
    }
}

