from sqlalchemy import (
    Column, Integer, String, Boolean, DateTime, Enum, Text, JSON,
    ForeignKey, DECIMAL, func, UniqueConstraint
)
from sqlalchemy.orm import relationship
from app.core.database import Base


class GameType(Base):
    __tablename__ = "game_types"

    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False, unique=True)
    slug = Column(String(100), unique=True, nullable=False)
    description = Column(Text, nullable=True)
    icon_url = Column(String(500), nullable=True)
    is_active = Column(Boolean, default=True)
    created_at = Column(DateTime, server_default=func.now())
    updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())

    assets = relationship("GameAsset", back_populates="game_type")
    games = relationship("Game", back_populates="game_type")
    sessions = relationship("GameSession", back_populates="game_type")


class GameAsset(Base):
    __tablename__ = "game_assets"

    id = Column(Integer, primary_key=True)
    game_type_id = Column(Integer, ForeignKey("game_types.id"), nullable=False)
    name = Column(String(255), nullable=False)
    slug = Column(String(255), nullable=False)
    svg_url = Column(Text, nullable=True)
    image_url = Column(Text, nullable=True)
    rive_url = Column(Text, nullable=True)
    sound_url = Column(Text, nullable=True)
    model_3d_url = Column(Text, nullable=True)
    asset_type = Column(
        Enum("image", "svg", "rive", "audio", "model", "animation", "video"),
        default="image"
    )
    asset_group = Column(Enum("target", "action", "decoration", "ui"), default="action")
    monetary_value = Column(DECIMAL(15, 2), default=0.00)
    quantity_default = Column(Integer, default=1)
    asset_metadata = Column(JSON, nullable=True)
    file_size_bytes = Column(Integer, nullable=True)
    is_offline_available = Column(Boolean, default=False)
    offline_path = Column(String(500), nullable=True)
    is_active = Column(Boolean, default=True)
    created_at = Column(DateTime, server_default=func.now())
    updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())

    game_type = relationship("GameType", back_populates="assets")


class GameCategory(Base):
    """A broad grouping for games, e.g. Home, School, Community, Science."""
    __tablename__ = "game_categories"

    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False, unique=True)
    slug = Column(String(100), unique=True, nullable=False)
    description = Column(Text, nullable=True)
    icon = Column(String(10), nullable=True)          # emoji, e.g. "\U0001f3e0"
    color_hex = Column(String(7), default="#4F46E5")
    thumbnail_url = Column(String(500), nullable=True)   # optional banner/thumbnail image
    is_active = Column(Boolean, default=True)
    created_at = Column(DateTime, server_default=func.now())
    updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())

    games = relationship("Game", back_populates="category")


class Game(Base):
    __tablename__ = "games"

    id = Column(Integer, primary_key=True)
    name = Column(String(255), nullable=False)
    slug = Column(String(255), unique=True, nullable=False)
    description = Column(Text, nullable=True)
    instructions = Column(Text, nullable=True)
    intro_video_url = Column(Text, nullable=True)
    artwork_url = Column(Text, nullable=True)
    game_type_id = Column(Integer, ForeignKey("game_types.id"), nullable=False)
    category_id = Column(Integer, ForeignKey("game_categories.id", ondelete="SET NULL"), nullable=True)
    subject_grade_id = Column(Integer, ForeignKey("subject_grades.id"), nullable=True)
    is_active = Column(Boolean, default=True)
    created_at = Column(DateTime, server_default=func.now())
    updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())

    game_type = relationship("GameType", back_populates="games")
    category = relationship("GameCategory", back_populates="games")
    subject_grade = relationship("SubjectGrade", back_populates="games")
    topics = relationship("GameTopic", back_populates="game", cascade="all, delete-orphan", order_by="GameTopic.sequence_order")
    levels = relationship("GameLevel", back_populates="game", cascade="all, delete-orphan")


class GameTopic(Base):
    """
    A game-specific topic / location node (e.g. 'Market', 'Home', 'School Canteen').
    Groups related levels within a single game — analogous to the community-map
    nodes shown in the GeniusMath world view.
    """
    __tablename__ = "game_topics"

    id = Column(Integer, primary_key=True)
    game_id = Column(Integer, ForeignKey("games.id", ondelete="CASCADE"), nullable=False)
    subject_id = Column(Integer, ForeignKey("subjects.id", ondelete="SET NULL"), nullable=True)
    name = Column(String(255), nullable=False)           # e.g. "Buying Snacks"
    slug = Column(String(255), nullable=False)
    description = Column(Text, nullable=True)
    location_name = Column(String(100), nullable=True)   # e.g. "Market", "Home"
    icon_url = Column(String(500), nullable=True)
    background_url = Column(String(500), nullable=True)
    color_hex = Column(String(7), default="#4F46E5")
    sequence_order = Column(Integer, default=1)
    is_active = Column(Boolean, default=True)
    created_at = Column(DateTime, server_default=func.now())
    updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())

    __table_args__ = (UniqueConstraint("game_id", "slug", name="uk_game_topic_slug"),)

    game = relationship("Game", back_populates="topics")
    subject = relationship("Subject", foreign_keys=[subject_id])
    levels = relationship("GameLevel", back_populates="game_topic", order_by="GameLevel.sequence_order")


