<?php
/**
 * WHMCS Server Module for WHP (Web Hosting Panel)
 * 
 * This module allows WHMCS to manage accounts on WHP servers
 */

if (!defined("WHMCS")) {
    die("This file cannot be accessed directly");
}

// Ensure required functions exist
if (!function_exists('logModuleCall')) {
    function logModuleCall($module, $action, $request, $response) {
        // Fallback logging function if WHMCS function doesn't exist
        error_log("[WHMCS-$module] $action: " . print_r($request, true) . " -> " . print_r($response, true));
    }
}

/**
 * Define module related meta data.
 */
function whp_MetaData() {
    return array(
        'DisplayName' => 'WHP (Web Hosting Panel)',
        'APIVersion' => '1.1',
        'RequiresServer' => true,
        'DefaultNonSSLPort' => '80',
        'DefaultSSLPort' => '443',
        'ServiceSingleSignOnLabel' => 'Login to Control Panel',
        'AdminSingleSignOnLabel' => 'Login to Control Panel as User',
    );
}

/**
 * Helper function to standardize server data extraction from WHMCS params
 */
function whp_getServerData(array $params) {
    // WHMCS passes server details differently depending on the context
    if (isset($params['serverhostname'])) {
        // Direct server configuration (TestConnection, some admin functions)
        return array(
            'hostname' => $params['serverhostname'],
            'port' => $params['serverport'],
            'secure' => $params['serversecure'] == 'on',
            'username' => $params['serverusername'],
            'password' => $params['serverpassword']
        );
    } elseif (isset($params['serverdata'])) {
        // Nested serverdata (most service functions)
        return $params['serverdata'];
    } else {
        // Fallback - params may contain server details directly
        return $params;
    }
}

/**
 * Get base plan resources from WHMCS product configuration
 */
function whp_getBaseResources($params) {
    // In WHMCS, the base plan resources are stored in the module configuration
    // These are the values you set in the Module Settings tab for the product
    // WHMCS passes these as configoption1, configoption2, etc. based on the order in whp_ConfigOptions()
    
    // Extract base resources from module configuration
    // These correspond to the order defined in whp_ConfigOptions() function:
    // 1. CPU Cores, 2. Memory (MB), 3. Disk Space (MB), 4. Email Accounts, 5. Email Storage (MB)
    $baseResources = array(
        'cpu_cores' => floatval($params['configoption1'] ?? 0.5),
        'memory_mb' => intval($params['configoption2'] ?? 512),
        'disk_mb' => intval($params['configoption3'] ?? 1000),
        'email_accounts' => intval($params['configoption4'] ?? 0),
        'email_storage_mb' => intval($params['configoption5'] ?? 1000),
        'archived_mailboxes' => intval($params['configoption7'] ?? 0),
        // configoption8: Sitesmith AI Builder (Yes/No)
        'sitesmith_enabled' => !empty($params['configoption8']) ? 1 : 0,
    );

    // Log what we found for debugging
    logModuleCall('whp', 'getBaseResources', array(
        'all_params' => array_keys($params),
        'configoption1_cpu_cores' => $params['configoption1'] ?? 'not set',
        'configoption2_memory_mb' => $params['configoption2'] ?? 'not set',
        'configoption3_disk_mb' => $params['configoption3'] ?? 'not set',
        'configoption4_email_accounts' => $params['configoption4'] ?? 'not set',
        'configoption5_email_storage_mb' => $params['configoption5'] ?? 'not set',
        'configoption7_archived_mailboxes' => $params['configoption7'] ?? 'not set',
        'configoption8_sitesmith_enabled' => $params['configoption8'] ?? 'not set',
        'extracted_base_resources' => $baseResources,
        'pid' => $params['pid'] ?? 'not set'
    ), 'Base resource extraction from module configuration');
    
    return $baseResources;
}

/**
 * Define product configuration options.
 */
