import enum
import uuid
from datetime import datetime

from sqlalchemy import Boolean, DateTime, Enum, ForeignKey, String
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship

from api.models.base import Base, new_uuid


class Ecosystem(str, enum.Enum):
    python = "python"
    node = "node"
    rust = "rust"
    go = "go"
    java = "java"
    terraform = "terraform"
    ansible = "ansible"
    tool = "tool"
    other = "other"


class SBOMEntry(Base):
    """Snapshot-based SBOM entry — no updated_at; new ingest replaces old rows."""
    __tablename__ = "sbom_entries"

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), primary_key=True, default=new_uuid
    )
    repo_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), ForeignKey("managed_repos.id", ondelete="RESTRICT"),
        nullable=False, index=True,
    )
    package_name: Mapped[str] = mapped_column(String(300), nullable=False)
    package_version: Mapped[str | None] = mapped_column(String(100), nullable=True)
    ecosystem: Mapped[Ecosystem] = mapped_column(
        Enum(Ecosystem, name="ecosystem"), nullable=False
    )
    license_spdx: Mapped[str | None] = mapped_column(String(100), nullable=True)
    is_direct: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
    is_dev: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    snapshot_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("sbom_snapshots.id", ondelete="RESTRICT"),
        nullable=False,
        index=True,
    )
    snapshot_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), nullable=False
    )
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), nullable=False
    )

    repo: Mapped["ManagedRepo"] = relationship("ManagedRepo", lazy="selectin")  # noqa: F821
    snapshot: Mapped["SBOMSnapshot"] = relationship(  # noqa: F821
        "SBOMSnapshot", lazy="selectin", back_populates="entries"
    )
