# backend/app/models.py
from datetime import datetime
from typing import Optional

from sqlalchemy import JSON, DateTime, Table, Column
from sqlalchemy import Enum as SqlEnum
from sqlalchemy import ForeignKey, Integer, String
from sqlalchemy.orm import Mapped, mapped_column, relationship

from .constants import MatchStatus, TournamentTypes, BracketTypes
from .database import Base

tournament_courts = Table(
    "tournament_courts",
    Base.metadata,
    Column(
        "tournament_id",
        String(8),
        ForeignKey("tournaments.id", ondelete="CASCADE"),
        primary_key=True,
    ),
    Column(
        "court_id",
        Integer,
        ForeignKey("courts.id", ondelete="CASCADE"),
        primary_key=True,
    ),
)


class Court(Base):
    __tablename__ = "courts"
    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    name: Mapped[str] = mapped_column(String, nullable=False, unique=True)

    tournaments: Mapped[list["Tournament"]] = relationship(
        "Tournament", secondary=tournament_courts, back_populates="courts"
    )


class Tournament(Base):
    __tablename__ = "tournaments"

    id: Mapped[str] = mapped_column(String(8), primary_key=True, index=True)
    name: Mapped[str] = mapped_column(String, nullable=False)
    code: Mapped[str] = mapped_column(String, nullable=True)
    timestamp: Mapped[datetime] = mapped_column(DateTime, nullable=False)
    duration: Mapped[int] = mapped_column(Integer, default=30)
    type: Mapped[TournamentTypes] = mapped_column(SqlEnum(TournamentTypes))

    teams: Mapped[list["Team"]] = relationship(
        "Team", back_populates="tournament", cascade="all, delete-orphan"
    )
    courts: Mapped[list["Court"]] = relationship(
        "Court", secondary=tournament_courts, back_populates="tournaments"
    )

    matches: Mapped[list["Match"]] = relationship(
        "Match", back_populates="tournament", cascade="all, delete-orphan"
    )

    @property
    def team_count(self) -> int:
        return len(self.teams)

    @property
    def court_count(self) -> int:
        return len(self.courts)


class Team(Base):
    __tablename__ = "teams"
    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    name: Mapped[str] = mapped_column(String, nullable=False)
    tournament_id: Mapped[str] = mapped_column(ForeignKey("tournaments.id"))

    tournament: Mapped["Tournament"] = relationship(back_populates="teams")


class Match(Base):
    __tablename__ = "matches"

    id: Mapped[str] = mapped_column(String, primary_key=True)
    tournament_id: Mapped[str] = mapped_column(ForeignKey("tournaments.id"))

    match_number: Mapped[int] = mapped_column(Integer)
    round_number: Mapped[int] = mapped_column(Integer, default=1)

    bracket_type: Mapped[BracketTypes] = mapped_column(SqlEnum(BracketTypes))

    court_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("courts.id"), nullable=True
    )
    start_time: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)

    status: Mapped[MatchStatus] = mapped_column(
        SqlEnum(MatchStatus), default=MatchStatus.SCHEDULED
    )

    p1_team_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("teams.id"), nullable=True
    )
    p2_team_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("teams.id"), nullable=True
    )

    ref_team_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("teams.id"), nullable=True
    )
    ref_label: Mapped[Optional[str]] = mapped_column(String, nullable=True)

    sets: Mapped[list[dict]] = mapped_column(JSON, default=list)
    winner_team_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("teams.id"), nullable=True
    )

    winner_next_match_id: Mapped[Optional[str]] = mapped_column(
        ForeignKey("matches.id"), nullable=True
    )
    winner_next_match_slot: Mapped[Optional[int]] = mapped_column(
        Integer, nullable=True
    )

    loser_next_match_id: Mapped[Optional[str]] = mapped_column(
        ForeignKey("matches.id"), nullable=True
    )
    loser_next_match_slot: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)

    tournament: Mapped["Tournament"] = relationship(back_populates="matches")
    court: Mapped[Optional["Court"]] = relationship()
    p1_team: Mapped["Team"] = relationship("Team", foreign_keys=[p1_team_id])
    p2_team: Mapped["Team"] = relationship("Team", foreign_keys=[p2_team_id])

    ref_team: Mapped[Optional["Team"]] = relationship(
        "Team", foreign_keys=[ref_team_id]
    )

    winner_next_match: Mapped["Match"] = relationship(
        "Match", remote_side=[id], foreign_keys=[winner_next_match_id]
    )
    loser_next_match: Mapped["Match"] = relationship(
        "Match", remote_side=[id], foreign_keys=[loser_next_match_id]
    )
