<?php

declare(strict_types=1);

namespace Core;

final class RequestLimits
{
    private const DEFAULT_APP_UPLOAD_MAX_FILE_MB = 6;

    public static function parseIniSizeToBytes(string $value): int
    {
        $value = trim($value);
        if ($value === '') {
            return 0;
        }

        $number = (float) $value;
        $unit = strtolower(substr($value, -1));

        return match ($unit) {
            'g' => (int) round($number * 1024 * 1024 * 1024),
            'm' => (int) round($number * 1024 * 1024),
            'k' => (int) round($number * 1024),
            default => (int) round((float) $value),
        };
    }

    public static function uploadMaxFileBytes(): int
    {
        $phpUploadLimitBytes = self::phpUploadMaxFileBytes();
        $appUploadCapBytes = self::appUploadMaxFileCapBytes();

        if ($phpUploadLimitBytes <= 0) {
            return $appUploadCapBytes;
        }

        if ($appUploadCapBytes <= 0) {
            return $phpUploadLimitBytes;
        }

        return min($phpUploadLimitBytes, $appUploadCapBytes);
    }

    public static function phpUploadMaxFileBytes(): int
    {
        $uploadMaxBytes = self::parseIniSizeToBytes((string) ini_get('upload_max_filesize'));
        $postMaxBytes = self::postMaxBytes();

        if ($uploadMaxBytes <= 0) {
            return $postMaxBytes;
        }

        if ($postMaxBytes <= 0) {
            return $uploadMaxBytes;
        }

        return min($uploadMaxBytes, $postMaxBytes);
    }

    public static function appUploadMaxFileCapBytes(): int
    {
        $configuredMb = self::normalizePositiveInt((int) \env('APP_UPLOAD_MAX_FILE_MB', self::DEFAULT_APP_UPLOAD_MAX_FILE_MB), self::DEFAULT_APP_UPLOAD_MAX_FILE_MB);
        return $configuredMb * 1024 * 1024;
    }

    public static function postMaxBytes(): int
    {
        return self::parseIniSizeToBytes((string) ini_get('post_max_size'));
    }

    public static function uploadMaxFileLabel(): string
    {
        return self::formatBytes(self::uploadMaxFileBytes());
    }

    public static function postMaxLabel(): string
    {
        return self::formatBytes(self::postMaxBytes());
    }

    public static function formTimeoutSeconds(): int
    {
        return self::normalizePositiveInt((int) \env('FORM_TIMEOUT_SECONDS', 600), 600);
    }

    public static function requestTimeoutSeconds(): int
    {
        return self::normalizePositiveInt((int) \env('REQUEST_TIMEOUT_SECONDS', 600), 600);
    }

    public static function formatBytes(int $bytes): string
    {
        if ($bytes <= 0) {
            return '0 B';
        }

        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        $size = (float) $bytes;
        $unitIndex = 0;

        while ($size >= 1024 && $unitIndex < count($units) - 1) {
            $size /= 1024;
            $unitIndex++;
        }

        $decimals = $size >= 100 || $unitIndex === 0 ? 0 : ($size >= 10 ? 1 : 2);
        $formatted = number_format($size, $decimals, ',', '.');

        return $formatted . ' ' . $units[$unitIndex];
    }

    private static function normalizePositiveInt(int $value, int $default): int
    {
        return $value > 0 ? $value : $default;
    }
}
