import uuid
from datetime import datetime, timezone
from typing import Optional, TYPE_CHECKING
from sqlalchemy import String, DateTime, ForeignKey, Boolean, Integer, CheckConstraint
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.dialects.postgresql import UUID
from app.core.database import Base

if TYPE_CHECKING:
    from app.models.session import Session
    from app.models.user import User
    from app.models.account import Account


class SessionShare(Base):
    __tablename__ = "session_shares"
    __table_args__ = (
        CheckConstraint(
            "visibility IN ('public', 'account')",
            name='ck_session_shares_visibility'
        ),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        primary_key=True,
        default=uuid.uuid4
    )
    session_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("sessions.id", ondelete="CASCADE"),
        nullable=False,
        index=True
    )
    account_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("accounts.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
        comment="Account that owns this share (denormalized from session at creation)"
    )
    share_token: Mapped[str] = mapped_column(
        String(64),
        unique=True,
        nullable=False,
        index=True,
        comment="URL-safe random token (48 bytes -> 64 base64 chars)"
    )
    share_name: Mapped[Optional[str]] = mapped_column(
        String(100),
        nullable=True,
        comment="Optional label: 'Training link', 'Customer escalation #1234'"
    )
    visibility: Mapped[str] = mapped_column(
        String(20),
        nullable=False,
        default="public",
        comment="public = anyone with link, account = account members only"
    )
    created_by: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False,
        index=True
    )
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=lambda: datetime.now(timezone.utc)
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=lambda: datetime.now(timezone.utc),
        onupdate=lambda: datetime.now(timezone.utc)
    )
    expires_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True),
        nullable=True,
        index=True,
        comment="Optional expiration for time-limited shares"
    )
    view_count: Mapped[int] = mapped_column(
        Integer,
        nullable=False,
        default=0
    )
    last_viewed_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True),
        nullable=True
    )
    is_active: Mapped[bool] = mapped_column(
        Boolean,
        nullable=False,
        default=True,
        index=True
    )

    # Relationships
    session: Mapped["Session"] = relationship("Session", back_populates="shares")
    account: Mapped["Account"] = relationship("Account")
    creator: Mapped["User"] = relationship("User", foreign_keys=[created_by])
    views: Mapped[list["SessionShareView"]] = relationship(
        "SessionShareView",
        back_populates="share",
        cascade="all, delete-orphan"
    )


class SessionShareView(Base):
    __tablename__ = "session_share_views"

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        primary_key=True,
        default=uuid.uuid4
    )
    share_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("session_shares.id", ondelete="CASCADE"),
        nullable=False,
        index=True
    )
    session_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("sessions.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
        comment="Denormalized from share for analytics queries"
    )
    viewer_id: Mapped[Optional[uuid.UUID]] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("users.id", ondelete="SET NULL"),
        nullable=True,
        index=True,
        comment="NULL for public shares (unauthenticated views)"
    )
    viewed_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=lambda: datetime.now(timezone.utc),
        index=True
    )
    viewer_ip: Mapped[Optional[str]] = mapped_column(
        String(45),  # IPv6 max length
        nullable=True
    )
    viewer_user_agent: Mapped[Optional[str]] = mapped_column(
        String(500),
        nullable=True
    )

    # Relationships
    share: Mapped["SessionShare"] = relationship("SessionShare", back_populates="views")
    viewer: Mapped[Optional["User"]] = relationship("User")
