<?php

/**
 * Хелпер для роботи з числами
 * Розширені методи для маніпуляції числами
 *
 * @package Flowaxy\Support\Helpers
 * @version 1.0.0 Alpha prerelease
 */

declare(strict_types=1);

namespace Flowaxy\Support\Helpers;

final class NumberHelper
{
    /**
     * Форматувати число
     *
     * @param float|int $number
     * @param int $decimals
     * @param string $decimalSeparator
     * @param string $thousandsSeparator
     * @return string
     */
    public static function format(float|int $number, int $decimals = 2, string $decimalSeparator = '.', string $thousandsSeparator = ','): string
    {
        return number_format($number, $decimals, $decimalSeparator, $thousandsSeparator);
    }

    /**
     * Округлити число
     *
     * @param float $number
     * @param int $precision
     * @return float
     */
    public static function round(float $number, int $precision = 0): float
    {
        return round($number, $precision);
    }

    /**
     * Округлити вгору
     *
     * @param float $number
     * @return int
     */
    public static function ceil(float $number): int
    {
        return (int)ceil($number);
    }

    /**
     * Округлити вниз
     *
     * @param float $number
     * @return int
     */
    public static function floor(float $number): int
    {
        return (int)floor($number);
    }

    /**
     * Перевірити, чи число парне
     *
     * @param int $number
     * @return bool
     */
    public static function isEven(int $number): bool
    {
        return $number % 2 === 0;
    }

    /**
     * Перевірити, чи число непарне
     *
     * @param int $number
     * @return bool
     */
    public static function isOdd(int $number): bool
    {
        return $number % 2 !== 0;
    }

    /**
     * Обмежити число діапазоном
     *
     * @param float|int $number
     * @param float|int $min
     * @param float|int $max
     * @return float|int
     */
    public static function clamp(float|int $number, float|int $min, float|int $max): float|int
    {
        return max($min, min($max, $number));
    }

    /**
     * Перевірити, чи число в діапазоні
     *
     * @param float|int $number
     * @param float|int $min
     * @param float|int $max
     * @return bool
     */
    public static function between(float|int $number, float|int $min, float|int $max): bool
    {
        return $number >= $min && $number <= $max;
    }

    /**
     * Конвертувати байти в читабельний формат
     *
     * @param int $bytes
     * @param int $precision
     * @return string
     */
    public static function formatBytes(int $bytes, int $precision = 2): string
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];

        for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) {
            $bytes /= 1024;
        }

        return round($bytes, $precision) . ' ' . $units[$i];
    }

    /**
     * Генерація випадкового числа
     *
     * @param int $min
     * @param int $max
     * @return int
     */
    public static function random(int $min = 0, int $max = PHP_INT_MAX): int
    {
        return random_int($min, $max);
    }

    /**
     * Перевірити, чи значення числове
     *
     * @param mixed $value
     * @return bool
     */
    public static function isNumeric(mixed $value): bool
    {
        return is_numeric($value);
    }

    /**
     * Конвертувати в ціле число
     *
     * @param mixed $value
     * @param int $default
     * @return int
     */
    public static function toInt(mixed $value, int $default = 0): int
    {
        if (is_int($value)) {
            return $value;
        }

        if (is_numeric($value)) {
            return (int)$value;
        }

        return $default;
    }

    /**
     * Конвертувати в число з плаваючою точкою
     *
     * @param mixed $value
     * @param float $default
     * @return float
     */
    public static function toFloat(mixed $value, float $default = 0.0): float
    {
        if (is_float($value)) {
            return $value;
        }

        if (is_numeric($value)) {
            return (float)$value;
        }

        return $default;
    }
}
