<?php
/**
 * PayNow Integration Test Script
 * 
 * Tests the PayNow integration in sandbox environment
 * 
 * Usage:
 * 1. Update PAYNOW_INTEGRATION_ID and PAYNOW_INTEGRATION_KEY with test credentials
 * 2. Run: php test_paynow_integration.php
 * 
 * Test Credentials (Sandbox):
 * Get from: https://www.paynow.co.zw/developer/integration
 */

// Test configuration - UPDATE THESE WITH YOUR TEST CREDENTIALS
define('PAYNOW_INTEGRATION_ID', '1234');  // Replace with your test Integration ID
define('PAYNOW_INTEGRATION_KEY', 'abcd1234');  // Replace with your test Integration Key
define('PAYNOW_MERCHANT_ID', 'MUTALEX001');
define('PAYNOW_MERCHANT_EMAIL', 'payments@mutalexacademy.com');
define('PAYNOW_MERCHANT_MOBILE', '263771234567');
define('USE_SANDBOX', true);

// Include dependencies
require_once 'includes/paynow/PayNowClient.php';

echo "==============================================\n";
echo "  PayNow Integration Test Suite\n";
echo "==============================================\n\n";

$passed = 0;
$failed = 0;
$tests = [];

/**
 * Test helper function
 */
function runTest($name, $callback) {
    global $passed, $failed, $tests;
    
    echo "Testing: $name... ";
    
    try {
        $result = $callback();
        if ($result === true || (is_array($result) && isset($result['success']) && $result['success'])) {
            echo "✓ PASSED\n";
            $passed++;
            $tests[$name] = ['status' => 'passed', 'result' => $result];
        } else {
            echo "✗ FAILED\n";
            echo "  Result: " . json_encode($result, JSON_PRETTY_PRINT) . "\n";
            $failed++;
            $tests[$name] = ['status' => 'failed', 'result' => $result];
        }
    } catch (Exception $e) {
        echo "✗ FAILED\n";
        echo "  Error: " . $e->getMessage() . "\n";
        $failed++;
        $tests[$name] = ['status' => 'failed', 'error' => $e->getMessage()];
    }
}

function assertEquals($expected, $actual, $message = '') {
    if ($expected !== $actual) {
        throw new Exception("$message Expected: $expected, Got: $actual");
    }
    return true;
}

function assertTrue($condition, $message = '') {
    if (!$condition) {
        throw new Exception($message ?: 'Assertion failed');
    }
    return true;
}

// ============================================
// TEST 1: Client Initialization
// ============================================
runTest('PayNow Client Initialization', function() {
    $client = new \PayNow\PayNowClient(
        PAYNOW_INTEGRATION_ID,
        PAYNOW_INTEGRATION_KEY,
        PAYNOW_MERCHANT_ID,
        USE_SANDBOX,
        PAYNOW_MERCHANT_EMAIL,
        PAYNOW_MERCHANT_MOBILE
    );
    
    assertTrue($client instanceof \PayNow\PayNowClient, 'Client should be instance of PayNowClient');
    assertTrue($client->isStaging() === USE_SANDBOX, 'Staging mode should match');
    
    return ['success' => true, 'message' => 'Client initialized successfully'];
});

// ============================================
// TEST 2: Mobile Number Formatting
// ============================================
runTest('Mobile Number Formatting - Zimbabwe format', function() {
    $client = new \PayNow\PayNowClient(
        PAYNOW_INTEGRATION_ID,
        PAYNOW_INTEGRATION_KEY,
        PAYNOW_MERCHANT_ID,
        true
    );
    
    // Test using reflection to access private method
    $reflection = new ReflectionClass($client);
    $method = $reflection->getMethod('formatMobileNumber');
    $method->setAccessible(true);
    
    // Test 07XXXXXXXX format
    $result = $method->invoke($client, '0771234567');
    assertEquals('263771234567', $result, '07 format should convert to 263 format');
    
    // Test 7XXXXXXXX format
    $result = $method->invoke($client, '771234567');
    assertEquals('263771234567', $result, '7 format should convert to 263 format');
    
    // Test already 263 format
    $result = $method->invoke($client, '263771234567');
    assertEquals('263771234567', $result, '263 format should stay unchanged');
    
    return ['success' => true];
});

