<?php

declare(strict_types=1);

namespace App\Framework\Core\ValueObjects;

use InvalidArgumentException;

final readonly class Percentage
{
    public function __construct(
        private float $value
    ) {
        if ($value < 0.0 || $value > 100.0) {
            throw new InvalidArgumentException('Percentage must be between 0 and 100');
        }
    }

    // Factory Methods
    public static function from(float $percentage): self
    {
        return new self($percentage);
    }

    public static function fromDecimal(float $decimal): self
    {
        return new self($decimal * 100);
    }

    public static function fromRatio(int $part, int $total): self
    {
        if ($total === 0) {
            throw new InvalidArgumentException('Total cannot be zero');
        }

        return new self(($part / $total) * 100);
    }

    // Parse from string like "75%" or "75"
    public static function parse(string $value): self
    {
        $value = trim($value);

        if (str_ends_with($value, '%')) {
            $value = substr($value, 0, -1);
        }

        if (! is_numeric($value)) {
            throw new InvalidArgumentException("Invalid percentage format: $value");
        }

        return new self((float) $value);
    }

    // Conversion Methods
    public function getValue(): float
    {
        return $this->value;
    }

    public function toDecimal(): float
    {
        return $this->value / 100;
    }

    public function format(int $precision = 1): string
    {
        return number_format($this->value, $precision) . '%';
    }

    // Comparison Methods
    public function equals(Percentage $other): bool
    {
        return abs($this->value - $other->value) < 1e-9;
    }

    public function greaterThan(Percentage $other): bool
    {
        return $this->value > $other->value;
    }

    public function lessThan(Percentage $other): bool
    {
        return $this->value < $other->value;
    }

    public function greaterThanOrEqual(Percentage $other): bool
    {
        return $this->value >= $other->value;
    }

    public function lessThanOrEqual(Percentage $other): bool
    {
        return $this->value <= $other->value;
    }

    // Threshold checks (useful for monitoring)
    public function isAbove(Percentage $threshold): bool
    {
        return $this->greaterThan($threshold);
    }

    public function isBelow(Percentage $threshold): bool
    {
        return $this->lessThan($threshold);
    }

    public function isCritical(float $threshold = 90.0): bool
    {
        return $this->value >= $threshold;
    }

    // Utility Methods
    public function isEmpty(): bool
    {
        return $this->value === 0.0;
    }

    public function isZero(): bool
    {
        return $this->value === 0.0;
    }

    public function isFull(): bool
    {
        return $this->value === 100.0;
    }

    public function toString(): string
    {
        return $this->format();
    }

    public function __toString(): string
    {
        return $this->format();
    }

    // Common constants
    public static function zero(): self
    {
        return new self(0.0);
    }

    public static function full(): self
    {
        return new self(100.0);
    }
}
