<?php

declare(strict_types=1);

namespace App\Framework\Core\ValueObjects;

enum TimeUnit: string
{
    case NANOSECOND = 'ns';
    case MICROSECOND = 'μs';
    case MILLISECOND = 'ms';
    case SECOND = 's';
    case MINUTE = 'min';
    case HOUR = 'h';
    case DAY = 'd';
    case WEEK = 'w';

    public function getMultiplierToSeconds(): float
    {
        return match ($this) {
            self::NANOSECOND => 1e-9,
            self::MICROSECOND => 1e-6,
            self::MILLISECOND => 0.001,
            self::SECOND => 1.0,
            self::MINUTE => 60.0,
            self::HOUR => 3600.0,
            self::DAY => 86400.0,
            self::WEEK => 604800.0,
        };
    }

    public function getName(): string
    {
        return match ($this) {
            self::NANOSECOND => 'Nanosecond',
            self::MICROSECOND => 'Microsecond',
            self::MILLISECOND => 'Millisecond',
            self::SECOND => 'Second',
            self::MINUTE => 'Minute',
            self::HOUR => 'Hour',
            self::DAY => 'Day',
            self::WEEK => 'Week',
        };
    }

    public function getNamePlural(): string
    {
        return match ($this) {
            self::NANOSECOND => 'Nanoseconds',
            self::MICROSECOND => 'Microseconds',
            self::MILLISECOND => 'Milliseconds',
            self::SECOND => 'Seconds',
            self::MINUTE => 'Minutes',
            self::HOUR => 'Hours',
            self::DAY => 'Days',
            self::WEEK => 'Weeks',
        };
    }

    public static function bestUnitFor(float $seconds): self
    {
        $absSeconds = abs($seconds);

        if ($absSeconds >= 604800) { // 1 week
            return self::WEEK;
        } elseif ($absSeconds >= 86400) { // 1 day
            return self::DAY;
        } elseif ($absSeconds >= 3600) { // 1 hour
            return self::HOUR;
        } elseif ($absSeconds >= 60) { // 1 minute
            return self::MINUTE;
        } elseif ($absSeconds >= 1) {
            return self::SECOND;
        } elseif ($absSeconds >= 0.001) {
            return self::MILLISECOND;
        } elseif ($absSeconds >= 1e-6) {
            return self::MICROSECOND;
        } else {
            return self::NANOSECOND;
        }
    }

    public static function fromString(string $unit): self
    {
        return match (strtolower(trim($unit))) {
            'ns', 'nano', 'nanosecond', 'nanoseconds' => self::NANOSECOND,
            'μs', 'us', 'micro', 'microsecond', 'microseconds' => self::MICROSECOND,
            'ms', 'milli', 'millisecond', 'milliseconds' => self::MILLISECOND,
            's', 'sec', 'second', 'seconds' => self::SECOND,
            'min', 'minute', 'minutes' => self::MINUTE,
            'h', 'hr', 'hour', 'hours' => self::HOUR,
            'd', 'day', 'days' => self::DAY,
            'w', 'week', 'weeks' => self::WEEK,
            default => throw new \InvalidArgumentException("Unknown time unit: $unit"),
        };
    }
}
