"""Member Management aggregates — Phase 9.2.

Independent aggregates use UUID references within sports_center_db only.
No ORM relationship graphs. Consumes Membership Catalog (9.1); does not recreate it.
Storage blobs are file refs only (Storage owns binaries).
"""
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 (
    CardKind,
    CardStatus,
    DocumentKind,
    FamilyRelationship,
    GUID,
    MemberStatus,
    WaiverStatus,
)


class Member(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
    OptimisticLockMixin,
):
    """Sports member profile — not Platform Member and not Loyalty Member."""

    __tablename__ = "members"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    branch_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    member_number: Mapped[str] = mapped_column(String(50), nullable=False)
    display_name: Mapped[str] = mapped_column(String(255), nullable=False)
    first_name: Mapped[str | None] = mapped_column(String(100), nullable=True)
    last_name: Mapped[str | None] = mapped_column(String(100), nullable=True)
    email: Mapped[str | None] = mapped_column(String(255), nullable=True)
    mobile: Mapped[str | None] = mapped_column(String(50), nullable=True)
    birth_date: Mapped[date | None] = mapped_column(Date, nullable=True)
    gender: Mapped[str | None] = mapped_column(String(32), nullable=True)
    status: Mapped[MemberStatus] = mapped_column(
        default=MemberStatus.ACTIVE, nullable=False
    )
    external_user_ref: Mapped[str | None] = mapped_column(String(100), 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)
    preferred_language: Mapped[str | None] = mapped_column(String(16), nullable=True)
    notes: Mapped[str | None] = mapped_column(Text, 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", "member_number", name="uq_members_tenant_member_number"
        ),
        Index("ix_members_center", "tenant_id", "sports_center_id"),
        Index("ix_members_tenant_status", "tenant_id", "status"),
        Index("ix_members_tenant_deleted", "tenant_id", "is_deleted"),
    )


