<?php
/**
 * New Features Test Cases for CuliUptime PHP Agent
 *
 * Tests for new functionality added in v0.1.1:
 * - URL reconstruction with hostname mapping (localhost -> agent.local)
 * - Microsecond to millisecond timing conversion
 * - Debug URL endpoint
 * - Platform HTTP check handling
 */

class AgentNewFeaturesTest
{
    private $testResults = [];

    public function runAllTests()
    {
        echo "=== CuliUptime Agent New Features Tests ===\n";

        // URL reconstruction tests
        $this->testURLReconstructionMapping();
        $this->testDebugURLEndpoint();

        // Timing conversion tests
        $this->testMicrosecondToMillisecondConversion();

        // Platform request handling tests
        $this->testPlatformHttpCheckFormatting();
        $this->testBodySizeLimiting();

        $this->printResults();
    }

    /**
     * Test Case: URL Reconstruction with Hostname Mapping
     * New feature: localhost/127.0.0.1 -> agent.local mapping for HMAC canonical requests
     */
    public function testURLReconstructionMapping()
    {
        $testName = "URL Reconstruction with Hostname Mapping";

        // Test the hostname mapping logic from the agent
        $testCases = [
            ['host' => 'localhost', 'expected' => 'agent.local'],
            ['host' => '127.0.0.1', 'expected' => 'agent.local'],
            ['host' => 'example.com', 'expected' => 'example.com'],
            ['host' => 'agent.local', 'expected' => 'agent.local'],
        ];

        $allPassed = true;
        $results = [];

        foreach ($testCases as $case) {
            $originalHost = $case['host'];
            $expectedHost = $case['expected'];

            // Simulate the hostname mapping logic from web_agent.php line 168-170
            $mappedHost = $originalHost;
            if ($originalHost === 'localhost' || $originalHost === '127.0.0.1') {
                $mappedHost = 'agent.local';
            }

            $passed = $mappedHost === $expectedHost;
            $results[] = "{$originalHost}->{$mappedHost}" . ($passed ? ' ✓' : ' ✗');

            if (!$passed) {
                $allPassed = false;
            }
        }

        $this->recordResult($testName, $allPassed,
            "Expected: localhost/127.0.0.1 mapped to agent.local, others unchanged. " .
            "Results: " . implode(', ', $results)
        );
    }

    /**
     * Test Case: Debug URL Endpoint
     * New feature: ?action=debug-url endpoint for troubleshooting URL reconstruction
     */
    public function testDebugURLEndpoint()
    {
        $testName = "Debug URL Endpoint";

        // Simulate the debug endpoint logic from web_agent.php lines 707-736
        $_GET['action'] = 'debug-url';
        $_SERVER['REQUEST_METHOD'] = 'POST';
        $_SERVER['HTTPS'] = 'on';
        $_SERVER['HTTP_HOST'] = 'localhost';
        $_SERVER['REQUEST_URI'] = '/culiuptime-agent.php?action=debug-url';

        // Test the URL reconstruction logic
        $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
        $originalHost = $host;
        if ($host === 'localhost' || $host === '127.0.0.1') {
            $host = 'agent.local';
        }

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

        $expectedUrl = "https://agent.local/culiuptime-agent.php?action=debug-url";
        $passed = $fullUrl === $expectedUrl;

        $this->recordResult($testName, $passed,
            "Expected: {$expectedUrl}. " .
            "Got: {$fullUrl} (original_host: {$originalHost})"
        );

        // Clean up
        unset($_GET['action']);
    }

