<?php

namespace App\Services\Prediction\Signals;

use Illuminate\Support\Facades\DB;

final class StickinessSignal extends AbstractSignal
{
    public function compute(SignalContext $context): array
    {
        $isSqlite = DB::connection()->getDriverName() === 'sqlite';
        $diffExpr = $isSqlite
            ? 'CAST((julianday(MAX(price_effective_at)) - julianday(MIN(price_effective_at))) AS INTEGER)'
            : 'DATEDIFF(MAX(price_effective_at), MIN(price_effective_at))';

        $rows = DB::table('station_prices')
            ->where('fuel_type', $context->fuelType->value)
            ->where('price_effective_at', '>=', now()->subDays(30))
            ->selectRaw("station_id, COUNT(*) as changes, {$diffExpr} as span_days")
            ->groupBy('station_id')
            ->having('changes', '>', 1)
            ->having('span_days', '>', 0)
            ->get();

        if ($rows->count() < 10) {
            return $this->disabledSignal('Insufficient stickiness data (need 10+ stations with price history)');
        }

        $avgHoldDays = $rows->avg(fn ($r) => $r->span_days / ($r->changes - 1));
        $avgHoldDays = round((float) $avgHoldDays, 1);

        $score = match (true) {
            $avgHoldDays < 2 => -0.1,
            $avgHoldDays > 5 => 0.1,
            default => 0.0,
        };

        $detail = match (true) {
            $avgHoldDays < 2 => "Volatile prices (avg hold: {$avgHoldDays} days) — harder to predict.",
            $avgHoldDays > 5 => "Sticky prices (avg hold: {$avgHoldDays} days) — more predictable.",
            default => "Normal hold period (avg: {$avgHoldDays} days).",
        };

        return [
            'score' => $score,
            'confidence' => min(1.0, $rows->count() / 200),
            'direction' => 'stable',
            'detail' => $detail,
            'data_points' => $rows->count(),
            'enabled' => true,
        ];
    }
}
