<?php

declare(strict_types=1);

namespace App\Services\Countries;

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

final class CountryRemoteProvider implements CountryRemoteProviderInterface
{
    public function __construct(
        private readonly HttpFactory $http,
    ) {
    }

    public function fetchAll(): array
    {
        $endpoint = trim((string) config('skinbase-countries.endpoint', ''));

        if ($endpoint === '') {
            throw new RuntimeException('Country sync endpoint is not configured.');
        }

        $response = $this->http->acceptJson()
            ->connectTimeout(max(1, (int) config('skinbase-countries.connect_timeout', 5)))
            ->timeout(max(1, (int) config('skinbase-countries.timeout', 10)))
            ->retry(
                max(0, (int) config('skinbase-countries.retry_times', 2)),
                max(0, (int) config('skinbase-countries.retry_sleep_ms', 250)),
                throw: false,
            )
            ->get($endpoint);

        if (! $response->successful()) {
            throw new RuntimeException(sprintf('Country sync request failed with status %d.', $response->status()));
        }

        $payload = $response->json();

        if (! is_array($payload)) {
            throw new RuntimeException('Country sync response was not a JSON array.');
        }

        return $this->normalizePayload($payload);
    }

    public function normalizePayload(array $payload): array
    {
        $normalized = [];

        foreach ($payload as $record) {
            if (! is_array($record)) {
                continue;
            }

            $country = $this->normalizeRecord($record);

            if ($country !== null) {
                $normalized[] = $country;
            }
        }

        return $normalized;
    }

    /**
     * @param  array<string, mixed>  $record
     * @return array<string, mixed>|null
     */
    private function normalizeRecord(array $record): ?array
    {
        $iso2 = strtoupper(trim((string) ($record['cca2'] ?? $record['iso2'] ?? '')));

        if (! preg_match('/^[A-Z]{2}$/', $iso2)) {
            return null;
        }

        $iso3 = strtoupper(trim((string) ($record['cca3'] ?? $record['iso3'] ?? '')));
        $iso3 = preg_match('/^[A-Z]{3}$/', $iso3) ? $iso3 : null;

        $numericCode = trim((string) ($record['ccn3'] ?? $record['numeric_code'] ?? ''));
        $numericCode = preg_match('/^\d{1,3}$/', $numericCode)
            ? str_pad($numericCode, 3, '0', STR_PAD_LEFT)
            : null;

        $name = $record['name'] ?? [];
        $nameCommon = trim((string) ($name['common'] ?? $record['name_common'] ?? ''));

        if ($nameCommon === '') {
            return null;
        }

        $nameOfficial = trim((string) ($name['official'] ?? $record['name_official'] ?? ''));
        $flags = $record['flags'] ?? [];
        $flagSvgUrl = trim((string) ($flags['svg'] ?? $record['flag_svg_url'] ?? ''));
        $flagPngUrl = trim((string) ($flags['png'] ?? $record['flag_png_url'] ?? ''));
        $flagEmoji = trim((string) ($record['flag'] ?? $record['flag_emoji'] ?? ''));
        $region = trim((string) ($record['region'] ?? ''));
        $subregion = trim((string) ($record['subregion'] ?? ''));

        return [
            'iso2' => $iso2,
            'iso3' => $iso3,
            'numeric_code' => $numericCode,
            'name_common' => $nameCommon,
            'name_official' => $nameOfficial !== '' ? $nameOfficial : null,
            'region' => $region !== '' ? $region : null,
            'subregion' => $subregion !== '' ? $subregion : null,
            'flag_svg_url' => $flagSvgUrl !== '' ? $flagSvgUrl : null,
            'flag_png_url' => $flagPngUrl !== '' ? $flagPngUrl : null,
            'flag_emoji' => $flagEmoji !== '' ? $flagEmoji : null,
        ];
    }
}
