<?php

/**
 * CuliUptime Web Agent v0.1.1
 *
 * HTTP/HTTPS Monitoring Agent for CuliUptime Platform
 * Based on US004 (Agent Management) and US002 (HTTP Monitoring)
 * Version aligned with CuliUptime platform v0.1.1
 */

// ============================================================================
// CONFIGURATION
// ============================================================================

/**
 * Get agent version (embedded for single-file deployment)
 * Version is automatically synced from pyproject.toml by scripts/sync-versions.py
 */
function getAgentVersion(): string {
    return '0.2.0'; // Auto-updated by version sync script
}

// AGENT CONFIGURATION - SET THESE VALUES DURING DEPLOYMENT
// These values are provided by CuliUptime platform during manual agent addition
define('AGENT_ID', getenv('AGENT_ID') ?: 'your-agent-uuid-here');
define('AGENT_SECRET_KEY', getenv('AGENT_SECRET_KEY') ?: 'your-shared-secret-here');
define('PLATFORM_API_KEY', getenv('PLATFORM_API_KEY') ?: 'platform-api-key-here');

$AGENT_CONFIG = [
    'version' => getAgentVersion(),
    'name' => 'CuliUptime Web Agent',
    'agent_id' => AGENT_ID,
    'shared_secret' => AGENT_SECRET_KEY,
    'platform_api_key' => PLATFORM_API_KEY,
    'supported_protocols' => ['http', 'https'],
    'capabilities' => [
        'max_concurrent_checks' => 100,
        'timeout_range' => ['min' => 1, 'max' => 300],
        'http_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
        'auth_types' => ['none', 'basic', 'digest'],
        'proxy_types' => ['http', 'socks4', 'socks5']
    ],
    'security' => [
        'hmac_enabled' => true,
        'timestamp_window' => 300, // 5 minutes in seconds
        'dangerous_patterns' => [
            '/javascript:/i',
            '/data:text\/html/i',
            '/data:(?!image\/)[^;]*;/i',
            '/vbscript:/i',
            '/on\w+\s*=/i',
            '/<script[\s\S]*?<\/script>/i',
            '/<iframe[\s\S]*?<\/iframe>/i',
            '/<svg[\s\S]*?<\/svg>/i',
            '/<\?(?:php)?/i',
            '/\${[^}]*}/i',
            '/`[^`]*`/i',
            '/\$\([^)]*\)/i',
            '/;\s*(rm|cat|wget|curl|nc|netcat|sh|bash|python|perl|ruby|php)/i',
            '/\|\s*(nc|netcat|sh|bash|python|perl|ruby|php)/i',
            '/&&\s*(rm|cat|wget|curl|nc|netcat|sh|bash|python|perl|ruby|php)/i',
            '/\'\s*(OR|AND)\s+/i',
            '/\'\s*OR\s+\'/i',
            '/\'\s*;\s*DROP\s+TABLE/i',
            '/UNION\s+SELECT/i',
            '/INSERT\s+INTO/i',
            '/DELETE\s+FROM/i',
            '/UPDATE\s+.*\s+SET/i',
            '/EXEC\s+/i',
            '/xp_cmdshell/i',
            '/--\s*$/i',
            '/#\s*$/i'
        ]
    ]
];

// ============================================================================
// CROSS-PLATFORM COMPATIBILITY
// ============================================================================

/**
 * getallheaders() polyfill for nginx/FastCGI environments
 *
 * The getallheaders() function is only available when PHP runs as an Apache module.
 * This polyfill provides compatibility for nginx, openresty, lighttpd, and other web servers.
 *
 * @return array Associative array of HTTP headers
 */
