from typing import List
from sqlalchemy import ForeignKey, UniqueConstraint
from sqlalchemy.orm import relationship, mapped_column, Mapped

from src.db.models.base import Base, BaseMixin


class Sport(Base, BaseMixin):
    __tablename__ = "sport"
    __table_args__ = (
        UniqueConstraint("name"),
    )
    name: Mapped[str] = mapped_column(nullable=False, index=True, unique=True)
    teams: Mapped[List["Team"]] = relationship(back_populates="sport")
    positions: Mapped[List["FieldPosition"]] = relationship(back_populates="sport")


class Team(Base, BaseMixin):
    __tablename__ = "team"
    name: Mapped[str] = mapped_column(nullable=False, index=True, unique=True)
    short_name: Mapped[str] = mapped_column(nullable=False)
    sport_id: Mapped[str] = mapped_column(ForeignKey("sport.id"), nullable=False)
    sport: Mapped[Sport] = relationship(back_populates="teams")
    roosters: Mapped[List["Rooster"]] = relationship(back_populates="team")


class FieldPosition(Base, BaseMixin):
    __tablename__ = "field_position"
    __table_args__ = (
        UniqueConstraint("name", "sport_id"),
        UniqueConstraint("short_name", "sport_id"),
    )
    name: Mapped[str] = mapped_column(nullable=False, index=True)
    short_name: Mapped[str] = mapped_column(nullable=False)
    sport_id: Mapped[str] = mapped_column(ForeignKey("sport.id"), nullable=False, index=True)
    sport: Mapped[Sport] = relationship(back_populates="positions")
    roosters: Mapped[List["Rooster"]] = relationship(back_populates="position")


class Player(Base, BaseMixin):
    __tablename__ = "player"
    __table_args__ = (
        UniqueConstraint("first_name", "last_name"),
    )
    first_name: Mapped[str] = mapped_column(nullable=False, index=True)
    last_name: Mapped[str] = mapped_column(nullable=False, index=True)
    roosters: Mapped[List["Rooster"]] = relationship(back_populates="player")

    def get_full_name(self) -> str:
        return f"{self.last_name}, {self.first_name}"


class Rooster(Base, BaseMixin):
    __tablename__ = "rooster"
    __table_args__ = (
        UniqueConstraint("year", "team_id", "player_id", "position_id"),
    )
    year: Mapped[int]
    team_id: Mapped[str] = mapped_column(ForeignKey("team.id"), nullable=False, index=True)
    team: Mapped[Team] = relationship(back_populates="roosters")
    player_id: Mapped[str] = mapped_column(ForeignKey("player.id"), nullable=False, index=True)
    player: Mapped[Player] = relationship(back_populates="roosters")
    position_id: Mapped[str] = mapped_column(ForeignKey("field_position.id"), nullable=False, index=True)
    position: Mapped[FieldPosition] = relationship(back_populates="roosters")
    cards: Mapped[List["Card"]] = relationship(back_populates="rooster")


class Vendor(Base, BaseMixin):
    __tablename__ = "vendor"
    name: Mapped[str] = mapped_column(nullable=False, unique=True, index=True)
    card_sets: Mapped[List["CardSet"]] = relationship(back_populates="vendor")
    cards: Mapped[List["Card"]] = relationship(back_populates="vendor")


class CardSet(Base, BaseMixin):
    __tablename__ = "card_set"
    __table_args__ = (
        UniqueConstraint("name", "vendor_id"),
    )
    name: Mapped[str] = mapped_column(index=True)
    parallel_set: Mapped[bool]
    insert_set: Mapped[bool]
    vendor_id: Mapped[str] = mapped_column(ForeignKey("vendor.id"), nullable=False, index=True)
    vendor: Mapped[Vendor] = relationship(back_populates="card_sets")
    cards: Mapped[List["Card"]] = relationship(back_populates="card_set")


class Card(Base, BaseMixin):
    __tablename__ = "card"
    __table_args__ = (
        UniqueConstraint("card_number", "year", "vendor_id", "card_set_id"),
    )
    card_number: Mapped[int] = mapped_column(index=True)
    year: Mapped[int] = mapped_column(index=True)
    card_set_id: Mapped[str] = mapped_column(ForeignKey("card_set.id"), nullable=False)
    card_set: Mapped[CardSet] = relationship(back_populates="cards")
    rooster_id: Mapped[str] = mapped_column(ForeignKey("rooster.id"), nullable=False)
    rooster: Mapped[Rooster] = relationship(back_populates="cards")
    vendor_id: Mapped[str] = mapped_column(ForeignKey("vendor.id"), nullable=False)
    vendor: Mapped[Vendor] = relationship(back_populates="cards")
