<?php
/**
 * External Client Allowance API for WHMCS Integration
 *
 * Generic endpoint for flipping boolean / enum allowance flags on
 * whp.client_allowances from the WHMCS provisioning module. Used for
 * "paid addon" configoptions (e.g. litespeed_tier, sitesmith) so the
 * WHMCS module does not need to re-send the full resources payload
 * just to flip a single flag.
 *
 * Security:
 *   - Auth: standard external API key (X-Api-Key / X-Api-Secret) via api_auth.php
 *   - Permission: 'user_management' (same scope as users.php; the WHMCS API key
 *     already has this enabled)
 *   - Column writes are gated by an explicit allowlist; arbitrary
 *     client_allowances columns cannot be written through this endpoint.
 *   - All values are bound via PDO prepared statements.
 *
 * Request: POST /api/external/set-client-allowance.php
 *   {
 *     "username":       "alphaone",
 *     "allowance_name": "litespeed_enabled",
 *     "enabled":        1
 *   }
 *
 * Response:
 *   { "status": "success", "message": "...", "data": { ... } }
 *
 * On error returns the api_auth.php standard error envelope with an
 * appropriate HTTP status code.
 */

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, X-API-Key, X-API-Secret, Authorization');

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

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

/**
 * Allowlist of client_allowances columns this endpoint is permitted to
 * write. Anything not listed here is rejected. Keep this list narrow —
 * resource caps (cpu/memory/disk/email) are managed via users.php and
 * should NOT be added here.
 *
 * value => column type:
 *   'bool' — 0/1 stored as TINYINT(1)
 */
const WHP_ALLOWANCE_COLUMN_ALLOWLIST = [
    'litespeed_enabled' => 'bool',
    'sitesmith_enabled' => 'bool',
    'bichon_enabled'    => 'bool',
];

try {
    // Standard external-API auth (same permission scope as users.php)
    $authData = api_authenticate('user_management');

    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        api_response(false, null, 'Method not allowed. Use POST.', 405);
    }

    $raw = file_get_contents('php://input');
    $input = json_decode($raw, true);
    if (!is_array($input)) {
        api_response(false, null, 'Invalid JSON input', 400);
    }

    $username       = isset($input['username']) ? trim((string)$input['username']) : '';
    $allowance_name = isset($input['allowance_name']) ? trim((string)$input['allowance_name']) : '';
    // Accept enabled as int (0/1), bool, or string ('0'/'1'). Reject anything else.
    if (!array_key_exists('enabled', $input)) {
        api_response(false, null, "Field 'enabled' is required", 400);
    }
    $enabled_raw = $input['enabled'];
    if (is_bool($enabled_raw)) {
        $enabled = $enabled_raw ? 1 : 0;
    } elseif (is_int($enabled_raw) || (is_string($enabled_raw) && in_array($enabled_raw, ['0', '1'], true))) {
        $enabled = ((int)$enabled_raw) ? 1 : 0;
    } else {
        api_response(false, null, "Field 'enabled' must be 0 or 1", 400);
    }

    if ($username === '') {
        api_response(false, null, "Field 'username' is required", 400);
    }
    if ($allowance_name === '') {
        api_response(false, null, "Field 'allowance_name' is required", 400);
    }

    // Username sanity: WHP usernames are lowercase alphanumeric (plus a few
    // separators). Reject anything weirder to avoid surprises in error logs.
    if (!preg_match('/^[a-z0-9][a-z0-9_-]{0,31}$/', $username)) {
        api_response(false, null, 'Invalid username format', 400);
    }

    if (!array_key_exists($allowance_name, WHP_ALLOWANCE_COLUMN_ALLOWLIST)) {
        api_response(false, null, "Allowance '$allowance_name' is not writable through this endpoint", 400);
    }

    $MySQLMgmt = new mysqlmgmt();
    $db = $MySQLMgmt->getMySQLConnection();
    if (!$db) {
        api_response(false, null, 'Database connection failed', 500);
    }

    // Confirm the user actually has a client_allowances row. We deliberately
    // do NOT auto-create one here — that's CreateAccount's job, and creating
    // an empty row out from under it would skip cpu/memory/disk defaults.
    $checkStmt = $db->prepare('SELECT 1 FROM whp.client_allowances WHERE username = ?');
    $checkStmt->execute([$username]);
    if (!$checkStmt->fetchColumn()) {
        api_response(false, null, "No client_allowances row for user '$username' — create the account first", 404);
    }

    // Column name is allowlist-bound; quote it defensively anyway. Value
    // is parameterized. (PDO does not parameterize identifiers.)
    $quotedCol = '`' . str_replace('`', '``', $allowance_name) . '`';
    $sql = "UPDATE whp.client_allowances SET $quotedCol = ? WHERE username = ?";
    $stmt = $db->prepare($sql);
    $stmt->execute([$enabled, $username]);

    error_log("set-client-allowance: $allowance_name=$enabled for $username (rows={$stmt->rowCount()})");

    api_response(true, [
        'username'       => $username,
        'allowance_name' => $allowance_name,
        'enabled'        => $enabled,
        'rows_affected'  => $stmt->rowCount(),
        'updated_at'     => date('c'),
    ], 'Allowance updated successfully');

} catch (Exception $e) {
    error_log('External set-client-allowance API error: ' . $e->getMessage());
    api_response(false, null, 'Internal server error', 500);
}