if (!function_exists('getallheaders')) {
    function getallheaders() {
        $headers = [];

        foreach ($_SERVER as $name => $value) {
            if (substr($name, 0, 5) == 'HTTP_') {
                // Convert HTTP_HEADER_NAME to Header-Name format
                $header = str_replace('_', '-', substr($name, 5));
                $header = ucwords(strtolower($header), '-');
                $headers[$header] = $value;
            } elseif (in_array($name, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'])) {
                // Special headers that aren't prefixed with HTTP_ in $_SERVER
                $header = str_replace('_', '-', $name);
                $header = ucwords(strtolower($header), '-');
                $headers[$header] = $value;
            }
        }

        return $headers;
    }
}

// ============================================================================
// SECURITY VALIDATION
// ============================================================================

// Legacy authentication function removed - using HMAC-only authentication

function sendErrorResponse($code, $message)
{
    header("HTTP/1.1 $code " . getHttpStatusText($code));
    header('Content-Type: application/json');
    echo json_encode(['error' => $message, 'status' => 'failed']);
    exit;
}

// ============================================================================
// HMAC AUTHENTICATION (US004 Requirements)
// ============================================================================

/**
 * Validate HMAC authentication for platform requests
 *
 * Based on US004-agent-management.md Scenario 3:
 * - Verify HMAC-SHA256 signature using agent's shared secret
 * - Validate timestamp to prevent replay attacks (5-minute window)
 * - Check platform API key and agent ID
 *
 * @param string $requestBody The raw request body
 * @param array $headers Request headers
 * @return array Authentication result
 */
function validateHMACAuthentication($requestBody, $headers)
{
    global $AGENT_CONFIG;

    try {
        // Check if HMAC is enabled
        if (!$AGENT_CONFIG['security']['hmac_enabled']) {
            return [
                'authenticated' => false,
                'error' => 'HMAC authentication is not enabled'
            ];
        }

        // Check required HMAC headers
        $requiredHeaders = [
            // 'X-CuliOps-API-Key',  // REMOVED - no longer transmitted for security
            'X-CuliOps-Agent-ID',
            'X-CuliOps-Signature',
            'X-CuliOps-Timestamp'
        ];

        foreach ($requiredHeaders as $header) {
            if (!isset($headers[$header]) || empty($headers[$header])) {
                return [
                    'authenticated' => false,
                    'error' => "Missing required header: $header"
                ];
            }
        }

        // Platform API key validation removed - key is included in HMAC signature only

        // Validate agent ID
        if ($headers['X-CuliOps-Agent-ID'] !== $AGENT_CONFIG['agent_id']) {
            return [
                'authenticated' => false,
                'error' => 'Invalid agent ID'
            ];
        }

        // Validate timestamp (replay attack prevention)
        $timestamp = intval($headers['X-CuliOps-Timestamp']);
        $currentTime = time();
        $timestampWindow = $AGENT_CONFIG['security']['timestamp_window'];

        if (abs($currentTime - $timestamp) > $timestampWindow) {
            return [
                'authenticated' => false,
                'error' => 'Request timestamp outside allowed window'
            ];
        }

        // Generate canonical request for signature verification
        // Use full URL for better security (prevents cross-domain replay attacks)
        $method = $_SERVER['REQUEST_METHOD'] ?? 'POST';

        // Reconstruct URL to match backend's stored endpoint_url exactly
        // Backend signs with stored endpoint_url, so agent must reconstruct same URL
        $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
        $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
        $uri = $_SERVER['REQUEST_URI'] ?? '/culiuptime-agent.php';

        // Handle Docker network hostname mapping: localhost -> agent.local
        if ($host === 'localhost' || $host === '127.0.0.1') {
            $host = 'agent.local';  // Match the endpoint_url stored in database
        }

        $fullUrl = "{$scheme}://{$host}{$uri}";
        $canonicalRequest = generateCanonicalRequest($method, $fullUrl, $timestamp, $requestBody);

        // Calculate expected signature
        $expectedSignature = hash_hmac('sha256', $canonicalRequest, $AGENT_CONFIG['shared_secret']);
        $providedSignature = $headers['X-CuliOps-Signature'];


        // Verify signature using timing-safe comparison
        if (!hash_equals($expectedSignature, $providedSignature)) {
            return [
                'authenticated' => false,
                'error' => 'Invalid HMAC signature'
            ];
        }

        return [
            'authenticated' => true,
            'agent_id' => $headers['X-CuliOps-Agent-ID'],
            'timestamp' => $timestamp
        ];
    } catch (Exception $e) {
        return [
            'authenticated' => false,
            'error' => 'HMAC validation error: ' . $e->getMessage()
        ];
    }
}

/**
 * Generate canonical request string for HMAC signature
 *
 * Format (Security best practice - full URL):
 * POST\nhttp://agent.local/culiuptime-agent.php\n{timestamp}\n{request_body}
 *
 * @param string $method HTTP method
 * @param string $url Full URL (for security - prevents cross-domain replay attacks)
 * @param int $timestamp Unix timestamp
 * @param string $body Request body
 * @return string Canonical request string
 */
function generateCanonicalRequest($method, $url, $timestamp, $body)
{
    global $AGENT_CONFIG;
    // Platform API key included in HMAC but not transmitted for security
    return "{$method}\n{$url}\n{$timestamp}\n{$body}\n{$AGENT_CONFIG['platform_api_key']}";
}

/**
 * HMAC authentication validation for all requests
 *
 * @return bool True if request is valid
 */
function validateSecurityWithHMAC()
{
    global $AGENT_CONFIG;

    // Get request data
    $requestBody = file_get_contents('php://input') ?: '';
    $headers = getallheaders() ?: [];

    // All requests must use HMAC authentication
    $hmacResult = validateHMACAuthentication($requestBody, $headers);

    if (!$hmacResult['authenticated']) {
        sendErrorResponse(401, 'HMAC authentication failed: ' . $hmacResult['error']);
    }

    return true; // HMAC authentication successful
}

function getHttpStatusText($code)
{
    $statusTexts = [
        400 => 'Bad Request',
        403 => 'Forbidden',
        500 => 'Internal Server Error'
    ];
    return $statusTexts[$code] ?? 'Unknown';
}

// Security validation is now handled in handleRequest() via validateSecurityWithHMAC()
// This allows both legacy (X-Agent-Secret) and HMAC (X-CuliOps-*) authentication

// ============================================================================
// INPUT SANITIZATION & VALIDATION
// ============================================================================

function sanitize($data)
{
    if (is_array($data)) {
        return array_map('sanitize', $data);
    }
    if ($data === null) {
        return null;
    }

    global $AGENT_CONFIG;

    // Convert to string and trim
    $data = trim((string)$data);

    // Remove null bytes and control characters
    $data = str_replace(["\0", "\r", "\n"], '', $data);

    // Apply security patterns from config
    foreach ($AGENT_CONFIG['security']['dangerous_patterns'] as $pattern) {
        $data = preg_replace($pattern, '', $data);
    }

    // Strip tags and encode HTML entities
    $data = strip_tags($data);
    $data = htmlspecialchars($data, ENT_QUOTES | ENT_HTML5 | ENT_SUBSTITUTE, 'UTF-8');

    return $data;
}

function validateURL($url)
{
    if (!filter_var($url, FILTER_VALIDATE_URL)) {
        sendErrorResponse(400, 'Invalid URL format');
    }

    // Additional URL security checks
    $parsed = parse_url($url);
    if (!$parsed || !in_array(strtolower($parsed['scheme'] ?? ''), ['http', 'https'])) {
        sendErrorResponse(400, 'Only HTTP and HTTPS protocols are allowed');
    }

    return true;
}

function validateProxyURL($proxyUrl)
{
    if (empty($proxyUrl)) {
        return true;
    }

    // Basic proxy URL validation to prevent SSRF
    if (
        !filter_var($proxyUrl, FILTER_VALIDATE_URL) &&
        !preg_match('/^[\w\.-]+:\d+$/', $proxyUrl)
    ) {
        sendErrorResponse(400, 'Invalid proxy URL format');
    }

    // Block dangerous protocols and local addresses
    if (
        preg_match('/^(file|ftp|gopher|dict|ldap):/i', $proxyUrl) ||
        preg_match('/^https?:\/\/(localhost|127\.|192\.168\.|10\.|172\.(1[6-9]|2[0-9]|3[01])\.|169\.254\.)/i', $proxyUrl)
    ) {
        sendErrorResponse(400, 'Proxy URL not allowed for security reasons');
    }

    return true;
}

function validateTimeout($timeout)
{
    global $AGENT_CONFIG;
    $min = $AGENT_CONFIG['capabilities']['timeout_range']['min'];
    $max = $AGENT_CONFIG['capabilities']['timeout_range']['max'];

    if (!is_numeric($timeout) || $timeout < $min || $timeout > $max) {
        sendErrorResponse(400, "Timeout must be between $min and $max seconds");
    }

    return (int)$timeout;
}

function validateHTTPMethod($method)
{
    global $AGENT_CONFIG;
    $allowed_methods = $AGENT_CONFIG['capabilities']['http_methods'];

    $method = strtoupper(trim($method));
    if (!in_array($method, $allowed_methods)) {
        sendErrorResponse(400, 'HTTP method not allowed: ' . $method);
    }

    return $method;
}

/**
 * Validate response body contains expected text if configured
 *
 * @param array $config Monitoring configuration from platform
 * @param array $result HTTP request result containing response body
 * @param array $response Current response array to modify
 * @return array Modified response array
 */
function validateExpectedResponseContains($config, $result, $response)
{
    // Skip validation if expected text is not configured or empty
    if (!isset($config['expected_response_contains']) ||
        empty($config['expected_response_contains'])) {
        return $response;
    }

    // Skip validation if response body is empty
    if (!isset($result['response']) || empty($result['response'])) {
        return $response;
    }

    $expectedText = $config['expected_response_contains'];
    $responseBody = $result['response'];

    // Perform case-sensitive substring search
    $containsExpectedText = strpos($responseBody, $expectedText) !== false;

    if (!$containsExpectedText) {
        // Response doesn't contain expected text - mark as failed
        $response['success'] = false;
        $response['error_message'] = "Response body does not contain expected text: '{$expectedText}'";
    }

    return $response;
}

// ============================================================================
// HTTP MONITORING
// ============================================================================

function monitorURL($params)
{
    // Extract and validate parameters
    $config = extractMonitoringParameters($params);

    // Perform HTTP request
    $result = performHTTPRequest($config);

    // Format and return response
    return formatMonitoringResponse($result, $config);
}

function extractMonitoringParameters($params)
{
    // Sanitize and extract basic parameters
    $url = sanitize($params['url'] ?? 'https://www.google.com/');
    $timeout = validateTimeout(sanitize($params['timeout'] ?? 10));
    $method = validateHTTPMethod(sanitize($params['method'] ?? 'GET'));

    // Validate URLs
    validateURL($url);
    $proxyUrl = sanitize($params['proxy_url'] ?? null);
    validateProxyURL($proxyUrl);

    // Extract boolean parameters
    $sslVerify = isset($params['ssl_verify']) ? filter_var($params['ssl_verify'], FILTER_VALIDATE_BOOLEAN) : true;
    $followRedirection = isset($params['follow_redirection']) ? filter_var($params['follow_redirection'], FILTER_VALIDATE_BOOLEAN) : false;
    $showResponseBody = isset($params['show_response_body']) ? filter_var($params['show_response_body'], FILTER_VALIDATE_BOOLEAN) : true;

    // Extract authentication parameters - handle backend's auth_credentials format
    $authType = sanitize($params['auth_type'] ?? 'none');
    $authCredentials = $params['auth_credentials'] ?? [];

    $authConfig = ['type' => $authType];

    if ($authType !== 'none' && !empty($authCredentials)) {
        if ($authType === 'bearer') {
            $authConfig['token'] = sanitize($authCredentials['token'] ?? null);
        } else {
            // basic, digest
            $authConfig['username'] = sanitize($authCredentials['username'] ?? null);
            $authConfig['password'] = sanitize($authCredentials['password'] ?? null);
        }
    } else {
        // Fallback to legacy format for backward compatibility
        $authConfig['username'] = sanitize($params['auth_username'] ?? null);
        $authConfig['password'] = sanitize($params['auth_password'] ?? null);
    }

    // Extract request data
    $requestData = [
        'body' => $params['request_body'] ?? null,
        'format' => sanitize($params['data_format'] ?? 'form'),
        'headers' => $params['headers'] ?? []
    ];

    // Extract proxy configuration
    $proxyConfig = [
        'url' => $proxyUrl,
        'type' => sanitize($params['proxy_type'] ?? 'http'),
        'username' => sanitize($params['proxy_username'] ?? null),
        'password' => sanitize($params['proxy_password'] ?? null)
    ];

    return [
        'url' => $url,
        'method' => $method,
        'timeout' => $timeout,
        'ssl_verify' => $sslVerify,
        'follow_redirection' => $followRedirection,
        'show_response_body' => $showResponseBody,
        'user_agent' => sanitize($params['user_agent'] ?? 'CuliUptime/1.0 (+https://uptime.culiops.net)'),
        'auth' => $authConfig,
        'request' => $requestData,
        'proxy' => $proxyConfig,
        'client_ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown'
    ];
}

function performHTTPRequest($config)
{
    // Initialize cURL handle
    static $ch = null;
    if ($ch === null) {
        $ch = curl_init();
    }

    // Set basic cURL options
    curl_setopt_array($ch, [
        CURLOPT_URL => $config['url'],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => $config['timeout'],
        CURLOPT_SSL_VERIFYPEER => $config['ssl_verify'],
        CURLOPT_FOLLOWLOCATION => $config['follow_redirection'],
        CURLOPT_USERAGENT => $config['user_agent']
    ]);

    // Configure proxy if provided
    configureProxy($ch, $config['proxy']);

    // Configure HTTP method and request data
    configureHTTPMethod($ch, $config['method'], $config['request']);

    // Configure authentication
    configureAuthentication($ch, $config['auth']);

    // Set custom headers
    configureHeaders($ch, $config['request']['headers']);

    // Execute request and capture timing
    $start_time = microtime(true);
    $response = curl_exec($ch);
    $end_time = microtime(true);

    $result = [
        'response' => $response,
        'curl_info' => curl_getinfo($ch),
        'curl_error' => curl_error($ch),
        'curl_errno' => curl_errno($ch),
        'execution_time' => $end_time - $start_time
    ];

    // Keep handle open for reuse
    curl_reset($ch);

    return $result;
}

function configureProxy($ch, $proxyConfig)
{
    if (empty($proxyConfig['url'])) {
        return;
    }

    curl_setopt($ch, CURLOPT_PROXY, $proxyConfig['url']);

    // Set proxy type
    $proxyTypes = [
        'socks4' => CURLPROXY_SOCKS4,
        'socks5' => CURLPROXY_SOCKS5,
        'http' => CURLPROXY_HTTP
    ];

    $type = strtolower($proxyConfig['type']);
    curl_setopt($ch, CURLOPT_PROXYTYPE, $proxyTypes[$type] ?? CURLPROXY_HTTP);

    // Set proxy authentication
    if (!empty($proxyConfig['username']) && !empty($proxyConfig['password'])) {
        curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxyConfig['username'] . ':' . $proxyConfig['password']);
    }
}

