<?php

use Illuminate\Http\Client\PendingRequest;
use App\Support\Integration\WalletApiRequestGuard;
use App\Support\Integration\WalletApiUrlSanitizer;

test('wallet api sanitizer rejects private and reserved literal addresses', function (string $url): void {
    expect(WalletApiUrlSanitizer::normalizeAndValidate($url))->toBeNull();
})->with([
    'ipv4 loopback' => 'https://127.0.0.1',
    'ipv4 shortened notation' => 'https://127.1',
    'ipv4 decimal integer notation' => 'https://2130706433',
    'ipv4 hexadecimal notation' => 'https://0x7f000001',
    'ipv4 octal notation' => 'https://0177.0.0.1',
    'ipv4 private' => 'https://10.0.0.1',
    'ipv4 link local' => 'https://169.254.169.254',
    'ipv4 cgnat' => 'https://100.64.0.1',
    'ipv4 documentation' => 'https://192.0.2.1',
    'ipv6 loopback' => 'https://[::1]',
    'ipv6 unique local' => 'https://[fd00::1]',
    'ipv6 link local' => 'https://[fe80::1]',
    'ipv6 nat64 private target' => 'https://[64:ff9b::a00:1]',
    'ipv6 protocol assignment' => 'https://[2001::1]',
    'ipv6 documentation' => 'https://[2001:db8::1]',
]);

test('wallet api guard rejects hostname when any dns answer is non-public', function (): void {
    fakeWalletApiDns([
        'wallet.example.test' => ['93.184.216.34', '10.0.0.8'],
    ], []);

    expect(app(WalletApiRequestGuard::class)->guard('https://wallet.example.test', 10))
        ->toBeNull();
});

test('wallet api guard rejects unresolved hostname', function (): void {
    fakeWalletApiDns([], []);

    expect(app(WalletApiRequestGuard::class)->guard('https://missing.example.test', 10))
        ->toBeNull();
});

test('wallet api guard accepts public ipv4 and ipv6 dns answers and bounds connect timeout', function (): void {
    fakeWalletApiDns([
        'wallet.example.test' => ['93.184.216.34', '2606:4700:4700::1111'],
    ], []);

    $endpoint = app(WalletApiRequestGuard::class)->guard('https://wallet.example.test:8443', 120);

    expect($endpoint)->not->toBeNull()
        ->and($endpoint?->baseUrl)->toBe('https://wallet.example.test:8443')
        ->and($endpoint?->port)->toBe(8443)
        ->and($endpoint?->pinnedIp)->toBe('93.184.216.34')
        ->and($endpoint?->totalTimeoutSeconds)->toBe(120)
        ->and($endpoint?->connectTimeoutSeconds)->toBe(5);

    $pending = $endpoint?->request(['Authorization' => 'Bearer secret']);
    $optionsProperty = new ReflectionProperty(PendingRequest::class, 'options');
    $options = $optionsProperty->getValue($pending);

    expect($options['allow_redirects'] ?? null)->toBeFalse()
        ->and($options['proxy'] ?? null)->toBe('')
        ->and($options['timeout'] ?? null)->toBe(120)
        ->and($options['connect_timeout'] ?? null)->toBe(5)
        ->and($options['curl'][CURLOPT_RESOLVE] ?? null)
        ->toBe(['wallet.example.test:8443:93.184.216.34']);
});

test('wallet api sanitizer accepts normal public literals', function (): void {
    expect(WalletApiUrlSanitizer::normalizeAndValidate('https://93.184.216.34'))
        ->toBe('https://93.184.216.34')
        ->and(WalletApiUrlSanitizer::normalizeAndValidate('https://[2606:4700:4700::1111]'))
        ->toBe('https://[2606:4700:4700::1111]');
});
