<?php
/**
 * External User Management API for WHMCS Integration
 * Provides user management functionality via API keys
 */

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); // Configure appropriately for production
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, X-API-Key, X-API-Secret, Authorization');

// Handle preflight requests
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    exit(0);
}

require_once(__DIR__ . '/../../libs/api_auth.php');
require_once(__DIR__ . '/../../libs/usermgmt.php');

try {
    // Authenticate and check permissions
    $authData = api_authenticate('user_management');
    
    $userMgmt = new usermgmt();
    $method = $_SERVER['REQUEST_METHOD'];
    $action = $_GET['action'] ?? '';
    
    switch ($method) {
        case 'GET':
            handleGetRequest($userMgmt, $action, $authData);
            break;
            
        case 'POST':
            handlePostRequest($userMgmt, $action, $authData);
            break;
            
        case 'PUT':
            handlePutRequest($userMgmt, $action, $authData);
            break;
            
        case 'DELETE':
            handleDeleteRequest($userMgmt, $action, $authData);
            break;
            
        default:
            api_response(false, null, 'Method not allowed', 405);
    }
    
} catch (Exception $e) {
    error_log("External Users API Error: " . $e->getMessage());
    api_response(false, null, 'Internal server error', 500);
}

function handleGetRequest($userMgmt, $action, $authData) {
    switch ($action) {
        case 'list':
            // List all users
            $users = $userMgmt->list_users();
            api_response(true, $users, 'Users retrieved successfully');
            break;
            
        case 'info':
            // Get specific user info
            $username = $_GET['username'] ?? '';
            if (empty($username)) {
                api_response(false, null, 'Username parameter required', 400);
            }
            
            $userInfo = getUserInfo($userMgmt, $username);
            if ($userInfo) {
                api_response(true, $userInfo, 'User info retrieved successfully');
            } else {
                api_response(false, null, 'User not found', 404);
            }
            break;
            
        case 'exists':
            // Check if user exists
            $username = $_GET['username'] ?? '';
            if (empty($username)) {
                api_response(false, null, 'Username parameter required', 400);
            }
            
            $exists = $userMgmt->user_exists($username);
            api_response(true, ['exists' => $exists], 'User existence checked');
            break;
            
        default:
            api_response(false, null, 'Invalid action. Use: list, info, exists', 400);
    }
}

function handlePostRequest($userMgmt, $action, $authData) {
    $input = json_decode(file_get_contents('php://input'), true);
    
    if (!$input) {
        api_response(false, null, 'Invalid JSON input', 400);
    }
    
    switch ($action) {
        case 'create':
            createUser($userMgmt, $input, $authData);
            break;
            
        case 'validate':
            // Validate user credentials without logging in
            validateUser($userMgmt, $input);
            break;
            
        default:
            api_response(false, null, 'Invalid action. Use: create, validate', 400);
    }
}

function handlePutRequest($userMgmt, $action, $authData) {
    $input = json_decode(file_get_contents('php://input'), true);
    
    if (!$input) {
        api_response(false, null, 'Invalid JSON input', 400);
    }
    
    switch ($action) {
        case 'password':
            // Change user password
            changePassword($userMgmt, $input, $authData);
            break;
            
        case 'resources':
            // Update user resource limits
            updateResources($userMgmt, $input, $authData);
            break;
            
        default:
            api_response(false, null, 'Invalid action. Use: password, resources', 400);
    }
}

function handleDeleteRequest($userMgmt, $action, $authData) {
    $input = json_decode(file_get_contents('php://input'), true);
    $username = $input['username'] ?? $_GET['username'] ?? '';
    
    if (empty($username)) {
        api_response(false, null, 'Username parameter required', 400);
    }
    
    switch ($action) {
        case 'user':
            deleteUser($userMgmt, $username, $authData);
            break;
            
        default:
            api_response(false, null, 'Invalid action. Use: user', 400);
    }
}

