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


class UserRole(str, enum.Enum):
    student = "student"
    parent = "parent"
    teacher = "teacher"
    school = "school"
    organization = "organization"
    admin = "admin"
    super_admin = "super_admin"


class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True, index=True)
    stem_id = Column(String(20), unique=True, nullable=False, index=True)
    email = Column(String(255), unique=True, nullable=True, index=True)
    phone = Column(String(20), nullable=True)
    username = Column(String(100), unique=True, nullable=True)
    password_hash = Column(String(255), nullable=False)
    first_name = Column(String(100), nullable=False)
    last_name = Column(String(100), nullable=False)
    role = Column(Enum(UserRole), nullable=False)
    profile_image_url = Column(Text, nullable=True)
    date_of_birth = Column(Date, nullable=True)
    gender = Column(Enum("male", "female", "other", "prefer_not_to_say"), nullable=True)
    address = Column(Text, nullable=True)
    is_active = Column(Boolean, default=True)
    is_email_verified = Column(Boolean, default=False)
    is_phone_verified = Column(Boolean, default=False)
    last_login_at = Column(DateTime, nullable=True)
    failed_login_attempts = Column(Integer, default=0)
    locked_until = Column(DateTime, nullable=True)
    created_at = Column(DateTime, server_default=func.now())
    updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())

    # Relationships
    tokens = relationship("UserToken", back_populates="user", cascade="all, delete-orphan")
    student_profile = relationship("StudentProfile", back_populates="user", uselist=False)
    parent_profile = relationship("ParentProfile", back_populates="user", uselist=False)
    teacher_profile = relationship("TeacherProfile", back_populates="user", uselist=False)
    school = relationship("School", back_populates="user", uselist=False, foreign_keys="[School.user_id]")
    organization = relationship("Organization", back_populates="user", uselist=False, foreign_keys="[Organization.user_id]")
    notifications = relationship("Notification", back_populates="user", cascade="all, delete-orphan")
    subscriptions = relationship("Subscription", back_populates="user")
    payments = relationship("Payment", back_populates="user")
    game_sessions_hosted = relationship("GameSession", back_populates="host_user", foreign_keys="GameSession.host_user_id")

    @property
    def full_name(self) -> str:
        return f"{self.first_name} {self.last_name}"


class UserToken(Base):
    __tablename__ = "user_tokens"

    id = Column(Integer, primary_key=True, index=True)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
    token_type = Column(Enum("refresh", "email_verify", "password_reset", "api_key"), nullable=False)
    token_hash = Column(String(255), nullable=False)
    expires_at = Column(DateTime, nullable=False)
    is_used = Column(Boolean, default=False)
    created_at = Column(DateTime, server_default=func.now())

    user = relationship("User", back_populates="tokens")


class StudentProfile(Base):
    __tablename__ = "student_profiles"

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), unique=True, nullable=False)
    current_grade_id = Column(Integer, nullable=True)
    current_school_id = Column(Integer, nullable=True)
    bio = Column(Text, nullable=True)
    learning_style = Column(Enum("visual", "auditory", "kinesthetic"), default="visual")
    preferred_game_type_id = Column(Integer, nullable=True)
    total_xp = Column(Integer, default=0)
    level_rank = Column(Integer, default=1)
    streak_days = Column(Integer, default=0)
    last_activity_at = Column(DateTime, nullable=True)
    created_at = Column(DateTime, server_default=func.now())
    updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())

    user = relationship("User", back_populates="student_profile")
    progress = relationship("PlayerProgress", primaryjoin="StudentProfile.user_id == foreign(PlayerProgress.student_user_id)", viewonly=True)
    awards = relationship("PlayerAward", primaryjoin="StudentProfile.user_id == foreign(PlayerAward.student_user_id)", viewonly=True)
    parent_links = relationship("ParentStudentLink", primaryjoin="StudentProfile.user_id == foreign(ParentStudentLink.student_user_id)", viewonly=True)
    school_enrollments = relationship("SchoolStudentEnrollment", primaryjoin="StudentProfile.user_id == foreign(SchoolStudentEnrollment.student_user_id)", viewonly=True)
    academic_summaries = relationship("AcademicProgressSummary", primaryjoin="StudentProfile.user_id == foreign(AcademicProgressSummary.student_user_id)", viewonly=True)


class ParentProfile(Base):
    __tablename__ = "parent_profiles"

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), unique=True, nullable=False)
    occupation = Column(String(100), nullable=True)
    created_at = Column(DateTime, server_default=func.now())

    user = relationship("User", back_populates="parent_profile")
    student_links = relationship("ParentStudentLink", primaryjoin="ParentProfile.user_id == foreign(ParentStudentLink.parent_user_id)", viewonly=True)


class ParentStudentLink(Base):
    __tablename__ = "parent_student_links"

    id = Column(Integer, primary_key=True)
    parent_user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
    student_user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
    relationship_type = Column(Enum("mother", "father", "guardian", "sibling", "other"), default="guardian")
    is_primary = Column(Boolean, default=False)
    created_at = Column(DateTime, server_default=func.now())

    parent_profile = relationship("ParentProfile", primaryjoin="foreign(ParentStudentLink.parent_user_id) == ParentProfile.user_id", viewonly=True)
    student_profile = relationship("StudentProfile", primaryjoin="foreign(ParentStudentLink.student_user_id) == StudentProfile.user_id", viewonly=True)


class TeacherProfile(Base):
    __tablename__ = "teacher_profiles"

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), unique=True, nullable=False)
    teacher_code = Column(String(30), unique=True, nullable=False)
    specialization = Column(Text, nullable=True)
    qualifications = Column(Text, nullable=True)
    experience_years = Column(Integer, default=0)
    is_content_approved = Column(Boolean, default=False)
    created_at = Column(DateTime, server_default=func.now())
    updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())

    user = relationship("User", back_populates="teacher_profile")
    question_submissions = relationship("TeacherQuestionSubmission", primaryjoin="TeacherProfile.user_id == foreign(TeacherQuestionSubmission.teacher_user_id)", viewonly=True)
    school_assignments = relationship("SchoolTeacherAssignment", primaryjoin="TeacherProfile.user_id == foreign(SchoolTeacherAssignment.teacher_user_id)", viewonly=True)


class Notification(Base):
    __tablename__ = "notifications"

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
    title = Column(String(255), nullable=False)
    message = Column(Text, nullable=False)
    type = Column(Enum("info", "success", "warning", "error", "achievement", "subscription", "system"), default="info")
    is_read = Column(Boolean, default=False)
    action_url = Column(String(500), nullable=True)
    created_at = Column(DateTime, server_default=func.now())

    user = relationship("User", back_populates="notifications")