function whp_ConfigOptions() {
    return array(
        'CPU Cores' => array(
            'Type' => 'text',
            'Size' => '10',
            'Default' => '1',
            'Description' => 'Number of CPU cores allocated',
        ),
        'Memory (MB)' => array(
            'Type' => 'text',
            'Size' => '10',
            'Default' => '512',
            'Description' => 'Memory allocation in MB',
        ),
        'Disk Space (MB)' => array(
            'Type' => 'text',
            'Size' => '10',
            'Default' => '1000',
            'Description' => 'Disk space allocation in MB',
        ),
        'Email Accounts' => array(
            'Type' => 'text',
            'Size' => '10',
            'Default' => '0',
            'Description' => 'Number of email accounts allowed',
        ),
        'Email Storage (MB)' => array(
            'Type' => 'text',
            'Size' => '10',
            'Default' => '1000',
            'Description' => 'Total email storage allocation in MB',
        ),
        'Account Type' => array(
            'Type' => 'dropdown',
            'Options' => 'full,domain_dns,mail_dns',
            'Description' => 'Account type: Full Hosting, Domain/DNS Only, or Mail/DNS Only',
            'Default' => 'full',
        ),
        'Max Archived Mailboxes' => array(
            'Type' => 'text',
            'Size' => '10',
            'Default' => '0',
            'Description' => 'Number of mailboxes the customer may enable archival on (Bichon)',
        ),
        'Sitesmith AI Builder' => array(
            'Type' => 'yesno',
            'Description' => 'Enable Sitesmith AI Builder for this account',
        ),
    );
}

/**
 * Create account on the remote server.
 */
function whp_CreateAccount(array $params) {
    try {
        $serverdata = whp_getServerData($params);
        
        
        $username = $params['username'];
        $password = $params['password'];
        $domain = $params['domain'] ?? '';
        $configoptions = $params['configoptions'];
        
        // Debug logging - log what WHMCS is passing to the module
        logModuleCall('whp', 'CreateAccount_ConfigOptions', array(
            'username' => $username,
            'configoptions_raw' => $configoptions,
            'all_params_keys' => array_keys($params),
            'producttype' => $params['producttype'] ?? 'not set',
            'pid' => $params['pid'] ?? 'not set',
            'serviceid' => $params['serviceid'] ?? 'not set',
            'customfields' => $params['customfields'] ?? array()
        ), 'WHMCS configuration debugging');
        
        // Get base plan resources from WHMCS product configuration
        // These should be set in the product/plan configuration in WHMCS admin
        $baseResources = whp_getBaseResources($params);
        
        // Configurable options are customer upgrades on top of base resources
        $upgradeResources = array(
            'cpu_cores' => floatval($configoptions['CPU Cores'] ?? 0),
            'memory_mb' => intval($configoptions['Memory (MB)'] ?? 0),
            'disk_mb' => intval($configoptions['Disk Space (MB)'] ?? 0),
            'email_accounts' => intval($configoptions['Email Accounts'] ?? 0),
            'email_storage_mb' => intval($configoptions['Email Storage (MB)'] ?? 0),
            'archived_mailboxes' => intval($configoptions['Max Archived Mailboxes'] ?? 0),
        );

        // Combine base resources + configurable option upgrades
        $finalResources = array(
            'cpu_cores' => $baseResources['cpu_cores'] + $upgradeResources['cpu_cores'],
            'memory_mb' => $baseResources['memory_mb'] + $upgradeResources['memory_mb'],
            'disk_mb' => $baseResources['disk_mb'] + $upgradeResources['disk_mb'],
            'email_accounts' => $baseResources['email_accounts'] + $upgradeResources['email_accounts'],
            'email_storage_mb' => $baseResources['email_storage_mb'] + $upgradeResources['email_storage_mb'],
            'archived_mailboxes' => $baseResources['archived_mailboxes'] + $upgradeResources['archived_mailboxes'],
            // sitesmith_enabled is a boolean flag, not additive — base value wins
            'sitesmith_enabled' => $baseResources['sitesmith_enabled'],
        );

        // Extract account type from config options (configoption6 = Account Type)
        $account_type = $params['configoption6'] ?? 'full';
        if (!in_array($account_type, ['full', 'domain_dns', 'mail_dns'])) {
            $account_type = 'full';
        }

        // Prepare API request
        $apiData = array(
            'username' => $username,
            'password' => $password,
            'resources' => $finalResources,
            'account_type' => $account_type,
        );

        // Debug logging - log the resource calculation
        logModuleCall('whp', 'CreateAccount_ResourceCalculation', array(
            'base_resources' => $baseResources,
            'upgrade_resources' => $upgradeResources,
            'final_resources' => $finalResources
        ), 'Resource calculation for WHP API');
        
        // Debug logging - log what we're sending to WHP
        logModuleCall('whp', 'CreateAccount_SendingToWHP', array(
            'username' => $username,
            'resources_being_sent' => $apiData['resources']
        ), 'Resources being sent to WHP API');
        
        // Add domain if provided
        if (!empty($domain)) {
            $apiData['domain'] = $domain;
        }
        
        // Make API call to create user
        $response = whp_api_call($serverdata, 'POST', 'users.php?action=create', $apiData);
        
        if ($response['status'] === 'success') {
            return 'success';
        } else {
            return 'Account creation failed: ' . $response['message'];
        }
        
    } catch (Exception $e) {
        logModuleCall('whp', __FUNCTION__, $params, $e->getMessage());
        return 'Error: ' . $e->getMessage();
    }
}

