<?php

declare(strict_types=1);

namespace App\Services\DaData;

use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\Factory as HttpFactory;

/**
 * HTTP-обёртка над DaData clean/phone (spec §3.6).
 *
 * POST https://cleaner.dadata.ru/api/v1/clean/phone
 *   Authorization: Token <key> ; X-Secret: <secret> ; body ["<phone>"]
 *
 * Retry — только на сетевые ошибки и 5xx (4xx → сразу DaDataException, без retry).
 * Сеть/таймаут после исчерпания retry → DaDataTimeoutException; 5xx → DaDataException.
 * Конвенция клиента зеркалит App\Services\Supplier\SupplierPortalClient (inject HttpFactory).
 */
class DaDataPhoneClient
{
    private const URL = 'https://cleaner.dadata.ru/api/v1/clean/phone';

    public function __construct(
        private readonly HttpFactory $http,
    ) {}

    public function cleanPhone(string $phone): DaDataPhoneResponse
    {
        $cfg = (array) config('services.dadata');
        $timeoutSec = max(1, (int) round(((int) ($cfg['timeout_ms'] ?? 2000)) / 1000));
        $attempts = max(1, (int) ($cfg['retries'] ?? 1) + 1);
        $apiKey = (string) ($cfg['api_key'] ?? '');
        $secret = (string) ($cfg['secret'] ?? '');

        $lastException = null;

        for ($attempt = 0; $attempt < $attempts; $attempt++) {
            try {
                $response = $this->http
                    ->asJson()
                    ->acceptJson()
                    ->timeout($timeoutSec)
                    ->withHeaders([
                        'Authorization' => 'Token '.$apiKey,
                        'X-Secret' => $secret,
                    ])
                    ->post(self::URL, [$phone]);
            } catch (ConnectionException $e) {
                $lastException = new DaDataTimeoutException(
                    'DaData connection failed: '.$e->getMessage(), 0, $e,
                );

                continue; // сеть → retry
            }

            if ($response->serverError()) {
                $lastException = new DaDataException('DaData 5xx: HTTP '.$response->status());

                continue; // 5xx → retry
            }

            if (! $response->successful()) {
                // 4xx — клиентская ошибка, retry бессмыслен.
                throw new DaDataException('DaData HTTP '.$response->status().': '.$response->body());
            }

            return $this->parse($response->json());
        }

        throw $lastException ?? new DaDataException('DaData failed without a response');
    }

    /**
     * @param  mixed  $body  декодированный JSON (ожидается массив с одним объектом)
     */
    private function parse($body): DaDataPhoneResponse
    {
        $row = (is_array($body) && isset($body[0]) && is_array($body[0])) ? $body[0] : [];

        return new DaDataPhoneResponse(
            qc: isset($row['qc']) ? (int) $row['qc'] : null,
            qcConflict: isset($row['qc_conflict']) ? (int) $row['qc_conflict'] : null,
            type: isset($row['type']) ? (string) $row['type'] : null,
            phone: isset($row['phone']) ? (string) $row['phone'] : null,
            provider: isset($row['provider']) ? (string) $row['provider'] : null,
            region: isset($row['region']) ? (string) $row['region'] : null,
            city: isset($row['city']) ? (string) $row['city'] : null,
            timezone: isset($row['timezone']) ? (string) $row['timezone'] : null,
            raw: $row,
        );
    }
}
