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

from typing import List, Optional
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy.orm import Session

from app.api.deps import get_current_admin, get_current_user, get_db, require_user_type
from app.models.academic import (
    AcademicSession, Assessment, AssessmentType, AttendanceRecord, AttendanceSession,
    AttendanceStatus, Course, Enrollment, EnrollmentStatus, Programme
)
from app.models.user import UserType
from app.schemas.academic import (
    AcademicSessionCreate, AcademicSessionResponse, AssessmentCreate, AssessmentResponse,
    AttendanceRecordCreate, AttendanceRecordResponse, AttendanceSessionCreate,
    AttendanceSessionResponse, CourseCreate, CourseResponse, EnrollmentCreate,
    EnrollmentResponse, ProgrammeCreate, ProgrammeResponse
)
from app.schemas.common import SuccessResponse

router = APIRouter(prefix="/academics", tags=["academics"])


# ========== Programmes ==========
@router.get("/programmes", response_model=SuccessResponse)
async def list_programmes(
    department: Optional[str] = Query(None),
    faculty: Optional[str] = Query(None),
    is_active: Optional[bool] = Query(None),
    db: Session = Depends(get_db),
):
    """List all programmes with optional filters."""
    query = db.query(Programme)
    
    if department:
        query = query.filter(Programme.department == department)
    if faculty:
        query = query.filter(Programme.faculty == faculty)
    if is_active is not None:
        query = query.filter(Programme.is_active == is_active)
    
    programmes = query.all()
    
    return SuccessResponse(
        data=[ProgrammeResponse.model_validate(p).model_dump() for p in programmes],
        message="Programmes retrieved successfully",
    )


@router.post("/programmes", response_model=SuccessResponse, status_code=status.HTTP_201_CREATED)
async def create_programme(
    programme_data: ProgrammeCreate,
    db: Session = Depends(get_db),
    current_admin = Depends(get_current_admin),
):
    """Create a new programme (admin only)."""
    # Check if code already exists
    existing = db.query(Programme).filter(Programme.code == programme_data.code).first()
    if existing:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Programme with this code already exists",
        )
    
    programme = Programme(**programme_data.model_dump())
    db.add(programme)
    db.commit()
    db.refresh(programme)
    
    return SuccessResponse(
        data=ProgrammeResponse.model_validate(programme).model_dump(),
        message="Programme created successfully",
    )


# ========== Courses ==========
@router.get("/courses", response_model=SuccessResponse)
async def list_courses(
    programme_id: Optional[UUID] = Query(None),
    level: Optional[int] = Query(None),
    semester: Optional[int] = Query(None),
    is_active: Optional[bool] = Query(None),
    db: Session = Depends(get_db),
):
    """List courses with optional filters."""
    query = db.query(Course)
    
    if programme_id:
        query = query.filter(Course.programme_id == programme_id)
    if level:
        query = query.filter(Course.level == level)
    if semester:
        query = query.filter(Course.semester == semester)
    if is_active is not None:
        query = query.filter(Course.is_active == is_active)
    
    courses = query.all()
    
    return SuccessResponse(
        data=[CourseResponse.model_validate(c).model_dump() for c in courses],
        message="Courses retrieved successfully",
    )


@router.post("/courses", response_model=SuccessResponse, status_code=status.HTTP_201_CREATED)
async def create_course(
    course_data: CourseCreate,
    db: Session = Depends(get_db),
    current_admin = Depends(get_current_admin),
):
    """Create a new course (admin only)."""
    # Verify programme exists
    programme = db.query(Programme).filter(Programme.id == course_data.programme_id).first()
    if not programme:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Programme not found",
        )
    
    course = Course(**course_data.model_dump())
    db.add(course)
    db.commit()
    db.refresh(course)
    
    return SuccessResponse(
        data=CourseResponse.model_validate(course).model_dump(),
        message="Course created successfully",
    )


# ========== Enrollments ==========
@router.get("/enrollments", response_model=SuccessResponse)
async def list_enrollments(
    student_id: Optional[UUID] = Query(None),
    course_id: Optional[UUID] = Query(None),
    programme_id: Optional[UUID] = Query(None),
    academic_session_id: Optional[UUID] = Query(None),
    status: Optional[EnrollmentStatus] = Query(None),
    db: Session = Depends(get_db),
    current_user_data: dict = Depends(get_current_user),
):
    """List enrollments with optional filters."""
    query = db.query(Enrollment)
    
    # Students can only see their own enrollments
    user_data = current_user_data
    if user_data.get("type") == "user":
        user = user_data.get("user")
        if user.user_type == UserType.GLOBAL_UNDERGRADUATE:
            query = query.filter(Enrollment.student_id == user.id)
    
    if student_id:
        query = query.filter(Enrollment.student_id == student_id)
    if course_id:
        query = query.filter(Enrollment.course_id == course_id)
    if programme_id:
        query = query.filter(Enrollment.programme_id == programme_id)
    if academic_session_id:
        query = query.filter(Enrollment.academic_session_id == academic_session_id)
    if status:
        query = query.filter(Enrollment.status == status)
    
    enrollments = query.all()
    
    return SuccessResponse(
        data=[EnrollmentResponse.model_validate(e).model_dump() for e in enrollments],
        message="Enrollments retrieved successfully",
    )