/**
 * Suspend account on the remote server.
 */
function whp_SuspendAccount(array $params) {
    try {
        // WHP doesn't have built-in suspension functionality
        $username = $params['username'];
        
        logModuleCall('whp', __FUNCTION__, $params, 'Suspension requested for user: ' . $username . ' - WHP does not support account suspension');
        
        // Return success since WHMCS requires it, but log that no action was taken
        return 'success';
        
    } catch (Exception $e) {
        logModuleCall('whp', __FUNCTION__, $params, $e->getMessage());
        return 'Error: ' . $e->getMessage();
    }
}

/**
 * Unsuspend account on the remote server.
 */
function whp_UnsuspendAccount(array $params) {
    try {
        // WHP doesn't have built-in suspension functionality
        $username = $params['username'];
        
        logModuleCall('whp', __FUNCTION__, $params, 'Unsuspension requested for user: ' . $username . ' - WHP does not support account suspension');
        
        // Return success since WHMCS requires it, but log that no action was taken
        return 'success';
        
    } catch (Exception $e) {
        logModuleCall('whp', __FUNCTION__, $params, $e->getMessage());
        return 'Error: ' . $e->getMessage();
    }
}

/**
 * Terminate account on the remote server.
 */
function whp_TerminateAccount(array $params) {
    try {
        $serverdata = whp_getServerData($params);
        $username = $params['username'];
        
        $apiData = array(
            'username' => $username,
        );
        
        $response = whp_api_call($serverdata, 'DELETE', 'users.php?action=user', $apiData);
        
        if ($response['status'] === 'success') {
            return 'success';
        } else {
            return 'Account termination failed: ' . $response['message'];
        }
        
    } catch (Exception $e) {
        logModuleCall('whp', __FUNCTION__, $params, $e->getMessage());
        return 'Error: ' . $e->getMessage();
    }
}

/**
 * Change the password for an account.
 */
function whp_ChangePassword(array $params) {
    try {
        $serverdata = whp_getServerData($params);
        $username = $params['username'];
        $password = $params['password'];
        
        $apiData = array(
            'username' => $username,
            'password' => $password,
        );
        
        $response = whp_api_call($serverdata, 'PUT', 'users.php?action=password', $apiData);
        
        if ($response['status'] === 'success') {
            return 'success';
        } else {
            return 'Password change failed: ' . $response['message'];
        }
        
    } catch (Exception $e) {
        logModuleCall('whp', __FUNCTION__, $params, $e->getMessage());
        return 'Error: ' . $e->getMessage();
    }
}

/**
 * Change the package for an account.
 */
