"""Matches, sides, and the team tree.

A match has two sides; each side is a tree of team_nodes; a node has a
boundary player (its lead, who represents it upward). This is the raw
structure the perspective engine (rep/courts_of/visible_players, §4.2)
projects at read time. Kept append-friendly: restructuring re-renders history.
"""
import datetime

from sqlalchemy import ForeignKey, Integer, String, UniqueConstraint, text
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column

from .base import Base, created_at, uuid_pk


class Match(Base):
    __tablename__ = "matches"

    id: Mapped[str] = uuid_pk()
    slug: Mapped[str] = mapped_column(String, unique=True, nullable=False)
    name: Mapped[str] = mapped_column(String, nullable=False)
    created_at: Mapped[datetime.datetime] = created_at()


class Side(Base):
    __tablename__ = "sides"

    id: Mapped[str] = uuid_pk()
    match_id: Mapped[str] = mapped_column(
        UUID(as_uuid=True), ForeignKey("matches.id", ondelete="CASCADE"), nullable=False
    )
    name: Mapped[str] = mapped_column(String, nullable=False)
    position: Mapped[int] = mapped_column(
        Integer, nullable=False, default=0, server_default=text("0")
    )


class TeamNode(Base):
    __tablename__ = "team_nodes"

    id: Mapped[str] = uuid_pk()
    side_id: Mapped[str] = mapped_column(
        UUID(as_uuid=True), ForeignKey("sides.id", ondelete="CASCADE"), nullable=False
    )
    # Null parent = a front-line (root) node.
    parent_node_id: Mapped[str | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("team_nodes.id", ondelete="CASCADE")
    )
    name: Mapped[str] = mapped_column(String, nullable=False)
    # The node's lead; the person it collapses into when viewed from outside.
    boundary_player_id: Mapped[str | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("players.id", ondelete="SET NULL")
    )


class TeamMember(Base):
    __tablename__ = "team_members"
    __table_args__ = (UniqueConstraint("match_id", "player_id", name="uq_member_per_match"),)

    id: Mapped[str] = uuid_pk()
    # match_id denormalized so "one node per player per match" is enforceable.
    match_id: Mapped[str] = mapped_column(
        UUID(as_uuid=True), ForeignKey("matches.id", ondelete="CASCADE"), nullable=False
    )
    node_id: Mapped[str] = mapped_column(
        UUID(as_uuid=True), ForeignKey("team_nodes.id", ondelete="CASCADE"), nullable=False
    )
    player_id: Mapped[str] = mapped_column(
        UUID(as_uuid=True), ForeignKey("players.id", ondelete="CASCADE"), nullable=False
    )