    /**
     * Test Case: Microsecond to Millisecond Timing Conversion
     * New feature: Convert cURL's microsecond timings to milliseconds for platform response
     */
    public function testMicrosecondToMillisecondConversion()
    {
        $testName = "Microsecond to Millisecond Timing Conversion";

        // Test the conversion logic from web_agent.php lines 870-875
        $testTimings = [
            'namelookup_time_us' => 15432,    // 15.432ms
            'connect_time_us' => 45678,       // 45.678ms
            'appconnect_time_us' => 156789,   // 156.789ms
            'pretransfer_time_us' => 189234,  // 189.234ms
            'starttransfer_time_us' => 567890, // 567.890ms
            'total_time_us' => 654321,        // 654.321ms
        ];

        $expectedMs = [
            'namelookup_time' => 15,    // intval(15432 / 1000)
            'connect_time' => 45,       // intval(45678 / 1000)
            'appconnect_time' => 156,   // intval(156789 / 1000)
            'pretransfer_time' => 189,  // intval(189234 / 1000)
            'starttransfer_time' => 567, // intval(567890 / 1000)
            'total_time' => 654,        // intval(654321 / 1000)
        ];

        $actualMs = [];
        foreach ($testTimings as $key => $microseconds) {
            $msKey = str_replace('_us', '', $key);
            $actualMs[$msKey] = intval($microseconds / 1000);
        }

        $passed = $actualMs === $expectedMs;

        $differences = [];
        if (!$passed) {
            foreach ($expectedMs as $key => $expected) {
                $actual = $actualMs[$key] ?? 'missing';
                if ($actual !== $expected) {
                    $differences[] = "{$key}: expected {$expected}, got {$actual}";
                }
            }
        }

        $this->recordResult($testName, $passed,
            "Expected: microsecond values converted to milliseconds. " .
            "Differences: " . implode(', ', $differences)
        );
    }

    /**
     * Test Case: Platform HTTP Check Response Formatting
     * New feature: Platform-specific response format with timing data in milliseconds
     */
    public function testPlatformHttpCheckFormatting()
    {
        $testName = "Platform HTTP Check Response Formatting";

        // Simulate platform HTTP check response formatting from web_agent.php lines 844-908
        $mockInfo = [
            'http_code' => 200,
            'total_time_us' => 1500000,    // 1.5 seconds = 1500ms
            'namelookup_time_us' => 50000,  // 50ms
            'connect_time_us' => 150000,    // 150ms
            'appconnect_time_us' => 300000, // 300ms
            'pretransfer_time_us' => 400000, // 400ms
            'starttransfer_time_us' => 800000, // 800ms
        ];

        $mockPayload = [
            'task_id' => 'test-task-123',
            'target' => 'https://example.com',
            'timeout' => 30,
            'method' => 'GET'
        ];

        // Build expected response structure
        $expectedResponse = [
            'task_id' => 'test-task-123',
            'success' => true,
            'response_time' => 1500, // total_time_us / 1000
            'status_code' => 200,
            'timestamp' => date('c'),
            'timing' => [
                'namelookup_time' => 50,   // / 1000
                'connect_time' => 150,     // / 1000
                'appconnect_time' => 300,  // / 1000
                'pretransfer_time' => 400, // / 1000
                'starttransfer_time' => 800, // / 1000
                'total_time' => 1500       // / 1000
            ]
        ];

        // Simulate the response building logic
        $actualResponse = [
            'task_id' => $mockPayload['task_id'],
            'success' => true,
            'response_time' => intval(($mockInfo['total_time_us'] ?? 0) / 1000),
            'status_code' => $mockInfo['http_code'] ?? null,
            'timestamp' => date('c'),
            'timing' => [
                'namelookup_time' => intval(($mockInfo['namelookup_time_us'] ?? 0) / 1000),
                'connect_time' => intval(($mockInfo['connect_time_us'] ?? 0) / 1000),
                'appconnect_time' => intval(($mockInfo['appconnect_time_us'] ?? 0) / 1000),
                'pretransfer_time' => intval(($mockInfo['pretransfer_time_us'] ?? 0) / 1000),
                'starttransfer_time' => intval(($mockInfo['starttransfer_time_us'] ?? 0) / 1000),
                'total_time' => intval(($mockInfo['total_time_us'] ?? 0) / 1000)
            ]
        ];

        // Compare key fields (ignoring timestamp)
        $passed = $actualResponse['task_id'] === $expectedResponse['task_id'] &&
                  $actualResponse['success'] === $expectedResponse['success'] &&
                  $actualResponse['response_time'] === $expectedResponse['response_time'] &&
                  $actualResponse['status_code'] === $expectedResponse['status_code'] &&
                  $actualResponse['timing'] === $expectedResponse['timing'];

        $this->recordResult($testName, $passed,
            "Expected: Platform response with millisecond timing data. " .
            "Got: response_time=" . $actualResponse['response_time'] . "ms, " .
            "total_time=" . $actualResponse['timing']['total_time'] . "ms"
        );
    }

