<?php

namespace App\Services\Prediction\Signals;

use App\Services\HaversineQuery;
use Illuminate\Support\Facades\DB;

final class RegionalMomentumSignal extends AbstractSignal
{
    private const float SLOPE_THRESHOLD_PENCE = 0.3;

    private const float REGIONAL_RADIUS_KM = 50.0;

    public function compute(SignalContext $context): array
    {
        if (! $context->hasCoordinates()) {
            return $this->disabledSignal('No coordinates provided for regional momentum analysis');
        }

        [$radiusSql, $radiusBindings] = HaversineQuery::withinKm($context->lat, $context->lng, self::REGIONAL_RADIUS_KM);

        $rows = DB::table('station_prices')
            ->join('stations', 'station_prices.station_id', '=', 'stations.node_id')
            ->where('station_prices.fuel_type', $context->fuelType->value)
            ->where('station_prices.price_effective_at', '>=', now()->subDays(14))
            ->whereRaw($radiusSql, $radiusBindings)
            ->selectRaw('DATE(station_prices.price_effective_at) as day, AVG(station_prices.price_pence) as avg_price')
            ->groupBy('day')
            ->orderBy('day')
            ->get();

        if ($rows->count() < 3) {
            return $this->disabledSignal('Insufficient regional data');
        }

        $regression = $this->linearRegression($rows->pluck('avg_price')->map(fn ($v) => (float) $v / 100)->values()->all());
        $direction = match (true) {
            $regression['slope'] >= self::SLOPE_THRESHOLD_PENCE => 'up',
            $regression['slope'] <= -self::SLOPE_THRESHOLD_PENCE => 'down',
            default => 'stable',
        };

        return [
            'score' => $direction === 'stable' ? 0.0 : ($direction === 'up' ? 0.7 : -0.7),
            'confidence' => min(1.0, $regression['r_squared']),
            'direction' => $direction,
            'detail' => 'Regional trend: '.round($regression['slope'], 2).'p/day (R²='.round($regression['r_squared'], 2).')',
            'data_points' => $rows->count(),
            'enabled' => true,
        ];
    }
}
