<?php

declare(strict_types=1);

namespace App\Framework\DateTime;

use App\Framework\Core\ValueObjects\Duration;

/**
 * System implementation of HighResolutionClock using hrtime() for monotonic timing
 *
 * This implementation provides high-precision timing capabilities that are
 * unaffected by system clock changes, making it ideal for performance measurements.
 */
final readonly class SystemHighResolutionClock implements HighResolutionClock
{
    /**
     * {@inheritDoc}
     */
    public function hrtime(): Duration
    {
        return Duration::fromNanoseconds(hrtime(true));
    }

    /**
     * {@inheritDoc}
     */
    public function measureDuration(callable $callback): array
    {
        $start = $this->hrtime();
        $result = $callback();
        $end = $this->hrtime();

        $duration = $end->subtract($start);

        return [
            'result' => $result,
            'duration' => $duration,
        ];
    }

    /**
     * {@inheritDoc}
     */
    public function benchmark(callable $callback, int $iterations = 1): array
    {
        if ($iterations < 1) {
            throw new \InvalidArgumentException('Iterations must be at least 1');
        }

        $durations = [];
        $totalDuration = Duration::zero();

        for ($i = 0; $i < $iterations; $i++) {
            $start = $this->hrtime();
            $callback();
            $end = $this->hrtime();

            $duration = $end->subtract($start);
            $durations[] = $duration;
            $totalDuration = $totalDuration->add($duration);
        }

        $averageDuration = Duration::fromNanoseconds(
            (int) round($totalDuration->toNanoseconds() / $iterations)
        );

        $minDuration = $durations[0];
        $maxDuration = $durations[0];

        foreach ($durations as $duration) {
            if ($duration->toNanoseconds() < $minDuration->toNanoseconds()) {
                $minDuration = $duration;
            }
            if ($duration->toNanoseconds() > $maxDuration->toNanoseconds()) {
                $maxDuration = $duration;
            }
        }

        return [
            'total' => $totalDuration,
            'average' => $averageDuration,
            'min' => $minDuration,
            'max' => $maxDuration,
        ];
    }
}