@router.post("/enrollments", response_model=SuccessResponse, status_code=status.HTTP_201_CREATED)
async def create_enrollment(
    enrollment_data: EnrollmentCreate,
    db: Session = Depends(get_db),
    current_admin = Depends(get_current_admin),
):
    """Create a new enrollment (admin/registrar only)."""
    # Verify student, programme, and course exist
    from app.models.user import User
    student = db.query(User).filter(User.id == enrollment_data.student_id).first()
    if not student:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Student not found")
    
    programme = db.query(Programme).filter(Programme.id == enrollment_data.programme_id).first()
    if not programme:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Programme not found")
    
    course = db.query(Course).filter(Course.id == enrollment_data.course_id).first()
    if not course:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Course not found")
    
    # Check if already enrolled
    existing = db.query(Enrollment).filter(
        Enrollment.student_id == enrollment_data.student_id,
        Enrollment.course_id == enrollment_data.course_id,
        Enrollment.academic_session_id == enrollment_data.academic_session_id,
    ).first()
    if existing:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Student is already enrolled in this course for this session",
        )
    
    enrollment = Enrollment(**enrollment_data.model_dump())
    db.add(enrollment)
    db.commit()
    db.refresh(enrollment)
    
    return SuccessResponse(
        data=EnrollmentResponse.model_validate(enrollment).model_dump(),
        message="Enrollment created successfully",
    )


# ========== Academic Sessions ==========
@router.get("/sessions", response_model=SuccessResponse)
async def list_academic_sessions(
    is_current: Optional[bool] = Query(None),
    db: Session = Depends(get_db),
):
    """List academic sessions."""
    query = db.query(AcademicSession)
    
    if is_current is not None:
        query = query.filter(AcademicSession.is_current == is_current)
    
    sessions = query.order_by(AcademicSession.start_date.desc()).all()
    
    return SuccessResponse(
        data=[AcademicSessionResponse.model_validate(s).model_dump() for s in sessions],
        message="Academic sessions retrieved successfully",
    )


@router.post("/sessions", response_model=SuccessResponse, status_code=status.HTTP_201_CREATED)
async def create_academic_session(
    session_data: AcademicSessionCreate,
    db: Session = Depends(get_db),
    current_admin = Depends(get_current_admin),
):
    """Create a new academic session (admin only)."""
    # If setting as current, unset all others
    if session_data.is_current:
        db.query(AcademicSession).update({"is_current": False})
    
    session = AcademicSession(**session_data.model_dump())
    db.add(session)
    db.commit()
    db.refresh(session)
    
    return SuccessResponse(
        data=AcademicSessionResponse.model_validate(session).model_dump(),
        message="Academic session created successfully",
    )


# ========== Attendance ==========
@router.get("/attendance", response_model=SuccessResponse)
async def list_attendance(
    student_id: Optional[UUID] = Query(None),
    course_id: Optional[UUID] = Query(None),
    session_id: Optional[UUID] = Query(None),
    db: Session = Depends(get_db),
    current_user_data: dict = Depends(get_current_user),
):
    """List attendance records."""
    query = db.query(AttendanceRecord).join(Enrollment)
    
    # Students can only see their own attendance
    user_data = current_user_data
    if user_data.get("type") == "user":
        user = user_data.get("user")
        if user.user_type == UserType.GLOBAL_UNDERGRADUATE:
            query = query.filter(Enrollment.student_id == user.id)
    
    if student_id:
        query = query.filter(Enrollment.student_id == student_id)
    if course_id:
        query = query.join(AttendanceSession).filter(AttendanceSession.course_id == course_id)
    if session_id:
        query = query.filter(AttendanceRecord.session_id == session_id)
    
    records = query.all()
    
    return SuccessResponse(
        data=[AttendanceRecordResponse.model_validate(r).model_dump() for r in records],
        message="Attendance records retrieved successfully",
    )