    /**
     * Test Case: Response Body Size Limiting
     * New feature: Limit response body to 1KB for platform requests to prevent JSON parsing issues
     */
    public function testBodySizeLimiting()
    {
        $testName = "Response Body Size Limiting";

        // Test the body limiting logic from web_agent.php lines 879-895
        $maxBodySize = 1024; // 1KB limit

        // Test with small body (should be included completely)
        $smallBody = str_repeat('a', 500);
        $smallResult = $this->simulateBodyLimiting($smallBody, $maxBodySize);

        // Test with large body (should be truncated)
        $largeBody = str_repeat('b', 2048); // 2KB
        $largeResult = $this->simulateBodyLimiting($largeBody, $maxBodySize);

        $passed = $smallResult['body_content'] === $smallBody &&
                  $smallResult['body_size'] === 500 &&
                  !isset($smallResult['body_truncated']) &&
                  $largeResult['body_size'] === 2048 &&
                  strlen($largeResult['body_content']) === $maxBodySize &&
                  $largeResult['body_truncated'] === true;

        $this->recordResult($testName, $passed,
            "Expected: Small body complete, large body truncated to 1KB. " .
            "Got: small_body=" . strlen($smallResult['body_content'] ?? '') . "bytes, " .
            "large_body=" . strlen($largeResult['body_content'] ?? '') . "bytes, " .
            "large_truncated=" . ($largeResult['body_truncated'] ?? false ? 'yes' : 'no')
        );
    }

    /**
     * Helper function to simulate body limiting logic
     */
    private function simulateBodyLimiting($bodyContent, $maxBodySize)
    {
        $bodySize = strlen($bodyContent);
        $response = ['body_size' => $bodySize];

        if ($bodySize <= $maxBodySize) {
            $response['body_content'] = $bodyContent;
        } else {
            $response['body_content'] = substr($bodyContent, 0, $maxBodySize);
            $response['body_truncated'] = true;
        }

        return $response;
    }

    private function recordResult($testName, $passed, $details)
    {
        $this->testResults[] = [
            'name' => $testName,
            'passed' => $passed,
            'details' => $details
        ];

        echo ($passed ? "✓ PASS" : "✗ FAIL") . ": $testName\n";
        if (!$passed) {
            echo "   Details: $details\n";
        }
    }

    private function printResults()
    {
        $passed = 0;
        $total = count($this->testResults);

        foreach ($this->testResults as $result) {
            if ($result['passed']) $passed++;
        }

        echo "\n=== New Features Test Results ===\n";
        echo "Passed: $passed/$total\n";

        if ($passed === $total) {
            echo "🎉 All new feature tests passed!\n";
        } else {
            echo "❌ Some new feature tests failed. Review implementation.\n";
            echo "\nFailed tests:\n";
            foreach ($this->testResults as $result) {
                if (!$result['passed']) {
                    echo "- {$result['name']}: {$result['details']}\n";
                }
            }
        }
    }
}

// Run tests if executed directly
if (basename(__FILE__) === basename($_SERVER['SCRIPT_NAME'])) {
    $newFeaturesTest = new AgentNewFeaturesTest();
    $newFeaturesTest->runAllTests();
}
?>