function configureHTTPMethod($ch, $method, $requestConfig)
{
    switch ($method) {
        case 'POST':
            curl_setopt($ch, CURLOPT_POST, true);
            setRequestBody($ch, $requestConfig);
            break;
        case 'PUT':
        case 'PATCH':
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
            setRequestBody($ch, $requestConfig);
            break;
        case 'DELETE':
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
            break;
        case 'HEAD':
            curl_setopt($ch, CURLOPT_NOBODY, true);
            break;
        case 'OPTIONS':
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'OPTIONS');
            break;
    }
}

function setRequestBody($ch, $requestConfig)
{
    if (empty($requestConfig['body'])) {
        return;
    }

    $body = $requestConfig['body'];
    if ($requestConfig['format'] === 'json') {
        $body = is_array($body) ? json_encode($body) : $body;
        $requestConfig['headers']['Content-Type'] = 'application/json';
    }

    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
}

function configureAuthentication($ch, $authConfig)
{
    if (empty($authConfig['username']) || empty($authConfig['password'])) {
        return;
    }

    $authTypes = [
        'basic' => CURLAUTH_BASIC,
        'digest' => CURLAUTH_DIGEST
    ];

    $type = strtolower($authConfig['type']);
    if (isset($authTypes[$type])) {
        curl_setopt($ch, CURLOPT_HTTPAUTH, $authTypes[$type]);
        curl_setopt($ch, CURLOPT_USERPWD, $authConfig['username'] . ':' . $authConfig['password']);
    }
}

