"""Academic models for programmes, courses, enrollments, attendance, and assessments."""

from datetime import datetime
from enum import Enum as PyEnum
from uuid import uuid4

from sqlalchemy import (
    Boolean, Column, Date, DateTime, Enum, ForeignKey, Integer, Numeric, String, Text
)
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship

from app.database import Base


class Programme(Base):
    """Academic programme (e.g., Computer Science, Business Administration)."""
    __tablename__ = "programmes"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4, index=True)
    code = Column(String(20), unique=True, nullable=False, index=True)  # e.g., "CS", "BA"
    name = Column(String(255), nullable=False)
    department = Column(String(255), nullable=False, index=True)
    faculty = Column(String(255), nullable=True, index=True)
    duration_years = Column(Integer, default=4, nullable=False)
    is_active = Column(Boolean, default=True, nullable=False)
    
    created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
    
    # Relationships
    courses = relationship("Course", back_populates="programme", cascade="all, delete-orphan")
    enrollments = relationship("Enrollment", back_populates="programme")

    def __repr__(self):
        return f"<Programme {self.code}: {self.name}>"


class Course(Base):
    """Course within a programme."""
    __tablename__ = "courses"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4, index=True)
    programme_id = Column(UUID(as_uuid=True), ForeignKey("programmes.id"), nullable=False, index=True)
    code = Column(String(20), nullable=False, index=True)  # e.g., "CS101"
    title = Column(String(255), nullable=False)
    description = Column(Text, nullable=True)
    level = Column(Integer, nullable=False)  # 100, 200, 300, 400
    semester = Column(Integer, nullable=False)  # 1 or 2
    credit_units = Column(Integer, default=3, nullable=False)
    is_elective = Column(Boolean, default=False, nullable=False)
    is_active = Column(Boolean, default=True, nullable=False)
    
    created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
    
    # Relationships
    programme = relationship("Programme", back_populates="courses")
    enrollments = relationship("Enrollment", back_populates="course")
    attendance_sessions = relationship("AttendanceSession", back_populates="course")
    assessments = relationship("Assessment", back_populates="course")

    def __repr__(self):
        return f"<Course {self.code}: {self.title}>"


class EnrollmentStatus(str, PyEnum):
    """Enrollment status."""
    ACTIVE = "active"
    COMPLETED = "completed"
    DROPPED = "dropped"
    FAILED = "failed"


class Enrollment(Base):
    """Student enrollment in a course."""
    __tablename__ = "enrollments"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4, index=True)
    student_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False, index=True)
    programme_id = Column(UUID(as_uuid=True), ForeignKey("programmes.id"), nullable=False, index=True)
    course_id = Column(UUID(as_uuid=True), ForeignKey("courses.id"), nullable=False, index=True)
    academic_session_id = Column(UUID(as_uuid=True), ForeignKey("academic_sessions.id"), nullable=True, index=True)
    
    status = Column(Enum(EnrollmentStatus), default=EnrollmentStatus.ACTIVE, nullable=False, index=True)
    enrollment_date = Column(DateTime, default=datetime.utcnow, nullable=False)
    
    # Grade information
    ca_score = Column(Numeric(5, 2), nullable=True)  # Continuous Assessment (0-30)
    exam_score = Column(Numeric(5, 2), nullable=True)  # Final Exam (0-70)
    total_score = Column(Numeric(5, 2), nullable=True)  # Total (0-100)
    grade = Column(String(2), nullable=True)  # A, B, C, D, F
    grade_point = Column(Numeric(3, 2), nullable=True)  # 5.0, 4.0, etc.
    
    created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
    
    # Relationships
    student = relationship("User", foreign_keys=[student_id])
    programme = relationship("Programme", back_populates="enrollments")
    course = relationship("Course", back_populates="enrollments")
    academic_session = relationship("AcademicSession", back_populates="enrollments")
    attendance_records = relationship("AttendanceRecord", back_populates="enrollment")

    def __repr__(self):
        return f"<Enrollment {self.student_id} in {self.course_id}: {self.status.value}>"


