from __future__ import annotations

from datetime import datetime, timezone

from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, String, Text, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column, relationship

from .database import Base


def utcnow() -> datetime:
    return datetime.now(timezone.utc)


class UserSession(Base):
    __tablename__ = "user_sessions"

    id: Mapped[int] = mapped_column(primary_key=True)
    session_token: Mapped[str] = mapped_column(String(128), unique=True, index=True)
    provider: Mapped[str] = mapped_column(String(32), default="teamsnap")
    external_user_id: Mapped[str | None] = mapped_column(String(128), index=True)
    external_team_id: Mapped[str | None] = mapped_column(String(128), index=True)
    external_player_id: Mapped[str | None] = mapped_column(String(128), index=True)
    access_token: Mapped[str | None] = mapped_column(Text())
    refresh_token: Mapped[str | None] = mapped_column(Text())
    token_expires_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
    is_admin: Mapped[bool] = mapped_column(Boolean, default=False)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
    updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow, onupdate=utcnow)


class AudioAsset(Base):
    __tablename__ = "audio_assets"

    id: Mapped[int] = mapped_column(primary_key=True)
    external_team_id: Mapped[str] = mapped_column(String(128), index=True)
    owner_external_player_id: Mapped[str] = mapped_column(String(128), index=True)
    uploaded_by_session_id: Mapped[int | None] = mapped_column(ForeignKey("user_sessions.id"))
    title: Mapped[str] = mapped_column(String(255))
    original_filename: Mapped[str] = mapped_column(String(255))
    mime_type: Mapped[str] = mapped_column(String(128))
    size_bytes: Mapped[int] = mapped_column(Integer)
    storage_path: Mapped[str] = mapped_column(String(512))
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)

    uploaded_by: Mapped[UserSession | None] = relationship()
    clips: Mapped[list[AudioClip]] = relationship(back_populates="asset", cascade="all, delete-orphan")


class AudioClip(Base):
    __tablename__ = "audio_clips"

    id: Mapped[int] = mapped_column(primary_key=True)
    asset_id: Mapped[int] = mapped_column(ForeignKey("audio_assets.id"), index=True)
    label: Mapped[str] = mapped_column(String(255))
    start_ms: Mapped[int] = mapped_column(Integer)
    end_ms: Mapped[int] = mapped_column(Integer)
    sort_order: Mapped[int] = mapped_column(Integer, default=0, index=True)
    hidden: Mapped[bool] = mapped_column(Boolean, default=False, index=True)
    normalization_status: Mapped[str] = mapped_column(String(32), default="pending")
    normalized_path: Mapped[str | None] = mapped_column(String(512))
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)

    asset: Mapped[AudioAsset] = relationship(back_populates="clips")


class GameAssignment(Base):
    __tablename__ = "game_assignments"
    __table_args__ = (
        UniqueConstraint("external_game_id", "clip_id", name="uq_game_assignment_game_clip"),
    )

    id: Mapped[int] = mapped_column(primary_key=True)
    external_team_id: Mapped[str] = mapped_column(String(128), index=True)
    external_game_id: Mapped[str] = mapped_column(String(128), index=True)
    external_player_id: Mapped[str] = mapped_column(String(128), index=True)
    clip_id: Mapped[int] = mapped_column(ForeignKey("audio_clips.id"), index=True)
    batting_slot: Mapped[int | None] = mapped_column(Integer)
    status: Mapped[str] = mapped_column(String(32), default="ready")
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
    updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow, onupdate=utcnow)

    clip: Mapped[AudioClip] = relationship()