function createUser($userMgmt, $input, $authData) {
    // Log the complete input from WHMCS for debugging
    error_log("WHMCS User Creation Request: " . json_encode($input));
    
    $required = ['username', 'password'];
    foreach ($required as $field) {
        if (empty($input[$field])) {
            api_response(false, null, "Field '$field' is required", 400);
        }
    }
    
    // Optional resource limits
    $resources = $input['resources'] ?? [];
    error_log("Resources from WHMCS for {$input['username']}: " . json_encode($resources));
    
    // Skip default resources if custom resources are provided
    $skip_defaults = !empty($resources);
    error_log("Skip defaults for {$input['username']}: " . ($skip_defaults ? 'true' : 'false'));
    
    $result = $userMgmt->create_new_user($input['username'], $input['password'], $skip_defaults);
    
    if ($result['status'] === '0') {
        $userData = [
            'username' => $input['username'],
            'uid' => $result['uid'],
            'created_at' => date('c')
        ];
        
        // Set resource limits - either custom or defaults
        $resourcesToSet = $resources;
        if (empty($resourcesToSet)) {
            // Use default resources if none provided
            $resourcesToSet = [
                'cpu_cores' => 0.5,
                'memory_mb' => 512,
                'disk_mb' => 1000,
                'email_accounts' => 0,
                'email_storage_mb' => 1000
            ];
            error_log("Using default resources for user: " . $input['username']);
        } else {
            error_log("Using WHMCS resources for user: " . $input['username'] . " - " . json_encode($resourcesToSet));
        }
        
        $resourceResult = setUserResources($input['username'], $resourcesToSet);
        if ($resourceResult) {
            $userData['resources'] = $resourcesToSet;
            error_log("Successfully set resources for user: " . $input['username']);
        } else {
            error_log("Failed to set resources for user: " . $input['username']);
            // If resource setting failed, return error
            api_response(false, null, 'User created but failed to set resource limits', 500);
        }
        
        // Handle account_type
        $account_type = $input['account_type'] ?? 'full';
        if (!in_array($account_type, ['full', 'domain_dns', 'mail_dns'])) {
            $account_type = 'full';
        }

        try {
            require_once(__DIR__ . '/../../libs/mysqlmgmt.php');
            $MySQLMgmt_acct = new mysqlmgmt();
            $db_acct = $MySQLMgmt_acct->getMySQLConnection();
            $db_acct->prepare("UPDATE whp.client_allowances SET account_type = ? WHERE username = ?")
                ->execute([$account_type, $input['username']]);
        } catch (Exception $e) {
            error_log("Failed to set account_type for {$input['username']}: " . $e->getMessage());
        }

        // Create domain if provided
        $domain = $input['domain'] ?? '';
        if (!empty($domain)) {
            try {
                $domainResult = createUserDomain($input['username'], $domain);
                if ($domainResult['success']) {
                    $userData['domain_created'] = $domain;
                    $userData['domain_id'] = $domainResult['domain_id'];
                    if (isset($domainResult['warnings']) && !empty($domainResult['warnings'])) {
                        $userData['domain_warnings'] = $domainResult['warnings'];
                    }
                } else {
                    $userData['domain_error'] = $domainResult['error'];
                }
            } catch (Exception $e) {
                error_log("Failed to create domain for user {$input['username']}: " . $e->getMessage());
                // Don't fail the user creation, just log the domain creation failure
                $userData['domain_error'] = 'Domain creation failed: ' . $e->getMessage();
            }
        }
        
        api_response(true, $userData, 'User created successfully');
    } else {
        api_response(false, null, $result['msg'], 400);
    }
}

function deleteUser($userMgmt, $username, $authData) {
    $result = $userMgmt->delete_user($username);
    
    if ($result['status'] === '0') {
        api_response(true, ['username' => $username, 'deleted_at' => date('c')], 'User deleted successfully');
    } else {
        api_response(false, null, $result['msg'], 400);
    }
}

function changePassword($userMgmt, $input, $authData) {
    $required = ['username', 'password'];
    foreach ($required as $field) {
        if (empty($input[$field])) {
            api_response(false, null, "Field '$field' is required", 400);
        }
    }
    
    $result = $userMgmt->change_password($input['username'], $input['password']);
    
    if ($result['status'] === '0') {
        api_response(true, [
            'username' => $input['username'],
            'updated_at' => date('c')
        ], 'Password changed successfully');
    } else {
        api_response(false, null, $result['msg'], 400);
    }
}

function validateUser($userMgmt, $input) {
    $required = ['username', 'password'];
    foreach ($required as $field) {
        if (empty($input[$field])) {
            api_response(false, null, "Field '$field' is required", 400);
        }
    }
    
    // Use PAM to validate credentials
    if (function_exists('pam_auth')) {
        $valid = pam_auth($input['username'], $input['password']);
        api_response(true, ['valid' => $valid], 'Credentials validated');
    } else {
        api_response(false, null, 'PAM authentication not available', 500);
    }
}