function whp_ChangePackage(array $params) {
    try {
        $serverdata = whp_getServerData($params);
        $username = $params['username'];
        $configoptions = $params['configoptions'];
        
        // Get base plan resources from WHMCS product configuration
        $baseResources = whp_getBaseResources($params);
        
        // Configurable options are customer upgrades on top of base resources
        $upgradeResources = array(
            'cpu_cores' => floatval($configoptions['CPU Cores'] ?? 0),
            'memory_mb' => intval($configoptions['Memory (MB)'] ?? 0),
            'disk_mb' => intval($configoptions['Disk Space (MB)'] ?? 0),
            'email_accounts' => intval($configoptions['Email Accounts'] ?? 0),
            'email_storage_mb' => intval($configoptions['Email Storage (MB)'] ?? 0),
            'archived_mailboxes' => intval($configoptions['Max Archived Mailboxes'] ?? 0),
        );

        // Combine base resources + configurable option upgrades
        $finalResources = array(
            'cpu_cores' => $baseResources['cpu_cores'] + $upgradeResources['cpu_cores'],
            'memory_mb' => $baseResources['memory_mb'] + $upgradeResources['memory_mb'],
            'disk_mb' => $baseResources['disk_mb'] + $upgradeResources['disk_mb'],
            'email_accounts' => $baseResources['email_accounts'] + $upgradeResources['email_accounts'],
            'email_storage_mb' => $baseResources['email_storage_mb'] + $upgradeResources['email_storage_mb'],
            'archived_mailboxes' => $baseResources['archived_mailboxes'] + $upgradeResources['archived_mailboxes'],
            // sitesmith_enabled is a boolean flag, not additive — base value wins
            'sitesmith_enabled' => $baseResources['sitesmith_enabled'],
        );

        // Extract account type from config options (configoption6 = Account Type)
        $account_type = $params['configoption6'] ?? 'full';
        if (!in_array($account_type, ['full', 'domain_dns', 'mail_dns'])) {
            $account_type = 'full';
        }

        $apiData = array(
            'username' => $username,
            'resources' => $finalResources,
            'account_type' => $account_type,
        );

        // Debug logging - log the resource calculation
        logModuleCall('whp', 'ChangePackage_ResourceCalculation', array(
            'base_resources' => $baseResources,
            'upgrade_resources' => $upgradeResources,
            'final_resources' => $finalResources
        ), 'Resource calculation for package change');
        
        $response = whp_api_call($serverdata, 'PUT', 'users.php?action=resources', $apiData);
        
        if ($response['status'] === 'success') {
            return 'success';
        } else {
            return 'Package change failed: ' . $response['message'];
        }
        
    } catch (Exception $e) {
        logModuleCall('whp', __FUNCTION__, $params, $e->getMessage());
        return 'Error: ' . $e->getMessage();
    }
}

/**
 * Test connection to the server.
 */
function whp_TestConnection(array $params) {
    try {
        $serverdata = whp_getServerData($params);
        
        // Add detailed logging for debugging
        logModuleCall('whp', 'TestConnection_Start', array(
            'params_keys' => array_keys($params),
            'hostname' => isset($serverdata['hostname']) ? $serverdata['hostname'] : 'not set',
            'port' => isset($serverdata['port']) ? $serverdata['port'] : 'not set',
            'secure' => isset($serverdata['secure']) ? $serverdata['secure'] : 'not set',
            'username' => !empty($serverdata['username']) ? 'set' : 'empty',
            'password' => !empty($serverdata['password']) ? 'set' : 'empty',
            'all_serverdata_keys' => is_array($serverdata) ? array_keys($serverdata) : 'not an array'
        ), 'Starting connection test');
        
        // Validate required fields
        if (empty($serverdata['hostname'])) {
            $error = 'Missing hostname in server configuration';
            logModuleCall('whp', 'TestConnection_Error', $serverdata, $error);
            return array('success' => false, 'message' => $error);
        }
        
        $response = whp_api_call($serverdata, 'GET', 'system.php?action=health');
        
        if (is_array($response) && isset($response['status'])) {
            if ($response['status'] === 'success') {
                $health = $response['data'] ?? array();
                $status = $health['status'] ?? 'unknown';
                
                if ($status === 'healthy') {
                    return array(
                        'success' => true,
                        'message' => 'Connection successful - Server is healthy',
                    );
                } else {
                    return array(
                        'success' => true,
                        'message' => 'Connection successful - Server status: ' . $status,
                    );
                }
            } else {
                $message = $response['message'] ?? 'Unknown API error';
                return array(
                    'success' => false,
                    'message' => 'API Error: ' . $message,
                );
            }
        } else {
            return array(
                'success' => false,
                'message' => 'Invalid response format from server',
            );
        }
        
    } catch (Exception $e) {
        $errorMsg = $e->getMessage();
        logModuleCall('whp', 'TestConnection', $params, 'Exception: ' . $errorMsg);
        
        return array(
            'success' => false,
            'message' => 'Connection test failed: ' . $errorMsg,
        );
    }
}

