<?php
/*
 * Copyright 2026 Alessandro Chiapparini <sprint_planer_web@chiapparini.org>
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * See the LICENSE file in the project root for the full license text.
 */

declare(strict_types=1);

namespace App\Services;

/**
 * Capacity math per spec §6.5.
 *
 * The same formula runs client-side in `sprint-planner.js` and server-side
 * here; any edit here must land in both places together.
 */
final class CapacityCalculator
{
    /** round to the nearest 0.5. */
    public static function roundHalf(float $x): float
    {
        return round($x * 2) / 2;
    }

    /**
     * Compute capacity for a single sprint worker.
     *
     * @return array{
     *   ressourcen: float,
     *   after_reserves: float,
     *   committed_prio1: float,
     *   available: float,
     * }
     */
    public static function forWorker(
        float $ressourcen,
        float $reserveFraction,
        float $committedPrio1Days = 0.0,
    ): array {
        $afterReserves = self::roundHalf($ressourcen * (1.0 - $reserveFraction));
        return [
            'ressourcen'      => $ressourcen,
            'after_reserves'  => $afterReserves,
            'committed_prio1' => $committedPrio1Days,
            'available'       => $afterReserves - $committedPrio1Days,
        ];
    }

    /**
     * Validate a 0.5-step numeric input: must be in [$min, $max] and land on a
     * half-day grid. Returns false if not finite, out of range, or mis-stepped.
     */
    public static function isHalfStep(
        float $v,
        float $min = 0.0,
        float $max = 5.0,
    ): bool {
        if (!is_finite($v)) {
            return false;
        }
        if ($v < $min || $v > $max) {
            return false;
        }
        $doubled = $v * 2;
        return abs($doubled - round($doubled)) < 1e-9;
    }

    /** Validate RTB or reserve_fraction — 0..1 in 0.05 steps. */
    public static function isRtbStep(float $v): bool
    {
        if (!is_finite($v) || $v < 0.0 || $v > 1.0) {
            return false;
        }
        $twentieths = $v * 20.0;
        return abs($twentieths - round($twentieths)) < 1e-9;
    }
}
