<?php

declare(strict_types=1);

use App\Jobs\RouteSupplierLeadJob;
use App\Models\SupplierLead;
use App\Models\SystemSetting;
use App\Support\WebhookUrlGuard;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Bus;

uses(DatabaseTransactions::class);

beforeEach(function () {
    SystemSetting::query()->where('key', 'supplier_webhook_secret')
        ->update(['value' => 'test-secret-32chars-aaaaaaaaaaaaaa']);
    SystemSetting::query()->where('key', 'supplier_ip_allowlist')->update(['value' => '[]']);
});

// --- Часть А: DNS-rebind пиннинг (юнит на WebhookUrlGuard::safeDeliveryIp) ---

test('safeDeliveryIp блокирует приватный/служебный адрес и не отдаёт ip для пиннинга', function () {
    foreach ([
        'https://10.0.0.1/hook',
        'https://169.254.169.254/hook',
        'https://127.0.0.1/hook',
        'https://192.168.1.1/hook',
    ] as $url) {
        $result = WebhookUrlGuard::safeDeliveryIp($url);
        expect($result['blockReason'])->not->toBeNull()
            ->and($result['ip'])->toBeNull();
    }
});

test('safeDeliveryIp пропускает публичный IP и отдаёт его для пиннинга', function () {
    $result = WebhookUrlGuard::safeDeliveryIp('https://1.1.1.1/hook');

    expect($result['blockReason'])->toBeNull()
        ->and($result['ip'])->toBe('1.1.1.1');
});

// --- Часть Б: аддитивный HMAC для supplier-webhook ---

test('secretless /api/webhook/supplier принимает валидную HMAC-подпись → 202', function () {
    Bus::fake();
    $secret = 'test-secret-32chars-aaaaaaaaaaaaaa';
    $body = json_encode(['vid' => 55501, 'project' => 'B1_hmac.ru', 'phone' => '79991234567', 'time' => time()]);
    $sig = hash_hmac('sha256', $body, $secret);

    $response = $this->call('POST', '/api/webhook/supplier', [], [], [], [
        'CONTENT_TYPE' => 'application/json',
        'HTTP_ACCEPT' => 'application/json',
        'HTTP_X_WEBHOOK_SIGNATURE' => $sig,
    ], $body);

    expect($response->getStatusCode())->toBe(202);
    expect(SupplierLead::where('vid', 55501)->exists())->toBeTrue();
    Bus::assertDispatched(RouteSupplierLeadJob::class);
});

test('secretless /api/webhook/supplier без подписи → 404', function () {
    $body = json_encode(['vid' => 55502, 'project' => 'B1_hmac.ru', 'phone' => '79991234567', 'time' => time()]);

    $response = $this->call('POST', '/api/webhook/supplier', [], [], [], [
        'CONTENT_TYPE' => 'application/json',
        'HTTP_ACCEPT' => 'application/json',
    ], $body);

    expect($response->getStatusCode())->toBe(404);
});

test('secretless /api/webhook/supplier с неверной подписью → 404', function () {
    $body = json_encode(['vid' => 55503, 'project' => 'B1_hmac.ru', 'phone' => '79991234567', 'time' => time()]);

    $response = $this->call('POST', '/api/webhook/supplier', [], [], [], [
        'CONTENT_TYPE' => 'application/json',
        'HTTP_ACCEPT' => 'application/json',
        'HTTP_X_WEBHOOK_SIGNATURE' => 'deadbeefdeadbeefdeadbeefdeadbeef',
    ], $body);

    expect($response->getStatusCode())->toBe(404);
});

test('существующий {secret}-маршрут продолжает принимать по URL-секрету → 202', function () {
    Bus::fake();

    $response = $this->postJson('/api/webhook/supplier/test-secret-32chars-aaaaaaaaaaaaaa', [
        'vid' => 55504, 'project' => 'B1_hmac.ru', 'phone' => '79991234567', 'time' => time(),
    ]);

    expect($response->getStatusCode())->toBe(202);
});