function configureHeaders($ch, $headers)
{
    if (empty($headers)) {
        return;
    }

    $formattedHeaders = [];
    foreach ($headers as $name => $value) {
        $formattedHeaders[] = "$name: $value";
    }

    curl_setopt($ch, CURLOPT_HTTPHEADER, $formattedHeaders);
}

// ============================================================================
// RESPONSE FORMATTING
// ============================================================================

function formatMonitoringResponse($result, $config)
{
    global $AGENT_CONFIG;

    $responseData = [
        'curl_params' => [
            'url' => $config['url'],
            'method' => $config['method'],
            'timeout' => $config['timeout'],
            'ssl_verify' => $config['ssl_verify'],
            'follow_redirection' => $config['follow_redirection'],
            'show_response_body' => $config['show_response_body'],
            'auth_type' => $config['auth']['type'],
            'client_ip' => $config['client_ip']
        ]
    ];

    if ($result['curl_errno'] === 0) {
        // Successful request
        $info = $result['curl_info'];

        $responseData = array_merge($responseData, [
            'status' => 'success',
            'http_code' => $info['http_code'],
            'namelookup_time' => $info['namelookup_time_us'] ?? 0,
            'connect_time' => $info['connect_time_us'] ?? 0,
            'appconnect_time' => $info['appconnect_time_us'] ?? 0,
            'pretransfer_time' => $info['pretransfer_time_us'] ?? 0,
            'starttransfer_time' => $info['starttransfer_time_us'] ?? 0,
            'total_time' => $info['total_time_us'] ?? 0,
            'redirect_time' => $info['redirect_time_us'] ?? 0,
            'redirect_count' => $info['redirect_count'] ?? 0,
            'url' => $info['url'],
            'agent_info' => [
                'version' => $AGENT_CONFIG['version'],
                'name' => $AGENT_CONFIG['name'],
                'timestamp' => date('c')
            ]
        ]);

        // Include response body if requested and method allows it
        if ($config['show_response_body'] && $config['method'] !== 'HEAD') {
            $responseData['http_body'] = $result['response'];
        }
    } else {
        // Request failed
        $responseData = array_merge($responseData, [
            'status' => 'failed',
            'error' => $result['curl_error'],
            'error_code' => $result['curl_errno']
        ]);
    }

    // Output JSON response
    header('Content-Type: application/json');
    echo json_encode($responseData, JSON_UNESCAPED_SLASHES);
}

