"""Package configuration models for Harbor task packages.

This module provides PackageReference for specifying package versions.
PackageInfo is now defined in harbor.models.task.config and can be used
as an optional field in TaskConfig for backward compatibility.
"""

import re

from pydantic import BaseModel, Field, field_validator

from harbor.models.package.version_ref import VersionRef

__all__ = [
    "PackageReference",
]


class PackageReference(BaseModel):
    """A reference to a specific package version.

    Used in dataset manifests and CLI commands to specify package versions.
    The ref field accepts tags, revision numbers, or content hash digests.
    """

    name: str = Field(
        ...,
        description="Package name in org/name format",
    )
    ref: str = Field(
        default="latest",
        description="Version reference (tag, revision number, or digest)",
    )

    @field_validator("name")
    @classmethod
    def validate_name_format(cls, v: str) -> str:
        """Validate that name follows org/name format."""
        pattern = r"^[a-z0-9_-]+/[a-z0-9_-]+$"
        if not re.match(pattern, v):
            raise ValueError(
                f"Package name must be in 'org/name' format with lowercase letters, "
                f"numbers, hyphens, and underscores only. Got: {v}"
            )
        return v

    @property
    def parsed_ref(self) -> VersionRef:
        """Parse the ref string into a VersionRef."""
        return VersionRef.parse(self.ref)

    @classmethod
    def parse(cls, ref_string: str) -> "PackageReference":
        """Parse a package reference string like 'org/name@ref'.

        Args:
            ref_string: Package reference in 'org/name@ref' format.
                If no '@' is present, defaults to 'latest'.

        Returns:
            PackageReference instance

        Raises:
            ValueError: If the format is invalid
        """
        if "@" not in ref_string:
            return cls(name=ref_string, ref="latest")

        name, ref = ref_string.rsplit("@", 1)
        return cls(name=name, ref=ref)

    def __str__(self) -> str:
        return f"{self.name}@{self.ref}"

    def __hash__(self) -> int:
        return hash((self.name, self.ref))

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, PackageReference):
            return NotImplemented
        return self.name == other.name and self.ref == other.ref

    @property
    def org(self) -> str:
        """Extract organization from package name."""
        return self.name.split("/")[0]

    @property
    def short_name(self) -> str:
        """Extract short name (without org) from package name."""
        return self.name.split("/")[1]
