<?php

namespace App\Services\Forecasting;

use DateTime;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use RuntimeException;

/**
 * Pulls the latest "Weekly road fuel prices (CSV) 2018 to 2026"
 * attachment from gov.uk's content API and upserts into
 * `weekly_pump_prices`.
 *
 * Idempotent: re-running on a day with no new publication is a no-op
 * (rows match by primary key `date`, content is unchanged).
 *
 * The forecast cache is busted at the end so the next API hit retrains
 * the ridge model on the fresh row.
 */
final class BeisImporter
{
    private const string API_URL = 'https://www.gov.uk/api/content/government/statistics/weekly-road-fuel-prices';

    private const string ATTACHMENT_TITLE = 'Weekly road fuel prices (CSV) 2018 to 2026';

    /**
     * @return array{
     *   csv_url: string,
     *   parsed: int,
     *   upserted: int,
     *   latest_date: string,
     * }
     */
    public function import(): array
    {
        $url = $this->resolveCsvUrl();
        $csv = $this->downloadCsv($url);
        $rows = $this->parse($csv);

        if ($rows === []) {
            throw new RuntimeException('BEIS CSV parsed empty — check delimiter / encoding');
        }

        DB::table('weekly_pump_prices')->upsert(
            $rows,
            ['date'],
            ['ulsp_pence', 'ulsd_pence', 'ulsp_duty_pence', 'ulsd_duty_pence', 'ulsp_vat_pct', 'ulsd_vat_pct'],
        );

        Cache::flush();

        $latest = (string) collect($rows)->pluck('date')->sortDesc()->first();

        return [
            'csv_url' => $url,
            'parsed' => count($rows),
            'upserted' => count($rows),
            'latest_date' => $latest,
        ];
    }

    private function resolveCsvUrl(): string
    {
        $response = Http::timeout(15)->acceptJson()->get(self::API_URL);
        $response->throw();

        $attachments = $response->json('details.attachments', []);
        foreach ($attachments as $a) {
            if (($a['title'] ?? null) === self::ATTACHMENT_TITLE) {
                $url = $a['url'] ?? null;
                if (! is_string($url) || $url === '') {
                    throw new RuntimeException('BEIS attachment had empty URL');
                }

                return $url;
            }
        }

        throw new RuntimeException(sprintf(
            'gov.uk content API did not return an attachment titled %s',
            self::ATTACHMENT_TITLE,
        ));
    }

    private function downloadCsv(string $url): string
    {
        $response = Http::timeout(60)->get($url);
        $response->throw();

        return $response->body();
    }

    /**
     * @return array<int, array<string, int|string>>
     */
    private function parse(string $csv): array
    {
        $rows = [];
        $lines = preg_split('/\r\n|\r|\n/', $csv);
        if ($lines === false || count($lines) < 2) {
            return [];
        }

        // Skip header.
        array_shift($lines);

        foreach ($lines as $line) {
            $line = trim($line);
            if ($line === '') {
                continue;
            }

            $cols = str_getcsv($line, escape: '\\');
            if (count($cols) < 7) {
                continue;
            }

            $date = DateTime::createFromFormat('d/m/Y', trim($cols[0]));
            if ($date === false) {
                continue;
            }

            $rows[] = [
                'date' => $date->format('Y-m-d'),
                'ulsp_pence' => (int) round(((float) $cols[1]) * 100),
                'ulsd_pence' => (int) round(((float) $cols[2]) * 100),
                'ulsp_duty_pence' => (int) round(((float) $cols[3]) * 100),
                'ulsd_duty_pence' => (int) round(((float) $cols[4]) * 100),
                'ulsp_vat_pct' => (int) $cols[5],
                'ulsd_vat_pct' => (int) $cols[6],
            ];
        }

        return $rows;
    }
}
