<?php

declare(strict_types=1);

namespace App\Framework\Http\Versioning;

use App\Framework\Exception\ErrorCode;
use App\Framework\Exception\FrameworkException;

/**
 * Represents an API version with semantic versioning support
 */
final readonly class ApiVersion
{
    public function __construct(
        public int $major,
        public int $minor = 0,
        public int $patch = 0
    ) {
        if ($major < 1) {
            throw FrameworkException::create(
                ErrorCode::VAL_BUSINESS_RULE_VIOLATION,
                'Major version must be at least 1'
            );
        }

        if ($minor < 0 || $patch < 0) {
            throw FrameworkException::create(
                ErrorCode::VAL_BUSINESS_RULE_VIOLATION,
                'Minor and patch versions must be non-negative'
            );
        }
    }

    public function toString(): string
    {
        return "v{$this->major}.{$this->minor}.{$this->patch}";
    }

    public function toShortString(): string
    {
        return "v{$this->major}";
    }

    public function toNumericString(): string
    {
        return "{$this->major}.{$this->minor}.{$this->patch}";
    }

    public function equals(self $other): bool
    {
        return $this->major === $other->major
            && $this->minor === $other->minor
            && $this->patch === $other->patch;
    }

    public function isCompatibleWith(self $other): bool
    {
        // Same major version = compatible
        return $this->major === $other->major;
    }

    public function isNewerThan(self $other): bool
    {
        if ($this->major !== $other->major) {
            return $this->major > $other->major;
        }

        if ($this->minor !== $other->minor) {
            return $this->minor > $other->minor;
        }

        return $this->patch > $other->patch;
    }

    public static function fromString(string $version): self
    {
        // Remove 'v' prefix if present
        $version = ltrim($version, 'vV');

        // Parse semantic version (1.0.0, 1.0, 1)
        $parts = explode('.', $version);

        if (empty($parts) || ! is_numeric($parts[0])) {
            throw FrameworkException::create(
                ErrorCode::VAL_BUSINESS_RULE_VIOLATION,
                "Invalid version format: {$version}"
            );
        }

        $major = (int) $parts[0];
        $minor = isset($parts[1]) && is_numeric($parts[1]) ? (int) $parts[1] : 0;
        $patch = isset($parts[2]) && is_numeric($parts[2]) ? (int) $parts[2] : 0;

        return new self($major, $minor, $patch);
    }

    public static function v1(): self
    {
        return new self(1, 0, 0);
    }

    public static function v2(): self
    {
        return new self(2, 0, 0);
    }

    public static function latest(): self
    {
        return new self(1, 0, 0); // Default to v1.0.0
    }
}