// ============================================================================
// HEALTH CHECK
// ============================================================================

function handleHealthCheck()
{
    global $AGENT_CONFIG;

    $systemCheck = performSystemCheck();

    $healthData = [
        'status' => $systemCheck['healthy'] ? 'healthy' : 'degraded',
        'agent' => [
            'name' => $AGENT_CONFIG['name'],
            'version' => $AGENT_CONFIG['version'],
            'supported_protocols' => $AGENT_CONFIG['supported_protocols'],
            'capabilities' => $AGENT_CONFIG['capabilities']
        ],
        'system' => $systemCheck,
        'location' => [
            'server_ip' => $_SERVER['HTTP_HOST'] ?? 'unknown',
            'client_ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown'
        ]
    ];

    header('Content-Type: application/json');
    echo json_encode($healthData, JSON_UNESCAPED_SLASHES);
    exit;
}

function performSystemCheck()
{
    $checks = [
        'php_version' => PHP_VERSION,
        'curl_available' => extension_loaded('curl'),
        'memory_usage' => memory_get_usage(true),
        'memory_limit' => ini_get('memory_limit'),
        'max_execution_time' => ini_get('max_execution_time'),
        'timestamp' => date('c')
    ];

    // Determine overall health
    $checks['healthy'] = $checks['curl_available'] &&
        version_compare(PHP_VERSION, '7.4.0', '>=');

    // Add warnings if any
    $warnings = [];
    if (!$checks['curl_available']) {
        $warnings[] = 'cURL extension not available';
    }
    if (version_compare(PHP_VERSION, '7.4.0', '<')) {
        $warnings[] = 'PHP version below recommended 7.4.0';
    }

    if (!empty($warnings)) {
        $checks['warnings'] = $warnings;
    }

    return $checks;
}