class FamilyMember(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Family / household link under a sports member."""

    __tablename__ = "family_members"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    member_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    related_member_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    display_name: Mapped[str] = mapped_column(String(255), nullable=False)
    relationship: Mapped[FamilyRelationship] = mapped_column(
        default=FamilyRelationship.OTHER, nullable=False
    )
    email: Mapped[str | None] = mapped_column(String(255), nullable=True)
    mobile: Mapped[str | None] = mapped_column(String(50), nullable=True)
    birth_date: Mapped[date | None] = mapped_column(Date, nullable=True)
    is_emergency_eligible: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    notes: Mapped[str | None] = mapped_column(Text, nullable=True)

    __table_args__ = (
        Index("ix_family_members_member", "tenant_id", "member_id"),
        Index("ix_family_members_tenant_deleted", "tenant_id", "is_deleted"),
    )


class EmergencyContact(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Emergency contact for a sports member."""

    __tablename__ = "emergency_contacts"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    member_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    display_name: Mapped[str] = mapped_column(String(255), nullable=False)
    relationship: Mapped[str | None] = mapped_column(String(64), nullable=True)
    phone: Mapped[str] = mapped_column(String(50), nullable=False)
    alternate_phone: Mapped[str | None] = mapped_column(String(50), nullable=True)
    email: Mapped[str | None] = mapped_column(String(255), nullable=True)
    is_primary: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    notes: Mapped[str | None] = mapped_column(Text, nullable=True)

    __table_args__ = (
        Index("ix_emergency_contacts_member", "tenant_id", "member_id"),
        Index("ix_emergency_contacts_tenant_deleted", "tenant_id", "is_deleted"),
    )


class MedicalInformation(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Privacy-aware medical clearance / note shell — not an EHR."""

    __tablename__ = "medical_information"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    member_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    blood_type: Mapped[str | None] = mapped_column(String(16), nullable=True)
    allergies: Mapped[list | None] = mapped_column(JSON, nullable=True)
    conditions: Mapped[list | None] = mapped_column(JSON, nullable=True)
    medications: Mapped[list | None] = mapped_column(JSON, nullable=True)
    clearance_status: Mapped[str | None] = mapped_column(String(32), nullable=True)
    clearance_expires_on: Mapped[date | None] = mapped_column(Date, nullable=True)
    physician_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
    physician_phone: Mapped[str | None] = mapped_column(String(50), nullable=True)
    notes: Mapped[str | None] = mapped_column(Text, nullable=True)
    document_file_ref: Mapped[str | None] = mapped_column(String(255), nullable=True)
    is_confidential: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "member_id", name="uq_medical_information_tenant_member"
        ),
        Index("ix_medical_information_member", "tenant_id", "member_id"),
        Index("ix_medical_information_tenant_deleted", "tenant_id", "is_deleted"),
    )


class MembershipCard(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Physical / digital / QR membership card shell."""

    __tablename__ = "membership_cards"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    member_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    membership_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    card_number: Mapped[str] = mapped_column(String(64), nullable=False)
    kind: Mapped[CardKind] = mapped_column(default=CardKind.QR, nullable=False)
    status: Mapped[CardStatus] = mapped_column(default=CardStatus.ACTIVE, nullable=False)
    qr_payload: Mapped[str | None] = mapped_column(String(512), nullable=True)
    barcode_payload: Mapped[str | None] = mapped_column(String(512), nullable=True)
    issued_on: Mapped[date | None] = mapped_column(Date, nullable=True)
    expires_on: Mapped[date | None] = mapped_column(Date, nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "card_number", name="uq_membership_cards_tenant_card_number"
        ),
        Index("ix_membership_cards_member", "tenant_id", "member_id"),
        Index("ix_membership_cards_tenant_status", "tenant_id", "status"),
        Index("ix_membership_cards_tenant_deleted", "tenant_id", "is_deleted"),
    )


class DigitalMembership(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Digital membership pass / wallet shell — token ref only."""

    __tablename__ = "digital_memberships"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    member_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    membership_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    pass_code: Mapped[str] = mapped_column(String(64), nullable=False)
    status: Mapped[CardStatus] = mapped_column(default=CardStatus.ACTIVE, nullable=False)
    token_ref: Mapped[str | None] = mapped_column(String(255), nullable=True)
    deep_link: Mapped[str | None] = mapped_column(String(512), nullable=True)
    issued_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    expires_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "pass_code", name="uq_digital_memberships_tenant_pass_code"
        ),
        Index("ix_digital_memberships_member", "tenant_id", "member_id"),
        Index("ix_digital_memberships_tenant_deleted", "tenant_id", "is_deleted"),
    )


class Waiver(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Liability / consent waiver record — document file ref only."""

    __tablename__ = "waivers"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    member_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    membership_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
    title: Mapped[str] = mapped_column(String(255), nullable=False)
    waiver_version: Mapped[str] = mapped_column(String(32), nullable=False, default="1")
    status: Mapped[WaiverStatus] = mapped_column(default=WaiverStatus.PENDING, nullable=False)
    signed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    expires_on: Mapped[date | None] = mapped_column(Date, nullable=True)
    document_file_ref: Mapped[str | None] = mapped_column(String(255), nullable=True)
    signature_ref: Mapped[str | None] = mapped_column(String(255), nullable=True)
    notes: Mapped[str | None] = mapped_column(Text, nullable=True)

    __table_args__ = (
        Index("ix_waivers_member", "tenant_id", "member_id"),
        Index("ix_waivers_tenant_status", "tenant_id", "status"),
        Index("ix_waivers_tenant_deleted", "tenant_id", "is_deleted"),
    )


class MemberDocument(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
):
    """Member attachment metadata — Storage owns binary content."""

    __tablename__ = "member_documents"

    sports_center_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    member_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    title: Mapped[str] = mapped_column(String(255), nullable=False)
    kind: Mapped[DocumentKind] = mapped_column(default=DocumentKind.OTHER, nullable=False)
    file_ref: Mapped[str] = mapped_column(String(255), nullable=False)
    mime_type: Mapped[str | None] = mapped_column(String(128), nullable=True)
    size_bytes: Mapped[int | None] = mapped_column(Integer, nullable=True)
    notes: Mapped[str | None] = mapped_column(Text, nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        Index("ix_member_documents_member", "tenant_id", "member_id"),
        Index("ix_member_documents_tenant_deleted", "tenant_id", "is_deleted"),
    )
