"""Role domain model."""

from typing import TYPE_CHECKING

from sqlalchemy import Column, ForeignKey, String, Table, Text
from sqlalchemy import UUID as SQLUUID
from sqlalchemy.orm import Mapped, mapped_column, relationship

from apex.domain.models.user import user_role_association
from apex.infrastructure.database.base import Base, BaseModel

if TYPE_CHECKING:
    from apex.domain.models.permission import BasePermission
    from apex.domain.models.user import BaseUser

# Association table for many-to-many relationship between roles and permissions
# Defined here to avoid circular imports
# NOTE: Association tables must use Column(), not mapped_column()
role_permission_association = Table(
    "role_permission_association",
    Base.metadata,
    Column("role_id", SQLUUID(as_uuid=True), ForeignKey("roles.id", ondelete="CASCADE"), primary_key=True),
    Column("permission_id", SQLUUID(as_uuid=True), ForeignKey("permissions.id", ondelete="CASCADE"), primary_key=True),
)


class BaseRole(BaseModel):
    """
    Abstract base role model.

    Users should extend this class to create their own Role model.
    Example:
        class Role(BaseRole):
            __tablename__ = "roles"
    """

    __abstract__ = True

    # Basic fields
    name: Mapped[str] = mapped_column(String(100), unique=True, nullable=False, index=True)
    slug: Mapped[str | None] = mapped_column(String(100), unique=True, nullable=True, index=True)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)

    # Multi-tenant (optional - roles can be global or org-specific)
    organization_id: Mapped[str | None] = mapped_column(
        String(36),  # UUID as string
        nullable=True,
        index=True,
    )

    # Relationships
    users: Mapped[list["BaseUser"]] = relationship(
        "BaseUser",
        secondary=user_role_association,
        back_populates="roles",
        lazy="selectin",
    )
    permissions: Mapped[list["BasePermission"]] = relationship(
        "BasePermission",
        secondary=role_permission_association,
        back_populates="roles",
        lazy="selectin",
    )