// ============================================================================
// MAIN ENTRY POINT
// ============================================================================

function addSecurityHeaders()
{
    header('X-Content-Type-Options: nosniff');
    header('X-Frame-Options: DENY');
    header('X-XSS-Protection: 1; mode=block');
    header('Referrer-Policy: no-referrer');
    header('Content-Security-Policy: default-src \'self\'; script-src \'self\'; object-src \'none\';');
}

function handleRequest()
{
    try {
        // Check for debug endpoint first (bypass authentication)
        if (isset($_GET['action']) && $_GET['action'] === 'debug-url') {
            $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
            $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
            $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
            $uri = $_SERVER['REQUEST_URI'] ?? '/culiuptime-agent.php';

            // Apply hostname mapping
            $original_host = $host;
            if ($host === 'localhost' || $host === '127.0.0.1') {
                $host = 'agent.local';
            }

            $fullUrl = "{$scheme}://{$host}{$uri}";

            header('Content-Type: application/json');
            echo json_encode([
                'original_host' => $original_host,
                'mapped_host' => $host,
                'reconstructed_url' => $fullUrl,
                'method' => $method,
                'scheme' => $scheme,
                'uri' => $uri,
                'server_vars' => [
                    'HTTP_HOST' => $_SERVER['HTTP_HOST'] ?? 'not set',
                    'SERVER_NAME' => $_SERVER['SERVER_NAME'] ?? 'not set',
                    'REQUEST_URI' => $_SERVER['REQUEST_URI'] ?? 'not set'
                ]
            ]);
            exit;
        }

        // Validate security first (includes HMAC authentication for platform requests)
        validateSecurityWithHMAC();

        // Check request method
        $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';

        if ($method === 'POST') {
            // Handle platform POST requests with JSON payload
            $requestBody = file_get_contents('php://input') ?: '';
            $headers = getallheaders() ?: [];

            // Check if this is an HMAC authenticated platform request
            if (isset($headers['X-CuliOps-Agent-ID']) && isset($headers['X-CuliOps-Signature'])) {
                handlePlatformRequest($requestBody, $headers);
                return;
            }
        }

        // Handle legacy GET requests for health checks
        $params = $_GET;
        $action = sanitize($params['action'] ?? 'monitor');

        switch ($action) {
            case 'health':
                handleHealthCheck();
                break;


            case 'monitor':
            default:
                monitorURL($params);
                break;
        }
    } catch (Exception $e) {
        error_log('CuliUptime Agent Error: ' . $e->getMessage());
        sendErrorResponse(500, 'Internal agent error');
    }
}

