"""Sports Center foundation aggregates — Phase 9.0.

Independent aggregates use UUID references within sports_center_db only.
No SQLAlchemy relationship graphs between aggregates.
No sport-specific business rules are hardcoded — sports are configurable catalog entries.
"""
from __future__ import annotations

import uuid
from datetime import date, datetime

from sqlalchemy import (
    Boolean,
    Date,
    DateTime,
    Index,
    Integer,
    String,
    Text,
    UniqueConstraint,
)
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.types import JSON

from app.core.database import Base
from app.models.base import (
    ActorAuditMixin,
    OptimisticLockMixin,
    SoftDeleteMixin,
    TenantMixin,
    TimestampMixin,
    UUIDPrimaryKeyMixin,
)
from app.models.types import (
    AuditAction,
    ConnectorCapability,
    DeviceStatus,
    FacilityKind,
    GUID,
    LifecycleStatus,
    LockerStatus,
    MembershipStatus,
    StaffKind,
)


class SportsCenter(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
    OptimisticLockMixin,
):
    """Root sports center / club aggregate for a tenant."""

    __tablename__ = "sports_centers"

    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.DRAFT, nullable=False
    )
    legal_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
    timezone: Mapped[str] = mapped_column(String(64), default="Asia/Tehran", nullable=False)
    language: Mapped[str] = mapped_column(String(16), default="fa", nullable=False)
    currency_code: Mapped[str] = mapped_column(String(3), default="IRR", nullable=False)
    settings: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint("tenant_id", "code", name="uq_sports_centers_tenant_code"),
        Index("ix_sports_centers_tenant_status", "tenant_id", "status"),
        Index("ix_sports_centers_tenant_deleted", "tenant_id", "is_deleted"),
    )


class Branch(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Unlimited branches under a sports center."""

    __tablename__ = "branches"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.ACTIVE, nullable=False
    )
    address: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    timezone: Mapped[str | None] = mapped_column(String(64), nullable=True)
    working_hours: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "sports_center_id", "code", name="uq_branches_tenant_code"
        ),
        Index("ix_branches_center", "tenant_id", "sports_center_id"),
        Index("ix_branches_tenant_deleted", "tenant_id", "is_deleted"),
    )


class Sport(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Generic sport catalog entry — never encodes sport-specific rules."""

    __tablename__ = "sports"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.ACTIVE, nullable=False
    )
    category: Mapped[str | None] = mapped_column(String(100), nullable=True)
    attributes: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "sports_center_id", "code", name="uq_sports_tenant_code"
        ),
        Index("ix_sports_center", "tenant_id", "sports_center_id"),
        Index("ix_sports_tenant_deleted", "tenant_id", "is_deleted"),
    )


class MembershipType(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Configurable membership type — catalog depth expanded in Phase 9.1."""

    __tablename__ = "membership_types"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.ACTIVE, nullable=False
    )
    duration_days: Mapped[int | None] = mapped_column(Integer, nullable=True)
    policies: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    sport_ids: Mapped[list | None] = mapped_column(JSON, nullable=True)
    # Phase 9.1 catalog links (UUID refs within sports_center_db only)
    package_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    plan_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    pricing_model_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    age_group_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    sport_category_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    renewal_policy_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    freezing_rule_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    expiration_policy_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    is_transferable: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    sort_order: Mapped[int] = mapped_column(Integer, default=0, nullable=False)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id",
            "sports_center_id",
            "code",
            name="uq_membership_types_tenant_code",
        ),
        Index("ix_membership_types_center", "tenant_id", "sports_center_id"),
        Index("ix_membership_types_tenant_deleted", "tenant_id", "is_deleted"),
    )


class Membership(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
    OptimisticLockMixin,
):
    """Sports membership instance — assigned to a Member; consumes catalog types."""

    __tablename__ = "memberships"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    branch_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    membership_type_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    member_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    membership_number: Mapped[str] = mapped_column(String(50), nullable=False)
    display_name: Mapped[str] = mapped_column(String(255), nullable=False)
    email: Mapped[str | None] = mapped_column(String(255), nullable=True)
    mobile: Mapped[str | None] = mapped_column(String(50), nullable=True)
    external_customer_ref: Mapped[str | None] = mapped_column(String(100), nullable=True)
    external_crm_contact_ref: Mapped[str | None] = mapped_column(String(100), nullable=True)
    status: Mapped[MembershipStatus] = mapped_column(
        default=MembershipStatus.PENDING, nullable=False
    )
    starts_on: Mapped[date | None] = mapped_column(Date, nullable=True)
    ends_on: Mapped[date | None] = mapped_column(Date, nullable=True)
    freeze_starts_on: Mapped[date | None] = mapped_column(Date, nullable=True)
    freeze_ends_on: Mapped[date | None] = mapped_column(Date, nullable=True)
    profile: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    custom_fields: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id",
            "membership_number",
            name="uq_memberships_tenant_membership_number",
        ),
        Index("ix_memberships_center", "tenant_id", "sports_center_id"),
        Index("ix_memberships_member", "tenant_id", "member_id"),
        Index("ix_memberships_tenant_status", "tenant_id", "status"),
        Index("ix_memberships_tenant_deleted", "tenant_id", "is_deleted"),
    )


class Coach(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Coach / instructor shell — not Identity ownership."""

    __tablename__ = "coaches"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    branch_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    display_name: Mapped[str] = mapped_column(String(255), nullable=False)
    email: Mapped[str | None] = mapped_column(String(255), nullable=True)
    mobile: Mapped[str | None] = mapped_column(String(50), nullable=True)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.ACTIVE, nullable=False
    )
    sport_ids: Mapped[list | None] = mapped_column(JSON, nullable=True)
    qualifications: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    external_user_ref: Mapped[str | None] = mapped_column(String(100), nullable=True)
    # Phase 9.3 — staff depth
    staff_kind: Mapped[StaffKind] = mapped_column(
        default=StaffKind.COACH, nullable=False
    )
    bio: Mapped[str | None] = mapped_column(Text, nullable=True)
    hire_date: Mapped[date | None] = mapped_column(Date, nullable=True)
    payroll_external_ref: Mapped[str | None] = mapped_column(String(100), nullable=True)
    sports_role_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "sports_center_id", "code", name="uq_coaches_tenant_code"
        ),
        Index("ix_coaches_center", "tenant_id", "sports_center_id"),
        Index("ix_coaches_tenant_deleted", "tenant_id", "is_deleted"),
    )


