<?php

namespace App\Services\BrentPriceSources;

use App\Services\ApiLogger;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\RequestException;
use Illuminate\Support\Facades\Http;
use Throwable;

final class FredBrentPriceSource
{
    private const string URL = 'https://api.stlouisfed.org/fred/series/observations';

    public function __construct(private readonly ApiLogger $apiLogger) {}

    /**
     * @return array{date: string, price_usd: float}[]|null null only when the response carried no usable rows
     *
     * @throws BrentPriceFetchException on network failure or non-2xx response after retries
     */
    public function fetch(): ?array
    {
        try {
            $response = $this->apiLogger->send('fred', 'GET', self::URL, fn () => Http::timeout(30)
                ->retry(3, 200, fn (Throwable $e) => $this->shouldRetry($e))
                ->throw()
                ->get(self::URL, [
                    'series_id' => 'DCOILBRENTEU',
                    'api_key' => config('services.fred.api_key'),
                    'sort_order' => 'desc',
                    'limit' => 30,
                    'file_type' => 'json',
                ]));
        } catch (ConnectionException $e) {
            throw new BrentPriceFetchException("FRED connection failed: {$e->getMessage()}", previous: $e);
        } catch (RequestException $e) {
            throw new BrentPriceFetchException("FRED returned HTTP {$e->response->status()}", previous: $e);
        }

        $rows = collect($response->json('observations') ?? [])
            ->filter(fn (array $obs) => $obs['value'] !== '.')
            ->map(fn (array $obs) => [
                'date' => $obs['date'],
                'price_usd' => (float) $obs['value'],
            ])
            ->all();

        return $rows === [] ? null : $rows;
    }

    private function shouldRetry(Throwable $e): bool
    {
        return $e instanceof ConnectionException
            || ($e instanceof RequestException && $e->response->serverError());
    }
}
