<?php

namespace App\Services;

use App\Models\WgTrafficSample;

/**
 * Turns per-peer cumulative traffic samples into a bucketed aggregate down/up THROUGHPUT series
 * for the dashboard SVG chart. Per peer, consecutive samples give a delta; negative deltas
 * (counter reset on a wg restart) clamp to 0; deltas are summed into time buckets across peers.
 */
class WgTraffic
{
    /**
     * @return array{window:int, points:array<int,array{t:int,down:int,up:int}>,
     *               total_down:int, total_up:int, peak_down:int, peak_up:int}
     */
    public function series(int $windowSeconds, int $buckets = 60): array
    {
        $windowSeconds = max(60, $windowSeconds);
        $buckets = max(1, $buckets);
        $now = time();
        $from = $now - $windowSeconds;
        $width = $windowSeconds / $buckets;

        $down = array_fill(0, $buckets, 0);
        $up = array_fill(0, $buckets, 0);

        $rows = WgTrafficSample::query()
            ->where('sampled_at', '>=', now()->subSeconds($windowSeconds + (int) ceil($width) + 5))
            ->orderBy('peer_pubkey')
            ->orderBy('sampled_at')
            ->get(['peer_pubkey', 'rx', 'tx', 'sampled_at']);

        $prev = [];
        foreach ($rows as $r) {
            $pk = $r->peer_pubkey;
            $t = $r->sampled_at->getTimestamp();
            if (isset($prev[$pk])) {
                $dRx = max(0, (int) $r->rx - $prev[$pk]['rx']);
                $dTx = max(0, (int) $r->tx - $prev[$pk]['tx']);
                $idx = (int) floor(($t - $from) / $width);
                if ($idx >= 0 && $idx < $buckets) {
                    $down[$idx] += $dRx;
                    $up[$idx] += $dTx;
                }
            }
            $prev[$pk] = ['rx' => (int) $r->rx, 'tx' => (int) $r->tx];
        }

        $points = [];
        for ($i = 0; $i < $buckets; $i++) {
            $points[] = [
                't' => (int) round($from + ($i + 0.5) * $width),
                'down' => $down[$i],
                'up' => $up[$i],
            ];
        }

        return [
            'window' => $windowSeconds,
            'points' => $points,
            'total_down' => array_sum($down),
            'total_up' => array_sum($up),
            'peak_down' => $down === [] ? 0 : max($down),
            'peak_up' => $up === [] ? 0 : max($up),
        ];
    }
}