class SportsRole(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Sports-center RBAC role definition (local to this service)."""

    __tablename__ = "sports_roles"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.ACTIVE, nullable=False
    )
    permission_codes: Mapped[list | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "sports_center_id", "code", name="uq_sports_roles_tenant_code"
        ),
        Index("ix_sports_roles_center", "tenant_id", "sports_center_id"),
        Index("ix_sports_roles_tenant_deleted", "tenant_id", "is_deleted"),
    )


class SportsPermission(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Sports-center permission catalog entries (local definitions)."""

    __tablename__ = "sports_permissions"

    sports_center_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    code: Mapped[str] = mapped_column(String(100), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.ACTIVE, nullable=False
    )

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "code", name="uq_sports_permissions_tenant_code"
        ),
        Index("ix_sports_permissions_tenant_deleted", "tenant_id", "is_deleted"),
    )


class Facility(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Generic facility shell (court/room/pool/field/studio as kind)."""

    __tablename__ = "facilities"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    branch_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    kind: Mapped[FacilityKind] = mapped_column(
        default=FacilityKind.GENERAL, nullable=False
    )
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.ACTIVE, nullable=False
    )
    capacity: Mapped[int | None] = mapped_column(Integer, nullable=True)
    attributes: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "sports_center_id", "code", name="uq_facilities_tenant_code"
        ),
        Index("ix_facilities_center", "tenant_id", "sports_center_id"),
        Index("ix_facilities_tenant_deleted", "tenant_id", "is_deleted"),
    )


class Court(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Court shell — specialization of facility via facility_id ref."""

    __tablename__ = "courts"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    branch_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    facility_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.ACTIVE, nullable=False
    )
    surface: Mapped[str | None] = mapped_column(String(100), nullable=True)
    attributes: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "sports_center_id", "code", name="uq_courts_tenant_code"
        ),
        Index("ix_courts_center", "tenant_id", "sports_center_id"),
        Index("ix_courts_tenant_deleted", "tenant_id", "is_deleted"),
    )


class Room(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Room shell."""

    __tablename__ = "rooms"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    branch_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    facility_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.ACTIVE, nullable=False
    )
    capacity: Mapped[int | None] = mapped_column(Integer, nullable=True)
    attributes: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "sports_center_id", "code", name="uq_rooms_tenant_code"
        ),
        Index("ix_rooms_center", "tenant_id", "sports_center_id"),
        Index("ix_rooms_tenant_deleted", "tenant_id", "is_deleted"),
    )


class LockerRoom(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Locker room shell."""

    __tablename__ = "locker_rooms"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    branch_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.ACTIVE, nullable=False
    )
    attributes: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "sports_center_id", "code", name="uq_locker_rooms_tenant_code"
        ),
        Index("ix_locker_rooms_center", "tenant_id", "sports_center_id"),
        Index("ix_locker_rooms_tenant_deleted", "tenant_id", "is_deleted"),
    )


class Locker(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
    OptimisticLockMixin,
):
    """Locker shell — assign/release events prepared; workflows later."""

    __tablename__ = "lockers"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    locker_room_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    label: Mapped[str | None] = mapped_column(String(100), nullable=True)
    status: Mapped[LockerStatus] = mapped_column(
        default=LockerStatus.AVAILABLE, nullable=False
    )
    assigned_membership_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    assigned_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True), nullable=True
    )
    attributes: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "locker_room_id", "code", name="uq_lockers_tenant_code"
        ),
        Index("ix_lockers_room", "tenant_id", "locker_room_id"),
        Index("ix_lockers_tenant_status", "tenant_id", "status"),
        Index("ix_lockers_tenant_deleted", "tenant_id", "is_deleted"),
    )