class GameLevel(Base):
    __tablename__ = "game_levels"

    id = Column(Integer, primary_key=True)
    game_id = Column(Integer, ForeignKey("games.id", ondelete="CASCADE"), nullable=False)
    game_topic_id = Column(Integer, ForeignKey("game_topics.id", ondelete="SET NULL"), nullable=True)
    topic_level_id = Column(Integer, ForeignKey("topic_levels.id"), nullable=True)
    title = Column(String(255), nullable=False)
    instructions = Column(Text, nullable=True)
    description = Column(Text, nullable=True)
    tag = Column(String(50), nullable=True)
    sequence_order = Column(Integer, default=1)
    is_active = Column(Boolean, default=True)
    created_at = Column(DateTime, server_default=func.now())
    updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())

    game = relationship("Game", back_populates="levels")
    game_topic = relationship("GameTopic", back_populates="levels")
    topic_level = relationship("TopicLevel", back_populates="game_levels")
    sessions = relationship("GameSession", back_populates="game_level")


class GameSession(Base):
    __tablename__ = "game_sessions"

    id = Column(Integer, primary_key=True)
    session_code = Column(String(20), unique=True, nullable=False)
    play_mode = Column(
        Enum("single_player", "pvp", "multiplayer", "team_vs_team"), nullable=False
    )
    game_level_id = Column(Integer, ForeignKey("game_levels.id"), nullable=False)
    game_type_id = Column(Integer, ForeignKey("game_types.id"), nullable=False)
    host_user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
    status = Column(
        Enum("waiting", "in_progress", "completed", "abandoned"), default="waiting"
    )
    max_players = Column(Integer, default=1)
    settings = Column(JSON, nullable=True)
    started_at = Column(DateTime, nullable=True)
    ended_at = Column(DateTime, nullable=True)
    is_offline = Column(Boolean, default=False)
    created_at = Column(DateTime, server_default=func.now())

    game_level = relationship("GameLevel", back_populates="sessions")
    game_type = relationship("GameType", back_populates="sessions")
    host_user = relationship("User", back_populates="game_sessions_hosted", foreign_keys=[host_user_id])
    teams = relationship("SessionTeam", back_populates="session", cascade="all, delete-orphan")
    players = relationship("SessionPlayer", back_populates="session", cascade="all, delete-orphan")
    responses = relationship("PlayerResponse", back_populates="session", cascade="all, delete-orphan")
    awards_given = relationship("PlayerAward", back_populates="session")


class SessionTeam(Base):
    __tablename__ = "session_teams"

    id = Column(Integer, primary_key=True)
    session_id = Column(Integer, ForeignKey("game_sessions.id", ondelete="CASCADE"), nullable=False)
    team_name = Column(String(100), nullable=False)
    team_color = Column(String(7), default="#4F46E5")
    total_score = Column(Integer, default=0)
    is_winner = Column(Boolean, default=False)

    session = relationship("GameSession", back_populates="teams")
    players = relationship("SessionPlayer", back_populates="team")


class SessionPlayer(Base):
    __tablename__ = "session_players"

    id = Column(Integer, primary_key=True)
    session_id = Column(Integer, ForeignKey("game_sessions.id", ondelete="CASCADE"), nullable=False)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
    team_id = Column(Integer, ForeignKey("session_teams.id"), nullable=True)
    score = Column(Integer, default=0)
    stars_earned = Column(Integer, default=0)
    xp_earned = Column(Integer, default=0)
    completion_time_seconds = Column(Integer, nullable=True)
    is_winner = Column(Boolean, default=False)
    answers_correct = Column(Integer, default=0)
    answers_total = Column(Integer, default=0)
    joined_at = Column(DateTime, server_default=func.now())
    completed_at = Column(DateTime, nullable=True)

    session = relationship("GameSession", back_populates="players")
    team = relationship("SessionTeam", back_populates="players")


class PlayerResponse(Base):
    __tablename__ = "player_responses"

    id = Column(Integer, primary_key=True)
    session_id = Column(Integer, ForeignKey("game_sessions.id", ondelete="CASCADE"), nullable=False)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
    question_id = Column(Integer, ForeignKey("questions.id"), nullable=False)
    selected_answer_id = Column(Integer, ForeignKey("answer_options.id"), nullable=True)
    is_correct = Column(Boolean, default=False)
    time_taken_seconds = Column(Integer, nullable=True)
    points_earned = Column(Integer, default=0)
    created_at = Column(DateTime, server_default=func.now())

    session = relationship("GameSession", back_populates="responses")
    question = relationship("Question", back_populates="responses")
    selected_answer = relationship("AnswerOption")