/**
 * Client area single sign-on.
 */
function whp_ServiceSingleSignOn(array $params) {
    try {
        $serverdata = whp_getServerData($params);
        $username = $params['username'];
        
        // Enhanced debugging for SSO
        logModuleCall('whp', 'SSO_Debug', array(
            'username' => $username,
            'serverdata_keys' => array_keys($serverdata),
            'hostname' => $serverdata['hostname'] ?? 'not set',
            'api_key_length' => strlen($serverdata['username'] ?? ''),
            'api_secret_length' => strlen($serverdata['password'] ?? ''),
            'api_key_preview' => substr($serverdata['username'] ?? '', 0, 10) . '...',
            'api_secret_preview' => substr($serverdata['password'] ?? '', 0, 10) . '...'
        ), 'Starting SSO process');
        
        // Generate SSO token
        $apiData = array(
            'username' => $username,
            'redirect_url' => '/index.php', // Redirect to dashboard
            'expiry_minutes' => 10,
        );
        
        $response = whp_api_call($serverdata, 'POST', 'sso.php?action=generate_token', $apiData);
        
        if ($response['status'] === 'success') {
            logModuleCall('whp', 'SSO_Success', $apiData, $response['data']['login_url']);
            return array(
                'success' => true,
                'redirectTo' => $response['data']['login_url'],
            );
        } else {
            $errorMsg = $response['message'] ?? 'Unknown API error';
            
            // Check for common permission issues
            if (strpos($errorMsg, 'Insufficient permissions') !== false || strpos($errorMsg, 'Internal server error') !== false) {
                $errorMsg = 'API key lacks SSO permission. Please enable "SSO Access" permission for the API key used by WHMCS in WHP Server Settings.';
            }
            
            logModuleCall('whp', 'SSO_API_Error', $apiData, 'API Error: ' . $errorMsg);
            return array(
                'success' => false,
                'errorMsg' => 'SSO failed: ' . $errorMsg,
            );
        }
        
    } catch (Exception $e) {
        $errorMsg = $e->getMessage();
        
        // Provide helpful error messages for common issues
        if (strpos($errorMsg, 'HTTP Error: 500') !== false) {
            $errorMsg = 'Internal server error. This is likely due to missing SSO permission. Please enable "SSO Access" permission for the API key in WHP Server Settings.';
        } elseif (strpos($errorMsg, 'HTTP Error: 403') !== false) {
            $errorMsg = 'Access denied. Please enable "SSO Access" permission for the API key in WHP Server Settings.';
        }
        
        logModuleCall('whp', 'SSO_Exception', $params, 'Exception: ' . $e->getMessage());
        return array(
            'success' => false,
            'errorMsg' => 'SSO error: ' . $errorMsg,
        );
    }
}

/**
 * Admin area single sign-on.
 */
function whp_AdminSingleSignOn(array $params) {
    // For admin SSO, we'll use the same mechanism but potentially with different permissions
    return whp_ServiceSingleSignOn($params);
}

/**
 * Admin custom buttons array.
 */
function whp_AdminCustomButtonArray() {
    return array(
        "Update Resources" => "update_resources",
        "View Usage Stats" => "view_usage",
        "Update Disk Quota" => "update_quota",
    );
}

/**
 * Handle admin custom actions.
 */