// ============================================
// TEST 3: Hash Generation
// ============================================
runTest('Hash Generation', function() {
    $client = new \PayNow\PayNowClient(
        PAYNOW_INTEGRATION_ID,
        PAYNOW_INTEGRATION_KEY,
        PAYNOW_MERCHANT_ID,
        true
    );
    
    $reflection = new ReflectionClass($client);
    $method = $reflection->getMethod('generateHash');
    $method->setAccessible(true);
    
    $params = [
        'id' => '1234',
        'reference' => 'TEST_REF_001',
        'amount' => '100.00',
        'status' => 'Message',
        'additionalinfo' => 'Test payment',
        'authemail' => 'test@example.com'
    ];
    
    $hash = $method->invoke($client, $params);
    
    // Hash should be 128 character hex string (SHA512)
    assertTrue(strlen($hash) === 128, 'Hash should be 128 characters');
    assertTrue(ctype_xdigit($hash), 'Hash should be hexadecimal');
    
    // Hash should be uppercase
    assertEquals(strtoupper($hash), $hash, 'Hash should be uppercase');
    
    return [
        'success' => true,
        'hash' => $hash,
        'expected_format' => 'SHA512 uppercase hex'
    ];
});

// ============================================
// TEST 4: Hash Verification
// ============================================
runTest('Hash Verification', function() {
    $client = new \PayNow\PayNowClient(
        PAYNOW_INTEGRATION_ID,
        PAYNOW_INTEGRATION_KEY,
        PAYNOW_MERCHANT_ID,
        true
    );
    
    // Test valid hash verification
    $response = [
        'status' => 'Paid',
        'transaction_id' => 'TXN123456',
        'reference' => 'TEST_REF_001',
        'amount' => '100.00'
    ];
    
    // Generate expected hash
    $hashString = 'Paid' . 'TXN123456' . 'TEST_REF_001' . '100.00' . PAYNOW_INTEGRATION_KEY;
    $expectedHash = strtoupper(hash('sha512', $hashString));
    
    $isValid = $client->verifyHash($response, $expectedHash);
    assertTrue($isValid, 'Valid hash should be verified');
    
    // Test invalid hash
    $invalidHash = strtoupper(hash('sha512', 'wrongkey'));
    $isValid = $client->verifyHash($response, $invalidHash);
    assertTrue(!$isValid, 'Invalid hash should fail verification');
    
    return ['success' => true];
});

// ============================================
// TEST 5: Payment Creation (Mock Test)
// ============================================
runTest('Payment Creation - Mock Request', function() {
    $client = new \PayNow\PayNowClient(
        PAYNOW_INTEGRATION_ID,
        PAYNOW_INTEGRATION_KEY,
        PAYNOW_MERCHANT_ID,
        true,
        PAYNOW_MERCHANT_EMAIL,
        PAYNOW_MERCHANT_MOBILE
    );
    
    // Note: This is a mock test. In production, you would test against the live API.
    // For sandbox testing, use: https://www.paynow.co.zw/site/paynow.aspx
    
    $reference = 'TEST_' . time() . '_' . rand(1000, 9999);
    $amount = 10.00;
    $description = 'Test Course Purchase';
    $email = 'test@example.com';
    
    // This would make a real API call - we're testing the parameter building
    $reflection = new ReflectionClass($client);
    $method = $reflection->getMethod('buildPaymentParams');
    $method->setAccessible(true);
    
    $params = $method->invoke($client, $reference, $amount, $description, $email, '', []);
    
    assertTrue(isset($params['id']), 'Should have integration ID');
    assertTrue(isset($params['reference']), 'Should have reference');
    assertTrue(isset($params['amount']), 'Should have amount');
    assertTrue(isset($params['additionalinfo']), 'Should have additionalinfo');
    assertEquals(PAYNOW_INTEGRATION_ID, $params['id'], 'Integration ID should match');
    assertEquals($reference, $params['reference'], 'Reference should match');
    assertEquals(number_format($amount, 2, '.', ''), $params['amount'], 'Amount should match');
    
    // Hash is generated in createPayment (not buildPaymentParams) after
    // returnurl/resulturl are added. Verify hash generation separately.
    $hashMethod = $reflection->getMethod('generateHash');
    $hashMethod->setAccessible(true);
    $paramsWithUrls = $params;
    $paramsWithUrls['returnurl'] = 'http://example.com/return';
    $paramsWithUrls['resulturl'] = 'http://example.com/webhook';
    $hash = $hashMethod->invoke($client, $paramsWithUrls);
    assertEquals(128, strlen($hash), 'Hash should be 128 characters (SHA512)');
    
    return [
        'success' => true,
        'params' => [
            'id' => $params['id'],
            'reference' => substr($params['reference'], 0, 20) . '...',
            'amount' => $params['amount'],
            'additionalinfo' => $params['additionalinfo'],
            'hash' => substr($hash, 0, 16) . '...'
        ]
    ];
});