/**
 * Handle authenticated platform requests
 *
 * Based on US004 requirements for platform communication
 *
 * @param string $requestBody JSON request body
 * @param array $headers Request headers
 */
function handlePlatformRequest($requestBody, $headers)
{
    global $AGENT_CONFIG;

    try {
        // Parse JSON payload
        $payload = json_decode($requestBody, true);
        if (!$payload) {
            sendErrorResponse(400, 'Invalid JSON payload');
        }

        $taskType = $payload['type'] ?? 'unknown';

        switch ($taskType) {
            case 'health_check':
                handlePlatformHealthCheck($payload);
                break;

            case 'http_check':
                handlePlatformHttpCheck($payload);
                break;

            default:
                sendErrorResponse(400, "Unknown task type: $taskType");
        }
    } catch (Exception $e) {
        sendErrorResponse(500, 'Platform request error: ' . $e->getMessage());
    }
}

/**
 * Handle platform health check requests
 *
 * @param array $payload Request payload
 */
function handlePlatformHealthCheck($payload)
{
    global $AGENT_CONFIG;

    $response = [
        'task_id' => $payload['task_id'] ?? null,
        'status' => 'ok',
        'agent_id' => $AGENT_CONFIG['agent_id'],
        'agent_version' => $AGENT_CONFIG['version'],
        'capabilities' => $AGENT_CONFIG['capabilities']['http_methods'] ?? [],
        'timestamp' => date('c'),
        'php_version' => phpversion(),
        'memory_usage' => memory_get_usage()
    ];

    header('Content-Type: application/json');
    echo json_encode($response);
}

