<?php
/**
 * API Client 测试
 *
 * @package StablePay_WooCommerce
 */

use PHPUnit\Framework\TestCase;

class ApiClientTest extends TestCase {
    private $api_client;

    protected function setUp(): void {
        $this->api_client = new StablePay_API_Client(
            'test_merchant_id',
            'test_api_key',
            'test_secret_key',
            true,
            new StablePay_Logger(false)
        );
    }

    /**
     * 测试 API 客户端初始化
     */
    public function test_api_client_initialization() {
        $this->assertInstanceOf(StablePay_API_Client::class, $this->api_client);
    }

    /**
     * 测试 Nonce 生成
     */
    public function test_nonce_generation() {
        $reflection = new ReflectionClass($this->api_client);
        $method = $reflection->getMethod('generate_nonce');
        $method->setAccessible(true);

        $nonce1 = $method->invoke($this->api_client);
        $nonce2 = $method->invoke($this->api_client);

        // Nonce 应该是 UUID 格式
        $this->assertMatchesRegularExpression('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i', $nonce1);

        // 每次生成的 Nonce 应该不同
        $this->assertNotEquals($nonce1, $nonce2);
    }

    /**
     * 测试签名生成
     */
    public function test_signature_generation() {
        $reflection = new ReflectionClass($this->api_client);
        $method = $reflection->getMethod('generate_signature');
        $method->setAccessible(true);

        $timestamp = 1704067200;
        $nonce = 'test-nonce-123';
        $request_body = '{"test":"data"}';

        $signature = $method->invoke($this->api_client, $timestamp, $nonce, $request_body);

        // 签名应该是64字符的十六进制字符串
        $this->assertMatchesRegularExpression('/^[0-9a-f]{64}$/i', $signature);

        // 相同输入应该生成相同签名
        $signature2 = $method->invoke($this->api_client, $timestamp, $nonce, $request_body);
        $this->assertEquals($signature, $signature2);
    }

    /**
     * 测试 Webhook 签名验证
     */
    public function test_webhook_signature_verification() {
        $webhook_secret = 'test_webhook_secret';
        $timestamp = time();
        $body = '{"type":"payment.completed","data":{"object":{"session_id":"sess_123"}}}';

        // 生成正确的签名：HMAC-SHA256(timestamp + "." + body, secret)
        $payload = $timestamp . '.' . $body;
        $correct_signature = hash_hmac('sha256', $payload, $webhook_secret);

        // 验证正确签名
        $result = StablePay_API_Client::verify_webhook_signature($correct_signature, $timestamp, $body, $webhook_secret);
        $this->assertTrue($result);

        // 验证错误签名
        $wrong_signature = 'wrong_signature';
        $result = StablePay_API_Client::verify_webhook_signature($wrong_signature, $timestamp, $body, $webhook_secret);
        $this->assertFalse($result);

        // 验证过期时间戳
        $old_timestamp = time() - 400; // 超过5分钟
        $old_payload = $old_timestamp . '.' . $body;
        $old_signature = hash_hmac('sha256', $old_payload, $webhook_secret);
        $result = StablePay_API_Client::verify_webhook_signature($old_signature, $old_timestamp, $body, $webhook_secret);
        $this->assertFalse($result);

        // 验证篡改的请求体
        $tampered_body = '{"type":"payment.completed","data":{"object":{"session_id":"sess_456"}}}';
        $result = StablePay_API_Client::verify_webhook_signature($correct_signature, $timestamp, $tampered_body, $webhook_secret);
        $this->assertFalse($result);
    }

    /**
     * 测试错误响应解析
     */
    public function test_error_response_parsing() {
        $reflection = new ReflectionClass($this->api_client);
        $method = $reflection->getMethod('parse_error_response');
        $method->setAccessible(true);

        // 测试带错误消息的响应
        $data = array('error' => array('message' => 'Custom error message'));
        $message = $method->invoke($this->api_client, $data, 400);
        $this->assertEquals('Custom error message', $message);

        // 测试默认错误消息
        $message = $method->invoke($this->api_client, null, 401);
        $this->assertEquals('认证失败，请检查 API 密钥', $message);

        // 测试未知状态码
        $message = $method->invoke($this->api_client, null, 999);
        $this->assertEquals('未知错误', $message);
    }
}