@router.post("/attendance/sessions", response_model=SuccessResponse, status_code=status.HTTP_201_CREATED)
async def create_attendance_session(
    session_data: AttendanceSessionCreate,
    db: Session = Depends(get_db),
    current_user_data: dict = Depends(get_current_user),
):
    """Create an attendance session (lecturer only)."""
    # Verify lecturer
    user_data = current_user_data
    if user_data.get("type") != "user" or user_data.get("user").user_type != UserType.ACADEMIC_FACULTY:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Only lecturers can create attendance sessions",
        )
    
    # Verify course exists
    course = db.query(Course).filter(Course.id == session_data.course_id).first()
    if not course:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Course not found")
    
    session = AttendanceSession(**session_data.model_dump())
    db.add(session)
    db.commit()
    db.refresh(session)
    
    return SuccessResponse(
        data=AttendanceSessionResponse.model_validate(session).model_dump(),
        message="Attendance session created successfully",
    )


@router.post("/attendance/records", response_model=SuccessResponse, status_code=status.HTTP_201_CREATED)
async def create_attendance_record(
    record_data: AttendanceRecordCreate,
    db: Session = Depends(get_db),
    current_user_data: dict = Depends(get_current_user),
):
    """Record attendance for a student (lecturer only)."""
    # Verify lecturer
    user_data = current_user_data
    if user_data.get("type") != "user" or user_data.get("user").user_type != UserType.ACADEMIC_FACULTY:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Only lecturers can record attendance",
        )
    
    # Verify enrollment and session exist
    enrollment = db.query(Enrollment).filter(Enrollment.id == record_data.enrollment_id).first()
    if not enrollment:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Enrollment not found")
    
    session = db.query(AttendanceSession).filter(AttendanceSession.id == record_data.session_id).first()
    if not session:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Attendance session not found")
    
    # Check if record already exists
    existing = db.query(AttendanceRecord).filter(
        AttendanceRecord.enrollment_id == record_data.enrollment_id,
        AttendanceRecord.session_id == record_data.session_id,
    ).first()
    if existing:
        # Update existing record
        existing.status = record_data.status
        existing.remarks = record_data.remarks
        db.commit()
        db.refresh(existing)
        return SuccessResponse(
            data=AttendanceRecordResponse.model_validate(existing).model_dump(),
            message="Attendance record updated successfully",
        )
    
    record = AttendanceRecord(**record_data.model_dump())
    db.add(record)
    db.commit()
    db.refresh(record)
    
    return SuccessResponse(
        data=AttendanceRecordResponse.model_validate(record).model_dump(),
        message="Attendance record created successfully",
    )


# ========== Assessments ==========
@router.get("/assessments", response_model=SuccessResponse)
async def list_assessments(
    student_id: Optional[UUID] = Query(None),
    course_id: Optional[UUID] = Query(None),
    enrollment_id: Optional[UUID] = Query(None),
    assessment_type: Optional[AssessmentType] = Query(None),
    db: Session = Depends(get_db),
    current_user_data: dict = Depends(get_current_user),
):
    """List assessments."""
    query = db.query(Assessment).join(Enrollment)
    
    # Students can only see their own assessments
    user_data = current_user_data
    if user_data.get("type") == "user":
        user = user_data.get("user")
        if user.user_type == UserType.GLOBAL_UNDERGRADUATE:
            query = query.filter(Enrollment.student_id == user.id)
    
    if student_id:
        query = query.filter(Enrollment.student_id == student_id)
    if course_id:
        query = query.filter(Assessment.course_id == course_id)
    if enrollment_id:
        query = query.filter(Assessment.enrollment_id == enrollment_id)
    if assessment_type:
        query = query.filter(Assessment.assessment_type == assessment_type)
    
    assessments = query.all()
    
    return SuccessResponse(
        data=[AssessmentResponse.model_validate(a).model_dump() for a in assessments],
        message="Assessments retrieved successfully",
    )


@router.post("/assessments", response_model=SuccessResponse, status_code=status.HTTP_201_CREATED)
async def create_assessment(
    assessment_data: AssessmentCreate,
    db: Session = Depends(get_db),
    current_user_data: dict = Depends(get_current_user),
):
    """Create an assessment entry (lecturer only)."""
    # Verify lecturer
    user_data = current_user_data
    if user_data.get("type") != "user" or user_data.get("user").user_type != UserType.ACADEMIC_FACULTY:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Only lecturers can create assessments",
        )
    
    # Verify enrollment and course exist
    enrollment = db.query(Enrollment).filter(Enrollment.id == assessment_data.enrollment_id).first()
    if not enrollment:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Enrollment not found")
    
    course = db.query(Course).filter(Course.id == assessment_data.course_id).first()
    if not course:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Course not found")
    
    assessment = Assessment(**assessment_data.model_dump())
    db.add(assessment)
    db.commit()
    db.refresh(assessment)
    
    return SuccessResponse(
        data=AssessmentResponse.model_validate(assessment).model_dump(),
        message="Assessment created successfully",
    )
