<?php

namespace App\Services\Warehouse;

use App\Models\Tenant\Purchase;
use App\Models\Tenant\Supplier;
use Illuminate\Support\Carbon;

class SupplierAnalytics
{
    /**
     * Percentage of received purchases that arrived on or before expected_at.
     * Returns null when there is no signal (no purchases with both dates).
     */
    public function onTimeRate(Supplier $supplier, int $days = 90): ?float
    {
        $since = Carbon::now()->subDays($days);
        $rows = Purchase::where('supplier_id', $supplier->id)
            ->where('status', 'received')
            ->whereNotNull('expected_at')
            ->whereNotNull('received_at')
            ->where('received_at', '>=', $since)
            ->get(['expected_at', 'received_at']);

        if ($rows->isEmpty()) return null;

        $onTime = $rows->filter(fn ($r) => $r->received_at->lte($r->expected_at))->count();
        return round($onTime / $rows->count() * 100, 1);
    }

    /** Average days between order_date and received_at. */
    public function avgDeliveryDays(Supplier $supplier, int $days = 90): ?float
    {
        $since = Carbon::now()->subDays($days);
        $rows = Purchase::where('supplier_id', $supplier->id)
            ->where('status', 'received')
            ->whereNotNull('order_date')
            ->whereNotNull('received_at')
            ->where('received_at', '>=', $since)
            ->get(['order_date', 'received_at']);

        if ($rows->isEmpty()) return null;

        $total = $rows->sum(fn ($r) => $r->order_date->diffInDays($r->received_at));
        return round($total / $rows->count(), 1);
    }

    /** Total spend (sum of purchase totals) over a window. */
    public function spend(Supplier $supplier, int $days = 90): float
    {
        $since = Carbon::now()->subDays($days);
        return (float) Purchase::where('supplier_id', $supplier->id)
            ->where('status', 'received')
            ->where('received_at', '>=', $since)
            ->sum('total');
    }

    /** Count of received purchases in window. */
    public function count(Supplier $supplier, int $days = 90): int
    {
        $since = Carbon::now()->subDays($days);
        return (int) Purchase::where('supplier_id', $supplier->id)
            ->where('status', 'received')
            ->where('received_at', '>=', $since)
            ->count();
    }

    /**
     * Compose a 1-5 score from on-time, delivery speed and spend volume.
     * Returns null when not enough signal — caller may keep manual rating.
     */
    public function computedRating(Supplier $supplier, int $days = 90): ?int
    {
        $onTime = $this->onTimeRate($supplier, $days);
        $count = $this->count($supplier, $days);

        if ($onTime === null || $count < 2) return null;   // need at least 2 deliveries to rate

        // On-time is the dominant factor (0..70 points).
        $score = $onTime * 0.7;
        // Bonus for higher volume (0..20 points capped at 10 purchases).
        $score += min(20, $count * 2);
        // Speed bonus: faster than 7 days avg → +10.
        $avg = $this->avgDeliveryDays($supplier, $days);
        if ($avg !== null && $avg < 7) $score += 10;

        return (int) max(1, min(5, round($score / 20)));
    }
}