class DeviceProvider(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Device provider registry entry — adapter key only, no vendor SDK here."""

    __tablename__ = "device_providers"

    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    capability: Mapped[ConnectorCapability] = mapped_column(
        default=ConnectorCapability.CUSTOM, nullable=False
    )
    adapter_key: Mapped[str] = mapped_column(String(100), nullable=False)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.ACTIVE, nullable=False
    )
    config_schema: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    settings: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "code", name="uq_device_providers_tenant_code"
        ),
        Index("ix_device_providers_capability", "tenant_id", "capability"),
        Index("ix_device_providers_tenant_deleted", "tenant_id", "is_deleted"),
    )


class Device(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
    OptimisticLockMixin,
):
    """Physical/logical device shell — connect via connector adapters later."""

    __tablename__ = "devices"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    branch_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    device_provider_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    capability: Mapped[ConnectorCapability] = mapped_column(
        default=ConnectorCapability.CUSTOM, nullable=False
    )
    status: Mapped[DeviceStatus] = mapped_column(
        default=DeviceStatus.REGISTERED, nullable=False
    )
    location_ref: Mapped[str | None] = mapped_column(String(100), nullable=True)
    external_device_ref: Mapped[str | None] = mapped_column(String(100), nullable=True)
    settings: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "sports_center_id", "code", name="uq_devices_tenant_code"
        ),
        Index("ix_devices_center", "tenant_id", "sports_center_id"),
        Index("ix_devices_tenant_status", "tenant_id", "status"),
        Index("ix_devices_tenant_deleted", "tenant_id", "is_deleted"),
    )


class AttendanceGateway(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Attendance gateway configuration shell — provider swap via events."""

    __tablename__ = "attendance_gateways"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    branch_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.ACTIVE, nullable=False
    )
    primary_provider_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    fallback_provider_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    device_ids: Mapped[list | None] = mapped_column(JSON, nullable=True)
    policies: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id",
            "sports_center_id",
            "code",
            name="uq_attendance_gateways_tenant_code",
        ),
        Index("ix_attendance_gateways_center", "tenant_id", "sports_center_id"),
        Index("ix_attendance_gateways_tenant_deleted", "tenant_id", "is_deleted"),
    )


class SportsConfiguration(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
    OptimisticLockMixin,
):
    """Tenant sports configuration — working hours, policies, locale, custom fields."""

    __tablename__ = "sports_configurations"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    branch_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    working_hours: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    membership_policies: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    attendance_policies: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    booking_policies: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    waiting_list: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    custom_fields: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    timezone: Mapped[str] = mapped_column(String(64), default="Asia/Tehran", nullable=False)
    language: Mapped[str] = mapped_column(String(16), default="fa", nullable=False)
    currency_code: Mapped[str] = mapped_column(String(3), default="IRR", nullable=False)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id",
            "sports_center_id",
            "code",
            name="uq_sports_configurations_tenant_code",
        ),
        Index("ix_sports_configurations_center", "tenant_id", "sports_center_id"),
        Index("ix_sports_configurations_tenant_deleted", "tenant_id", "is_deleted"),
    )


class SportsEvent(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Generic sports event / session shell — no scheduling workflows yet."""

    __tablename__ = "sports_events"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    branch_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    sport_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    facility_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    coach_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    code: Mapped[str] = mapped_column(String(50), nullable=False)
    title: Mapped[str] = mapped_column(String(255), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    status: Mapped[LifecycleStatus] = mapped_column(
        default=LifecycleStatus.DRAFT, nullable=False
    )
    starts_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True), nullable=True
    )
    ends_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True), nullable=True
    )
    capacity: Mapped[int | None] = mapped_column(Integer, nullable=True)
    attributes: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "sports_center_id", "code", name="uq_sports_events_tenant_code"
        ),
        Index("ix_sports_events_center", "tenant_id", "sports_center_id"),
        Index("ix_sports_events_tenant_deleted", "tenant_id", "is_deleted"),
    )


class SportsSetting(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Key/value sports settings shell."""

    __tablename__ = "sports_settings"

    sports_center_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    branch_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    key: Mapped[str] = mapped_column(String(100), nullable=False)
    value: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id",
            "sports_center_id",
            "branch_id",
            "key",
            name="uq_sports_settings_tenant_key",
        ),
        Index("ix_sports_settings_tenant_deleted", "tenant_id", "is_deleted"),
    )


class SportsAuditLog(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
    """Append-only sports audit trail."""

    __tablename__ = "sports_audit_logs"

    entity_type: Mapped[str] = mapped_column(String(50), nullable=False)
    entity_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    action: Mapped[AuditAction] = mapped_column(nullable=False)
    actor_user_id: Mapped[str | None] = mapped_column(String(100), nullable=True)
    changes: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    message: Mapped[str | None] = mapped_column(Text, nullable=True)

    __table_args__ = (
        Index(
            "ix_sports_audit_entity",
            "tenant_id",
            "entity_type",
            "entity_id",
        ),
    )