function whp_update_resources(array $params) {
    try {
        $serverdata = whp_getServerData($params);
        $username = $params['username'];
        $configoptions = $params['configoptions'];
        
        // Get base plan resources from WHMCS product configuration
        $baseResources = whp_getBaseResources($params);
        
        // Configurable options are customer upgrades on top of base resources
        $upgradeResources = array(
            'cpu_cores' => floatval($configoptions['CPU Cores'] ?? 0),
            'memory_mb' => intval($configoptions['Memory (MB)'] ?? 0),
            'disk_mb' => intval($configoptions['Disk Space (MB)'] ?? 0),
            'email_accounts' => intval($configoptions['Email Accounts'] ?? 0),
            'email_storage_mb' => intval($configoptions['Email Storage (MB)'] ?? 0),
        );
        
        // Combine base resources + configurable option upgrades
        $finalResources = array(
            'cpu_cores' => $baseResources['cpu_cores'] + $upgradeResources['cpu_cores'],
            'memory_mb' => $baseResources['memory_mb'] + $upgradeResources['memory_mb'],
            'disk_mb' => $baseResources['disk_mb'] + $upgradeResources['disk_mb'],
            'email_accounts' => $baseResources['email_accounts'] + $upgradeResources['email_accounts'],
            'email_storage_mb' => $baseResources['email_storage_mb'] + $upgradeResources['email_storage_mb'],
        );
        
        // Prepare resource update data
        $apiData = array(
            'username' => $username,
            'resources' => $finalResources,
        );
        
        // Debug logging - log the resource calculation
        logModuleCall('whp', 'UpdateResources_ResourceCalculation', array(
            'base_resources' => $baseResources,
            'upgrade_resources' => $upgradeResources,
            'final_resources' => $finalResources
        ), 'Resource calculation for update resources');
        
        $response = whp_api_call($serverdata, 'PUT', 'users.php?action=resources', $apiData);
        
        if ($response['status'] === 'success') {
            return 'success';
        } else {
            return 'Resource update failed: ' . $response['message'];
        }
        
    } catch (Exception $e) {
        logModuleCall('whp', __FUNCTION__, $params, $e->getMessage());
        return 'Error: ' . $e->getMessage();
    }
}

/**
 * View usage statistics.
 */
function whp_view_usage(array $params) {
    try {
        $serverdata = whp_getServerData($params);
        $username = $params['username'];
        
        // Get user usage information
        $response = whp_api_call($serverdata, 'GET', 'users.php?action=info&username=' . urlencode($username));
        
        if ($response['status'] === 'success') {
            $userInfo = $response['data'];
            $usage = $userInfo['usage'] ?? [];
            
            $output = "Current Usage Statistics:\n\n";
            
            if (isset($usage['disk_used_mb'])) {
                $diskUsed = intval($usage['disk_used_mb']);
                $diskLimit = intval($userInfo['resources']['disk_mb'] ?? 0);
                $diskPercent = $diskLimit > 0 ? ($diskUsed / $diskLimit) * 100 : 0;
                
                $output .= "Disk Usage: " . $diskUsed . " MB / " . $diskLimit . " MB (" . number_format($diskPercent, 1) . "%)\n";
            }
            
            if (isset($usage['last_updated'])) {
                $output .= "Last Updated: " . $usage['last_updated'] . "\n";
            }
            
            // Add resource limits
            if (isset($userInfo['resources'])) {
                $resources = $userInfo['resources'];
                $output .= "\nResource Limits:\n";
                $output .= "- CPU Cores: " . ($resources['cpu_cores'] ?? 'N/A') . "\n";
                $output .= "- Memory: " . ($resources['memory_mb'] ?? 'N/A') . " MB\n";
                $output .= "- Email Accounts: " . ($resources['email_accounts'] ?? 'N/A') . "\n";
                $output .= "- Email Storage: " . ($resources['email_storage_mb'] ?? 'N/A') . " MB\n";
            }
            
            return $output;
        } else {
            return 'Failed to retrieve usage statistics: ' . $response['message'];
        }
        
    } catch (Exception $e) {
        logModuleCall('whp', __FUNCTION__, $params, $e->getMessage());
        return 'Error: ' . $e->getMessage();
    }
}

/**
 * Update disk quota for user.
 */
