<?php

declare(strict_types=1);

use App\Services\DaData\DaDataException;
use App\Services\DaData\DaDataPhoneClient;
use App\Services\DaData\DaDataTimeoutException;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Support\Facades\Http;

it('parses qc=0 mobile response into DTO', function (): void {
    Http::fake(['cleaner.dadata.ru/*' => Http::response([[
        'qc' => 0, 'qc_conflict' => 0, 'type' => 'Мобильный', 'phone' => '+7 921 555-12-34',
        'provider' => 'МегаФон', 'region' => 'Санкт-Петербург и область', 'city' => null, 'timezone' => 'UTC+3',
    ]], 200)]);

    $resp = app(DaDataPhoneClient::class)->cleanPhone('79215551234');

    expect($resp->qc)->toBe(0)
        ->and($resp->provider)->toBe('МегаФон')
        ->and($resp->region)->toBe('Санкт-Петербург и область')
        ->and($resp->type)->toBe('Мобильный')
        ->and($resp->raw)->toBeArray();
});

it('parses qc=3 multiple response', function (): void {
    Http::fake(['cleaner.dadata.ru/*' => Http::response([[
        'qc' => 3, 'region' => 'Москва', 'provider' => 'МТС', 'type' => 'Мобильный',
    ]], 200)]);

    expect(app(DaDataPhoneClient::class)->cleanPhone('79991234567')->qc)->toBe(3);
});

it('sends Token auth, X-Secret header and json-array body', function (): void {
    config(['services.dadata.api_key' => 'KEY', 'services.dadata.secret' => 'SEC']);
    Http::fake(['cleaner.dadata.ru/*' => Http::response([['qc' => 0, 'region' => 'Москва']], 200)]);

    app(DaDataPhoneClient::class)->cleanPhone('79161234567');

    Http::assertSent(function ($request): bool {
        return $request->url() === 'https://cleaner.dadata.ru/api/v1/clean/phone'
            && $request->hasHeader('Authorization', 'Token KEY')
            && $request->hasHeader('X-Secret', 'SEC')
            && $request->body() === '["79161234567"]';
    });
});

it('throws DaDataTimeoutException on connection error', function (): void {
    Http::fake(fn () => throw new ConnectionException('timeout'));

    expect(fn () => app(DaDataPhoneClient::class)->cleanPhone('79215551234'))
        ->toThrow(DaDataTimeoutException::class);
});

it('throws DaDataException on persistent 5xx', function (): void {
    Http::fake(['cleaner.dadata.ru/*' => Http::response('upstream error', 500)]);

    expect(fn () => app(DaDataPhoneClient::class)->cleanPhone('79215551234'))
        ->toThrow(DaDataException::class);
});

it('retries once on 5xx then succeeds', function (): void {
    Http::fakeSequence('cleaner.dadata.ru/*')
        ->push('upstream error', 500)
        ->push([['qc' => 0, 'region' => 'Москва', 'provider' => 'МТС']], 200);

    $resp = app(DaDataPhoneClient::class)->cleanPhone('79161234567');

    expect($resp->qc)->toBe(0);
    Http::assertSentCount(2);
});

it('does not retry on 4xx client error', function (): void {
    Http::fake(['cleaner.dadata.ru/*' => Http::response('bad request', 400)]);

    expect(fn () => app(DaDataPhoneClient::class)->cleanPhone('79161234567'))
        ->toThrow(DaDataException::class);

    Http::assertSentCount(1);
});
