<?php

use Illuminate\Http\Client\ConnectionException;
use Illuminate\Support\Facades\Http;
use Modules\Payment\Enums\RefundStatus;
use Modules\Payment\Gateways\KbzMiniAppGateway;
use Modules\Payment\Support\KbzSignature;

$config = [
    'app_id' => 'APPID123',
    'merchant_code' => 'MERCH001',
    'merchant_key' => 'test-merchant-key',
    'base_url' => 'https://kbz.test/gateway',
    'notify_url' => 'https://app.test/api/v1/webhooks/kbz',
];

test('refund posts a correctly signed refund request, wiring the partial amount through', function () use ($config) {
    Http::fake(['kbz.test/*' => Http::response(['Response' => ['result' => 'SUCCESS', 'refund_order_id' => 'REFUND123']])]);

    (new KbzMiniAppGateway($config))->refund('EVB-FIXTURE-001', '8000', 'customer requested partial refund');

    Http::assertSent(function ($request) {
        $body = $request->data()['Request'];

        return $request->url() === 'https://kbz.test/gateway'
            && $body['method'] === 'kbz.payment.refund'
            && $body['sign_type'] === 'SHA256'
            && $body['biz_content']['appid'] === 'APPID123'
            && $body['biz_content']['merch_code'] === 'MERCH001'
            && $body['biz_content']['merch_order_id'] === 'EVB-FIXTURE-001'
            // unlike bnf_event (amount hardcoded/commented out), this is wired through
            && $body['biz_content']['refund_amount'] === '8000'
            && $body['biz_content']['refund_reason'] === 'customer requested partial refund'
            && ! empty($body['biz_content']['refund_request_no'])
            && $body['sign'] === KbzSignature::sign($body, 'test-merchant-key');
    });
});

test('refund returns a completed RefundResultData on success', function () use ($config) {
    Http::fake(['kbz.test/*' => Http::response(['Response' => ['result' => 'SUCCESS', 'refund_order_id' => 'REFUND123']])]);

    $result = (new KbzMiniAppGateway($config))->refund('EVB-FIXTURE-001', '8000', 'customer request');

    expect($result->status)->toBe(RefundStatus::Completed)
        ->and($result->gatewayRefundId)->toBe('REFUND123')
        ->and($result->gatewayPayload)->toBe(['result' => 'SUCCESS', 'refund_order_id' => 'REFUND123']);
});

test('refund returns a failed RefundResultData when KBZ rejects the request', function () use ($config) {
    Http::fake(['kbz.test/*' => Http::response(['Response' => ['result' => 'FAIL', 'msg' => 'Refund window expired']])]);

    $result = (new KbzMiniAppGateway($config))->refund('EVB-FIXTURE-001', '8000', 'customer request');

    expect($result->status)->toBe(RefundStatus::Failed)
        ->and($result->gatewayRefundId)->toBeNull()
        ->and($result->message)->toBe('Refund window expired');
});

test('refund returns a failed RefundResultData when the connection fails', function () use ($config) {
    Http::fake(['kbz.test/*' => fn () => throw new ConnectionException('Connection refused')]);

    $result = (new KbzMiniAppGateway($config))->refund('EVB-FIXTURE-001', '8000', 'customer request');

    expect($result->status)->toBe(RefundStatus::Failed)
        ->and($result->gatewayRefundId)->toBeNull()
        ->and($result->gatewayPayload)->toBe([])
        ->and($result->message)->toBe('Connection refused');
});

test('refund builds mTLS cert/ssl_key/verify options from config', function () {
    $gateway = new KbzMiniAppGateway([
        'app_id' => 'APPID123',
        'merchant_code' => 'MERCH001',
        'merchant_key' => 'test-merchant-key',
        'base_url' => 'https://kbz.test/gateway',
        'cert_path' => '/certs/merch.pem',
        'cert_key_path' => '/certs/merch.key',
        'ca_path' => '/certs/ca.crt',
        'cert_password' => 'secret',
    ]);

    $options = (new ReflectionMethod($gateway, 'mtlsOptions'))->invoke($gateway);

    expect($options)->toBe([
        'cert' => ['/certs/merch.pem', 'secret'],
        'ssl_key' => ['/certs/merch.key', 'secret'],
        'verify' => '/certs/ca.crt',
    ]);
});

test('refund omits mTLS options entirely when cert config is not set', function () use ($config) {
    $gateway = new KbzMiniAppGateway($config);

    $options = (new ReflectionMethod($gateway, 'mtlsOptions'))->invoke($gateway);

    expect($options)->toBe([]);
});