function whp_update_quota(array $params) {
    try {
        $serverdata = whp_getServerData($params);
        $username = $params['username'];
        $configoptions = $params['configoptions'];
        
        // Get base plan resources from WHMCS product configuration
        $baseResources = whp_getBaseResources($params);
        
        // Calculate final disk quota (base + configurable upgrades)
        $upgradeDiskMb = intval($configoptions['Disk Space (MB)'] ?? 0);
        $finalDiskMb = $baseResources['disk_mb'] + $upgradeDiskMb;
        
        $apiData = array(
            'username' => $username,
            'resources' => array(
                'disk_mb' => $finalDiskMb,
            ),
        );
        
        // Debug logging
        logModuleCall('whp', 'UpdateQuota_Calculation', array(
            'base_disk_mb' => $baseResources['disk_mb'],
            'upgrade_disk_mb' => $upgradeDiskMb,
            'final_disk_mb' => $finalDiskMb
        ), 'Disk quota calculation');
        
        $response = whp_api_call($serverdata, 'PUT', 'users.php?action=resources', $apiData);
        
        if ($response['status'] === 'success') {
            return 'Disk quota updated successfully to ' . $finalDiskMb . ' MB.';
        } else {
            return 'Disk quota update failed: ' . $response['message'];
        }
        
    } catch (Exception $e) {
        logModuleCall('whp', __FUNCTION__, $params, $e->getMessage());
        return 'Error: ' . $e->getMessage();
    }
}

/**
 * Client area actions.
 */
function whp_ClientArea(array $params) {
    try {
        $serverdata = whp_getServerData($params);
        
        // Enhanced debugging for ClientArea
        logModuleCall('whp', 'ClientArea_Debug', array(
            'params_keys' => array_keys($params),
            'serverdata_extracted' => array(
                'hostname' => $serverdata['hostname'] ?? 'not set',
                'username' => !empty($serverdata['username']) ? 'set' : 'empty',
                'password' => !empty($serverdata['password']) ? 'set' : 'empty'
            )
        ), 'ClientArea parameter debugging');
        
        $username = $params['username'];
        
        // Get user information only (no server statistics for clients)
        $userResponse = whp_api_call($serverdata, 'GET', 'users.php?action=info&username=' . urlencode($username));
        
        $userInfo = $userResponse['status'] === 'success' ? $userResponse['data'] : null;
        
        return array(
            'templatefile' => 'overview',
            'vars' => array(
                'user_info' => $userInfo,
                'username' => $username,
                'serviceid' => $params['serviceid'],
            ),
        );
        
    } catch (Exception $e) {
        logModuleCall('whp', __FUNCTION__, $params, $e->getMessage());
        return array(
            'templatefile' => 'error',
            'vars' => array(
                'error' => 'Unable to load account information: ' . $e->getMessage(),
            ),
        );
    }
}

/**
 * Admin area actions.
 */
function whp_AdminServicesTabFields(array $params) {
    try {
        $serverdata = whp_getServerData($params);
        
        // Enhanced debugging
        logModuleCall('whp', 'AdminServicesTabFields_Debug', array(
            'params_keys' => array_keys($params),
            'serverdata_extracted' => array(
                'hostname' => $serverdata['hostname'] ?? 'not set',
                'username' => !empty($serverdata['username']) ? 'set' : 'empty',
                'password' => !empty($serverdata['password']) ? 'set' : 'empty'
            )
        ), 'Parameter debugging');
        
        $username = $params['username'];
        
        // Get detailed user information
        $response = whp_api_call($serverdata, 'GET', 'users.php?action=info&username=' . urlencode($username));
        
        if ($response['status'] === 'success') {
            $userInfo = $response['data'];
            
            return array(
                'Username' => $userInfo['username'],
                'UID' => $userInfo['uid'] ?? 'N/A',
                'Home Directory' => $userInfo['home_directory'] ?? 'N/A',
                'Shell' => $userInfo['shell'] ?? 'N/A',
                'CPU Cores' => $userInfo['resources']['cpu_cores'] ?? 'N/A',
                'Memory (MB)' => $userInfo['resources']['memory_mb'] ?? 'N/A',
                'Disk Space (MB)' => $userInfo['resources']['disk_mb'] ?? 'N/A',
                'Email Accounts' => $userInfo['resources']['email_accounts'] ?? 'N/A',
                'Email Storage (MB)' => $userInfo['resources']['email_storage_mb'] ?? 'N/A',
                'Disk Used (MB)' => $userInfo['usage']['disk_used_mb'] ?? 'N/A',
                'Last Updated' => $userInfo['usage']['last_updated'] ?? 'N/A',
            );
        } else {
            return array(
                'Error' => 'Unable to retrieve user information: ' . $response['message'],
            );
        }
        
    } catch (Exception $e) {
        logModuleCall('whp', __FUNCTION__, $params, $e->getMessage());
        return array(
            'Error' => 'Error retrieving user information: ' . $e->getMessage(),
        );
    }
}