/**
 * Handle platform HTTP check requests
 *
 * @param array $payload Request payload
 */
function handlePlatformHttpCheck($payload)
{
    // Convert platform payload to agent format
    $monitorParams = [
        'url' => $payload['target'] ?? '',
        'timeout' => $payload['timeout'] ?? 30,
        'method' => $payload['method'] ?? 'GET',
        'task_id' => $payload['task_id'] ?? null,
        'show_response_body' => true,  // Keep body for keyword checking support

        // Extract authentication parameters
        'auth_type' => $payload['auth_type'] ?? 'none',
        'auth_credentials' => $payload['auth_credentials'] ?? []
    ];

    // Perform the monitoring check using our own logic
    $config = extractMonitoringParameters($monitorParams);
    $result = performHTTPRequest($config);

    // Build response based on HTTP result
    if ($result['curl_errno'] === 0) {
        // Successful request
        $info = $result['curl_info'];
        $httpCode = $info['http_code'] ?? 0;

        // ✅ FIX: Validate HTTP status against expected codes
        $expectedStatuses = $payload['config']['up_http_statuses'] ?? [200];
        $isStatusSuccess = in_array($httpCode, $expectedStatuses);

        $response = [
            'task_id' => $payload['task_id'] ?? null,
            'success' => $isStatusSuccess, // ✅ FIXED: Based on status validation
            'response_time' => intval(($info['total_time_us'] ?? 0) / 1000), // Convert µs to ms
            'status_code' => $httpCode,
            'timestamp' => date('c'),
            'timing' => [
                'namelookup_time' => intval(($info['namelookup_time_us'] ?? 0) / 1000), // Convert µs to ms
                'connect_time' => intval(($info['connect_time_us'] ?? 0) / 1000), // Convert µs to ms
                'appconnect_time' => intval(($info['appconnect_time_us'] ?? 0) / 1000), // Convert µs to ms
                'pretransfer_time' => intval(($info['pretransfer_time_us'] ?? 0) / 1000), // Convert µs to ms
                'starttransfer_time' => intval(($info['starttransfer_time_us'] ?? 0) / 1000), // Convert µs to ms
                'total_time' => intval(($info['total_time_us'] ?? 0) / 1000) // Convert µs to ms
            ]
        ];

        // Handle response body with size limiting
        if (isset($result['response']) && !empty($result['response'])) {
            $bodyContent = $result['response'];
            $bodySize = strlen($bodyContent);

            // Provide body content with size limit for JSON stability
            $response['body_size'] = $bodySize;

            // Include first 1KB of body for keyword checking (configurable)
            $maxBodySize = 1024; // 1KB limit for JSON response to prevent parsing issues
            if ($bodySize <= $maxBodySize) {
                $response['body_content'] = $bodyContent;
            } else {
                $response['body_content'] = substr($bodyContent, 0, $maxBodySize);
                $response['body_truncated'] = true;
            }
        }

        // Add validation failure message if status doesn't match expected codes
        if (!$isStatusSuccess) {
            $response['error_message'] = "HTTP status $httpCode not in expected statuses: " .
                                       implode(', ', $expectedStatuses);
        }

        // Apply expected response validation if configured
        $response = validateExpectedResponseContains($payload['config'], $result, $response);
    } else {
        // Request failed
        $response = [
            'task_id' => $payload['task_id'] ?? null,
            'success' => false,
            'error_message' => $result['curl_error'] ?? 'Unknown error',
            'timestamp' => date('c')
        ];
    }

    header('Content-Type: application/json');
    echo json_encode($response);
}

// Add security headers
addSecurityHeaders();

// Debug: Verify file version
error_log("CuliUptime Agent v0.1.1 - HMAC-only authentication loaded at " . date('Y-m-d H:i:s'));

// Handle the request
handleRequest();
