"""Version reference parsing for the tag/revision/digest model.

Replaces semantic versioning with three reference types:
- Tags: human-friendly mutable labels (e.g., "latest", "stable")
- Revisions: auto-incrementing integers (e.g., "3")
- Digests: content hash prefixes (e.g., "sha256:abc123")
"""

import re
from enum import Enum

from pydantic import BaseModel

__all__ = [
    "RefType",
    "VersionRef",
]

# Tag constraints: lowercase alphanumeric + hyphens + dots.
# Cannot be a pure integer. Cannot start with "sha256:".
_TAG_PATTERN = re.compile(r"^[a-z0-9][a-z0-9.\-]*$")


class RefType(str, Enum):
    """Type of version reference."""

    TAG = "tag"
    REVISION = "revision"
    DIGEST = "digest"


class VersionRef(BaseModel):
    """Parsed version reference.

    Supports three reference types:
        org/name@latest         -> TagRef("latest")
        org/name@stable         -> TagRef("stable")
        org/name@3              -> RevisionRef(3)
        org/name@sha256:abc123  -> DigestRef("sha256:abc123")
        org/name                -> implicit TagRef("latest")
    """

    type: RefType
    value: str

    @classmethod
    def parse(cls, ref: str | None) -> "VersionRef":
        """Parse a version reference string.

        Args:
            ref: Raw string after @ in a package reference.
                None or empty defaults to "latest".

        Returns:
            Parsed VersionRef instance.
        """
        if ref is None or ref == "" or ref == "latest":
            return cls(type=RefType.TAG, value="latest")

        # Pure integer -> revision
        if ref.isdigit():
            return cls(type=RefType.REVISION, value=ref)

        # sha256: prefix -> digest
        if ref.startswith("sha256:"):
            return cls(type=RefType.DIGEST, value=ref)

        # Everything else -> tag
        return cls(type=RefType.TAG, value=ref)

    @property
    def revision(self) -> int:
        """Get the revision number (only valid for REVISION type)."""
        if self.type != RefType.REVISION:
            raise ValueError(f"Cannot get revision from {self.type} ref")
        return int(self.value)

    def __str__(self) -> str:
        return self.value


def validate_tag(tag: str) -> str:
    """Validate a tag name.

    Tag constraints:
    - Lowercase alphanumeric + hyphens + dots
    - Cannot be a pure integer (those are revisions)
    - Cannot start with "sha256:" (those are digests)

    Args:
        tag: Tag name to validate.

    Returns:
        The validated tag name.

    Raises:
        ValueError: If the tag name is invalid.
    """
    if not tag:
        raise ValueError("Tag name cannot be empty")

    if tag.isdigit():
        raise ValueError(
            f"Tag name cannot be a pure integer (would conflict with revision numbers). Got: {tag}"
        )

    if tag.startswith("sha256:"):
        raise ValueError(
            f"Tag name cannot start with 'sha256:' (reserved for digest references). Got: {tag}"
        )

    if not _TAG_PATTERN.match(tag):
        raise ValueError(
            f"Tag name must be lowercase alphanumeric with hyphens and dots only. Got: {tag}"
        )

    return tag