class AcademicSession(Base):
    """Academic session (e.g., 2024/2025)."""
    __tablename__ = "academic_sessions"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4, index=True)
    name = Column(String(50), unique=True, nullable=False, index=True)  # e.g., "2024/2025"
    start_date = Column(Date, nullable=False)
    end_date = Column(Date, nullable=False)
    is_current = Column(Boolean, default=False, nullable=False, index=True)
    
    created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
    
    # Relationships
    enrollments = relationship("Enrollment", back_populates="academic_session")
    attendance_sessions = relationship("AttendanceSession", back_populates="academic_session")

    def __repr__(self):
        return f"<AcademicSession {self.name}>"


class AttendanceSession(Base):
    """A class session for attendance recording."""
    __tablename__ = "attendance_sessions"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4, index=True)
    course_id = Column(UUID(as_uuid=True), ForeignKey("courses.id"), nullable=False, index=True)
    academic_session_id = Column(UUID(as_uuid=True), ForeignKey("academic_sessions.id"), nullable=True, index=True)
    lecturer_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False, index=True)
    
    session_date = Column(Date, nullable=False, index=True)
    session_time = Column(String(20), nullable=True)  # e.g., "10:00 AM"
    topic = Column(String(255), nullable=True)
    notes = Column(Text, nullable=True)
    
    created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
    
    # Relationships
    course = relationship("Course", back_populates="attendance_sessions")
    academic_session = relationship("AcademicSession", back_populates="attendance_sessions")
    lecturer = relationship("User", foreign_keys=[lecturer_id])
    attendance_records = relationship("AttendanceRecord", back_populates="session", cascade="all, delete-orphan")

    def __repr__(self):
        return f"<AttendanceSession {self.course_id} on {self.session_date}>"


class AttendanceStatus(str, PyEnum):
    """Attendance status."""
    PRESENT = "present"
    ABSENT = "absent"
    LATE = "late"
    EXCUSED = "excused"


class AttendanceRecord(Base):
    """Individual student attendance record for a session."""
    __tablename__ = "attendance_records"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4, index=True)
    enrollment_id = Column(UUID(as_uuid=True), ForeignKey("enrollments.id"), nullable=False, index=True)
    session_id = Column(UUID(as_uuid=True), ForeignKey("attendance_sessions.id"), nullable=False, index=True)
    
    status = Column(Enum(AttendanceStatus), default=AttendanceStatus.ABSENT, nullable=False)
    remarks = Column(Text, nullable=True)
    
    recorded_at = Column(DateTime, default=datetime.utcnow, nullable=False)
    created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
    
    # Relationships
    enrollment = relationship("Enrollment", back_populates="attendance_records")
    session = relationship("AttendanceSession", back_populates="attendance_records")

    def __repr__(self):
        return f"<AttendanceRecord {self.enrollment_id}: {self.status.value}>"


class AssessmentType(str, PyEnum):
    """Assessment type."""
    CA = "ca"  # Continuous Assessment
    QUIZ = "quiz"
    ASSIGNMENT = "assignment"
    PROJECT = "project"
    MIDTERM = "midterm"
    FINAL = "final"


class Assessment(Base):
    """Assessment/CA entry for a course."""
    __tablename__ = "assessments"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4, index=True)
    course_id = Column(UUID(as_uuid=True), ForeignKey("courses.id"), nullable=False, index=True)
    enrollment_id = Column(UUID(as_uuid=True), ForeignKey("enrollments.id"), nullable=False, index=True)
    lecturer_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False, index=True)
    
    assessment_type = Column(Enum(AssessmentType), nullable=False, index=True)
    title = Column(String(255), nullable=False)
    max_score = Column(Numeric(5, 2), default=100.00, nullable=False)
    score = Column(Numeric(5, 2), nullable=False)
    weight = Column(Numeric(5, 2), nullable=True)  # Weight in final grade calculation
    
    assessment_date = Column(Date, nullable=False)
    remarks = Column(Text, nullable=True)
    
    created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
    
    # Relationships
    course = relationship("Course", back_populates="assessments")
    enrollment = relationship("Enrollment")
    lecturer = relationship("User", foreign_keys=[lecturer_id])

    def __repr__(self):
        return f"<Assessment {self.title}: {self.score}/{self.max_score}>"
