<?php

declare(strict_types=1);

namespace App\Framework\Core\ValueObjects;

use InvalidArgumentException;

/**
 * Represents growth rates that can exceed 100% (e.g., memory growth, performance metrics)
 */
final readonly class GrowthRate
{
    public function __construct(
        private float $value
    ) {
        if ($value < 0.0) {
            throw new InvalidArgumentException('Growth rate cannot be negative');
        }
    }

    // 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(float $current, float $original): self
    {
        if ($original <= 0) {
            throw new InvalidArgumentException('Original value must be positive');
        }

        return new self(($current / $original - 1) * 100);
    }

    public static function fromMemoryValues(int $currentBytes, int $originalBytes): self
    {
        if ($originalBytes <= 0) {
            throw new InvalidArgumentException('Original memory value must be positive');
        }

        return new self(($currentBytes / $originalBytes - 1) * 100);
    }

    // Parse from string like "150%" or "150"
    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 growth rate 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 toMultiplier(): float
    {
        return 1 + ($this->value / 100);
    }

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

    public function formatWithSign(int $precision = 1): string
    {
        $sign = $this->value >= 0 ? '+' : '';

        return $sign . number_format($this->value, $precision) . '%';
    }

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

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

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

    // Growth Analysis Methods
    public function isPositiveGrowth(): bool
    {
        return $this->value > 0;
    }

    public function isNegativeGrowth(): bool
    {
        return $this->value < 0;
    }

    public function isNoGrowth(): bool
    {
        return abs($this->value) < 1e-9;
    }

    // Memory-specific analysis
    public function isModerateMemoryGrowth(): bool
    {
        return $this->value >= 10.0 && $this->value < 50.0;
    }

    public function isHighMemoryGrowth(): bool
    {
        return $this->value >= 50.0 && $this->value < 100.0;
    }

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

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

    // Performance-specific analysis
    public function isSignificantGrowth(float $threshold = 25.0): bool
    {
        return $this->value >= $threshold;
    }

    public function getGrowthLevel(): string
    {
        return match (true) {
            $this->value < 0 => 'decrease',
            $this->value < 1 => 'none',
            $this->value < 10 => 'minimal',
            $this->value < 25 => 'low',
            $this->value < 50 => 'moderate',
            $this->value < 100 => 'high',
            $this->value < 200 => 'critical',
            default => 'extreme'
        };
    }

    // Arithmetic Operations
    public function add(GrowthRate $other): self
    {
        return new self($this->value + $other->value);
    }

    public function subtract(GrowthRate $other): self
    {
        return new self($this->value - $other->value);
    }

    public function multiply(float $factor): self
    {
        return new self($this->value * $factor);
    }

    public function divide(float $divisor): self
    {
        if ($divisor == 0) {
            throw new InvalidArgumentException('Cannot divide by zero');
        }

        return new self($this->value / $divisor);
    }

    // Utility Methods
    public function toPercentage(): ?Percentage
    {
        // Convert to Percentage only if within valid range
        if ($this->value >= 0.0 && $this->value <= 100.0) {
            return Percentage::from($this->value);
        }

        return null;
    }

    public function clampToPercentage(): Percentage
    {
        return Percentage::from(min(100.0, max(0.0, $this->value)));
    }

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

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

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

    public static function tripleGrowth(): self
    {
        return new self(200.0);
    }
}