function getUserInfo($userMgmt, $username) {
    // Get basic user info
    $users = $userMgmt->list_users();
    $userInfo = null;
    
    foreach ($users as $user) {
        if ($user['username'] === $username) {
            $userInfo = $user;
            break;
        }
    }
    
    if (!$userInfo) {
        return null;
    }
    
    // Add resource information
    $resources = getUserResources($username);
    if ($resources) {
        $userInfo['resources'] = $resources;
    }
    
    // Add usage statistics
    $usage = getUserUsage($username);
    if ($usage) {
        $userInfo['usage'] = $usage;
    }
    
    return $userInfo;
}

function getUserResources($username) {
    try {
        require_once(__DIR__ . '/../../libs/mysqlmgmt.php');
        $MySQLMgmt = new mysqlmgmt();
        $db = $MySQLMgmt->getMySQLConnection();
        $db->exec("USE whp");
        
        $stmt = $db->prepare("
            SELECT max_cpu_allowance, max_memory_allowance, max_disk_space, 
                   max_email_accounts, max_email_storage_mb
            FROM client_allowances 
            WHERE username = ?
        ");
        
        $stmt->execute([$username]);
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if ($result) {
            // Map database column names back to API field names (only WHP-tracked resources)
            return [
                'cpu_cores' => $result['max_cpu_allowance'],
                'memory_mb' => $result['max_memory_allowance'],
                'disk_mb' => $result['max_disk_space'],
                'email_accounts' => $result['max_email_accounts'],
                'email_storage_mb' => $result['max_email_storage_mb']
            ];
        }
        
        return null;
        
    } catch (Exception $e) {
        error_log("Error getting user resources: " . $e->getMessage());
        return null;
    }
}

function setUserResources($username, $resources) {
    try {
        require_once(__DIR__ . '/../../libs/mysqlmgmt.php');
        $MySQLMgmt = new mysqlmgmt();
        $db = $MySQLMgmt->getMySQLConnection();
        $db->exec("USE whp");
        
        // Extract resource values with detailed logging
        $cpu_cores = $resources['cpu_cores'] ?? 0.5;
        $memory_mb = $resources['memory_mb'] ?? 512;
        $disk_mb = $resources['disk_mb'] ?? 1000;
        $email_accounts = $resources['email_accounts'] ?? 0;
        $email_storage_mb = $resources['email_storage_mb'] ?? 1000;
        
        error_log("Calling updateClientAllowances for {$username} with: CPU={$cpu_cores}, Memory={$memory_mb}, Disk={$disk_mb}, Email={$email_accounts}, EmailStorage={$email_storage_mb}");
        
        // Use the proper updateClientAllowances method for validation and quota sync
        // This method already handles filesystem quota syncing internally
        $result = $MySQLMgmt->updateClientAllowances(
            $username,
            $cpu_cores,
            $memory_mb,
            null, // max_domains not needed for this call
            $disk_mb,
            $email_accounts,
            $email_storage_mb
        );
        
        if ($result['status'] === '0') {
            error_log("Successfully set resources for {$username}: CPU={$resources['cpu_cores']}, Memory={$resources['memory_mb']}, Disk={$resources['disk_mb']}, Email={$resources['email_accounts']}, EmailStorage={$resources['email_storage_mb']}");
        } else {
            error_log("Failed to set resources for {$username}: " . $result['msg']);
        }
        
        return $result['status'] === '0';
        
    } catch (Exception $e) {
        error_log("Error setting user resources for {$username}: " . $e->getMessage());
        return false;
    }
}

function updateResources($userMgmt, $input, $authData) {
    $username = $input['username'] ?? '';
    $resources = $input['resources'] ?? [];
    
    if (empty($username)) {
        api_response(false, null, 'Username is required', 400);
    }
    
    if (empty($resources)) {
        api_response(false, null, 'Resources data is required', 400);
    }
    
    $result = setUserResources($username, $resources);

    if ($result) {
        // Handle account_type if provided
        if (isset($input['account_type'])) {
            $account_type = $input['account_type'];
            if (!in_array($account_type, ['full', 'domain_dns', 'mail_dns'])) {
                $account_type = 'full';
            }
            try {
                require_once(__DIR__ . '/../../libs/mysqlmgmt.php');
                $MySQLMgmt_acct = new mysqlmgmt();
                $db_acct = $MySQLMgmt_acct->getMySQLConnection();
                $db_acct->prepare("UPDATE whp.client_allowances SET account_type = ? WHERE username = ?")
                    ->execute([$account_type, $username]);
            } catch (Exception $e) {
                error_log("Failed to update account_type for {$username}: " . $e->getMessage());
            }
        }

        api_response(true, [
            'username' => $username,
            'resources' => $resources,
            'updated_at' => date('c')
        ], 'User resources updated successfully');
    } else {
        api_response(false, null, 'Failed to update user resources', 500);
    }
}

function getUserUsage($username) {
    try {
        // Get disk usage
        $homePath = "/docker/users/$username";
        $diskUsage = 0;
        
        if (is_dir($homePath)) {
            $output = shell_exec("du -s $homePath 2>/dev/null | cut -f1");
            $diskUsage = intval($output) * 1024; // Convert from KB to bytes
        }
        
        // Get additional usage stats (can be extended)
        return [
            'disk_used_bytes' => $diskUsage,
            'disk_used_mb' => round($diskUsage / (1024 * 1024), 2),
            'last_updated' => date('c')
        ];
        
    } catch (Exception $e) {
        error_log("Error getting user usage: " . $e->getMessage());
        return null;
    }
}

/**
 * Create a domain for a user (following the same process as domains.php)
 */
function createUserDomain($username, $domain_name) {
    try {
        require_once(__DIR__ . '/../../libs/mysqlmgmt.php');
        require_once(__DIR__ . '/../../libs/pdns-integration.php');
        require_once(__DIR__ . '/../../libs/emailmgmt.php');
        
        $MySQLMgmt = new mysqlmgmt();
        $db = $MySQLMgmt->getMySQLConnection();
        
        if (!$db) {
            return ['success' => false, 'error' => 'Database connection failed'];
        }
        
        $domain_name = strtolower(trim($domain_name));
        
        // Validate domain format
        if (!filter_var('http://' . $domain_name, FILTER_VALIDATE_URL)) {
            return ['success' => false, 'error' => 'Invalid domain format'];
        }
        
        // Check if domain already exists in WHP
        $stmt = $db->prepare("SELECT id FROM whp.domains WHERE domain_name = ?");
        $stmt->execute([$domain_name]);
        if ($stmt->fetch()) {
            return ['success' => false, 'error' => 'Domain already exists in the system'];
        }
        
        // Initialize PowerDNS integration
        $pdns = new PowerDNSIntegration($db);
        
        // Create PowerDNS zone first
        $zone_result = $pdns->createZoneForDomain($domain_name, $username);
        if (!$zone_result['success']) {
            return ['success' => false, 'error' => 'Failed to create DNS zone: ' . $zone_result['error']];
        }
        
        // Insert domain into WHP database
        $stmt = $db->prepare("
            INSERT INTO whp.domains (domain_name, username, active) 
            VALUES (?, ?, 1)
        ");
        $stmt->execute([$domain_name, $username]);
        $domain_id = $db->lastInsertId();
        
        $warnings = [];
        
        // Initialize Email Management for mail server synchronization
        try {
            $EmailMgmt = new emailmgmt();
            
            // Add domain to mail server
            $mail_result = $EmailMgmt->createMailServerDomain($domain_name, [
                'disabled' => false,
                'reference_id' => $username
            ]);
            
            if ($mail_result['status'] !== '0') {
                $warnings[] = 'Mail server sync failed: ' . $mail_result['msg'];
            } else {
                // Wait for mail server to process domain creation
                sleep(3);
                
                // Generate DKIM records on mail server with retry logic
                try {
                    $dkim_result = $EmailMgmt->createDkimRecordsWithRetry($domain_name, $username, 3, 2);
                    if ($dkim_result['status'] !== '0') {
                        $warnings[] = 'DKIM setup failed: ' . $dkim_result['msg'];
                    } else {
                        // Add DKIM DNS record to PowerDNS
                        $dns_result = $EmailMgmt->createDkimDnsRecord($domain_name, null, null, $username);
                        if ($dns_result['status'] !== '0') {
                            $warnings[] = 'DKIM DNS record creation failed: ' . $dns_result['msg'];
                        }
                    }
                } catch (Exception $e) {
                    $warnings[] = 'DKIM setup failed: ' . $e->getMessage();
                }
            }
        } catch (Exception $e) {
            $warnings[] = 'Email integration failed: ' . $e->getMessage();
        }
        
        $result = [
            'success' => true,
            'domain_id' => $domain_id,
            'domain_name' => $domain_name
        ];
        
        if (!empty($warnings)) {
            $result['warnings'] = $warnings;
        }
        
        return $result;
        
    } catch (Exception $e) {
        error_log("Error creating user domain: " . $e->getMessage());
        return ['success' => false, 'error' => $e->getMessage()];
    }
}
?>