/**
 * Execute an API call to the WHP server.
 */
function whp_api_call($serverdata, $method, $endpoint, $data = null) {
    $hostname = $serverdata['hostname'];
    $port = $serverdata['secure'] ? ($serverdata['port'] ?: 443) : ($serverdata['port'] ?: 80);
    $protocol = $serverdata['secure'] ? 'https' : 'http';
    
    // Server authentication details
    $apiKey = $serverdata['username']; // Store API key in username field
    $apiSecret = $serverdata['password']; // Store API secret in password field
    
    // Enhanced logging for debugging
    logModuleCall('whp', 'api_call_start', array(
        'hostname' => $hostname,
        'port' => $port,
        'protocol' => $protocol,
        'endpoint' => $endpoint,
        'method' => $method,
        'api_key' => $apiKey,
        'api_secret' => substr($apiSecret, 0, 10) . '...',
        'full_url' => $url
    ), 'Starting API call');
    
    if (empty($apiKey) || empty($apiSecret)) {
        $error = 'API credentials not configured - username: ' . (!empty($apiKey) ? 'set' : 'empty') . ', password: ' . (!empty($apiSecret) ? 'set' : 'empty');
        logModuleCall('whp', 'api_call_error', $serverdata, $error);
        throw new Exception($error);
    }
    
    $url = $protocol . '://' . $hostname . ':' . $port . '/api/external/' . $endpoint;
    
    // Log the full URL being called
    logModuleCall('whp', 'api_call_url', array('url' => $url), 'Full API URL');
    
    $ch = curl_init();
    
    // Basic cURL options
    curl_setopt_array($ch, array(
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_SSL_VERIFYPEER => false, // Configure appropriately for production
        CURLOPT_SSL_VERIFYHOST => false,
        CURLOPT_USERAGENT => 'WHMCS-WHP-Module/1.0',
    ));
    
    // Set authentication headers
    // Note: Headers must match exact case that the server expects
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json',
        'X-Api-Key: ' . $apiKey,
        'X-Api-Secret: ' . $apiSecret,
    ));
    
    // Set method-specific options
    switch (strtoupper($method)) {
        case 'POST':
            curl_setopt($ch, CURLOPT_POST, true);
            if ($data) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
            }
            break;
            
        case 'PUT':
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
            if ($data) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
            }
            break;
            
        case 'DELETE':
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
            if ($data) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
            }
            break;
            
        case 'GET':
        default:
            // GET is default, no additional options needed
            break;
    }
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curlError = curl_error($ch);
    $curlInfo = curl_getinfo($ch);
    
    curl_close($ch);
    
    // Enhanced logging
    logModuleCall('whp', 'curl_response', array(
        'http_code' => $httpCode,
        'curl_error' => $curlError,
        'response_size' => strlen($response),
        'total_time' => $curlInfo['total_time'],
        'connect_time' => $curlInfo['connect_time']
    ), 'cURL execution completed');
    
    if ($curlError) {
        $error = 'cURL Error: ' . $curlError;
        logModuleCall('whp', 'curl_error', $curlInfo, $error);
        throw new Exception($error);
    }
    
    if ($httpCode >= 400) {
        $error = 'HTTP Error: ' . $httpCode . ' - ' . $response;
        logModuleCall('whp', 'http_error', array('code' => $httpCode, 'response' => $response), $error);
        throw new Exception($error);
    }
    
    // Log raw response for debugging
    logModuleCall('whp', 'raw_response', array('response' => $response), 'Raw API response');
    
    $decodedResponse = json_decode($response, true);
    
    if (json_last_error() !== JSON_ERROR_NONE) {
        $error = 'Invalid JSON response: ' . json_last_error_msg() . ' - Raw response: ' . $response;
        logModuleCall('whp', 'json_error', array('error' => json_last_error_msg(), 'response' => $response), $error);
        throw new Exception($error);
    }
    
    // Log the successful API call
    logModuleCall('whp', $method . ' ' . $endpoint, $data, $decodedResponse);
    
    return $decodedResponse;
}
?>