// ============================================
// TEST 6: Payment Status Check (Mock Test)
// ============================================
runTest('Payment Status Check - Mock Request', function() {
    $client = new \PayNow\PayNowClient(
        PAYNOW_INTEGRATION_ID,
        PAYNOW_INTEGRATION_KEY,
        PAYNOW_MERCHANT_ID,
        true
    );
    
    // Test parameter building for status check
    $pollUrl = 'https://www.paynow.co.zw/interface/query?result=abc123&hash=xyz789';
    
    $parseUrl = parse_url($pollUrl);
    parse_str($parseUrl['query'], $params);
    
    assertTrue(isset($params['result']), 'Should have result param');
    assertTrue(isset($params['hash']), 'Should have hash param');
    
    return [
        'success' => true,
        'status' => 'Parameters validated',
        'poll_params' => array_keys($params)
    ];
});

// ============================================
// TEST 7: Webhook Signature Verification
// ============================================
runTest('Webhook Signature Verification', function() {
    $client = new \PayNow\PayNowClient(
        PAYNOW_INTEGRATION_ID,
        PAYNOW_INTEGRATION_KEY,
        PAYNOW_MERCHANT_ID,
        true
    );
    
    $payload = json_encode([
        'reference' => 'TEST_REF_001',
        'status' => 'Paid',
        'amount' => '100.00'
    ]);
    
    // Generate expected signature
    $expectedSignature = base64_encode(
        hash_hmac('sha256', $payload, PAYNOW_INTEGRATION_KEY, true)
    );
    
    $isValid = $client->verifyWebhookSignature($expectedSignature, $payload);
    assertTrue($isValid, 'Valid signature should be verified');
    
    // Test with wrong signature
    $wrongSignature = base64_encode(
        hash_hmac('sha256', 'wrong payload', PAYNOW_INTEGRATION_KEY, true)
    );
    $isValid = $client->verifyWebhookSignature($wrongSignature, $payload);
    assertTrue(!$isValid, 'Wrong signature should fail');
    
    return ['success' => true];
});

// ============================================
// TEST 8: Payment Response Handler
// ============================================
runTest('Payment Response Handler', function() {
    $successResponse = [
        'status' => 'Paid',
        'transaction_id' => 'TXN123456',
        'reference' => 'TEST_REF_001',
        'amount' => '100.00'
    ];
    
    $handler = new \PayNow\PayNowPaymentResponse($successResponse);
    
    assertTrue($handler->success(), 'Should be success for Paid status');
    assertTrue(!$handler->pending(), 'Should not be pending');
    assertTrue(!$handler->failed(), 'Should not be failed');
    assertTrue(!$handler->cancelled(), 'Should not be cancelled');
    assertEquals('Payment successful', $handler->getStatusMessage());
    
    $pendingResponse = ['status' => 'Pending'];
    $handler2 = new \PayNow\PayNowPaymentResponse($pendingResponse);
    assertTrue($handler2->pending(), 'Should be pending');
    
    $failedResponse = ['status' => 'Failed'];
    $handler3 = new \PayNow\PayNowPaymentResponse($failedResponse);
    assertTrue($handler3->failed(), 'Should be failed');
    
    return ['success' => true];
});

// ============================================
// TEST 9: Error Handling
// ============================================
runTest('Error Handling - Invalid Credentials', function() {
    try {
        $client = new \PayNow\PayNowClient('', '', '', true);
        return ['success' => false, 'error' => 'Should have thrown exception'];
    } catch (InvalidArgumentException $e) {
        return ['success' => true, 'message' => 'Properly throws exception for empty credentials'];
    }
});

// ============================================
// Print Summary
// ============================================
echo "\n==============================================\n";
echo "  Test Results Summary\n";
echo "==============================================\n";
echo "Total Tests: " . ($passed + $failed) . "\n";
echo "Passed: $passed\n";
echo "Failed: $failed\n";
echo "==============================================\n";

if ($failed > 0) {
    echo "\nFailed Tests:\n";
    foreach ($tests as $name => $test) {
        if ($test['status'] === 'failed') {
            echo "  - $name\n";
            if (isset($test['error'])) {
                echo "    Error: " . $test['error'] . "\n";
            }
        }
    }
}

echo "\n==============================================\n";
echo "  Next Steps for Production\n";
echo "==============================================\n";
echo "1. Get your PayNow credentials:\n";
echo "   - Go to: https://www.paynow.co.zw/developer/integration\n";
echo "   - Create an account and get Integration ID/Key\n";
echo "\n2. Update database settings:\n";
echo "   - Run: php add_paynow_fields_migration.php\n";
echo "   - Update credentials in admin panel\n";
echo "\n3. Test in sandbox:\n";
echo "   - Use sandbox gateway_type in payment gateway settings\n";
echo "   - Test complete payment flow\n";
echo "\n4. Deploy to production:\n";
echo "   - Change gateway_type to 'live'\n";
echo "   - Update with production credentials\n";
echo "   - Test webhook endpoints\n";
echo "==============================================\n";

exit($failed > 0 ? 1 : 0);
