from datetime import datetime, time, date, timedelta
from sqlalchemy import func, and_, or_, case, extract
from src.models import DatabaseContextManager
from src.models.models import (
    Tutor, TeachingSession, TutorAvailability, TimetableBlock, Supervisor, Course, Attendance,
    AttendanceStatus, TeachingVerificationMethod, Reminder, TutorTeachingLog, Student, Enrollment,
    MakeupSession, DailyTeachingSession, User
)
from flask import current_app
from src.utils import (
    ApiABC,
    custom_response,
    send_email
)
import uuid
from typing import Dict, List
from enum import Enum
from .continuous_sessions import continuous_session_manager


class SessionConflictType(Enum):
    """Types of teaching session conflicts"""
    TUTOR_UNAVAILABLE = "tutor_unavailable"
    TUTOR_ON_LEAVE = "tutor_on_leave"
    TIMETABLE_CONFLICT = "timetable_conflict"
    ROOM_CONFLICT = "room_conflict"
    COURSE_CONFLICT = "course_conflict"
    OVERLAP = "overlap"
    OUTSIDE_WORKING_HOURS = "outside_working_hours"

class TeachingSessionManager:
    def __init__(self):
        self.table = TeachingSession
        # Initialize continuous session manager
        continuous_session_manager.set_session_manager(self)

    def create(self, payload: Dict) -> Dict:
        """
        Create a new teaching session after validating against tutor availability and timetable
        
        Args:
            payload: {
                'course_id': str,
                'tutor_id': str,
                'timetable_block_id': str (optional),
                'title': str,
                'description': str (optional),
                'start_datetime': str (ISO format),
                'end_datetime': str (ISO format),
                'location': str (optional),
                'max_attendees': int (optional),
                'is_mandatory': bool (default True),
                'session_type': str ('lecture', 'tutorial', 'lab', etc.),
                'materials_prepared': bool (default False),
                'notes': str (optional),
                'created_by': str (supervisor ID)
            }
            
        Returns:
            Response with created session or error
        """
        with DatabaseContextManager() as ctx:
            # Validate required fields
            required_fields = ['course_id', 'tutor_id', 'session_type', 'created_by']
            if not all(field in payload for field in required_fields):
                return custom_response(
                    success=False,
                    data=f"Missing required fields. Required: {', '.join(required_fields)}",
                    status_code=400
                )
            
            # Parse datetimes
            try:
                start_datetime = datetime.fromisoformat(payload['start_datetime'])
                end_datetime = datetime.fromisoformat(payload['end_datetime'])
                
                if end_datetime <= start_datetime:
                    return custom_response(
                        success=False,
                        data="End datetime must be after start datetime",
                        status_code=400
                    )
            except ValueError as e:
                return custom_response(
                    success=False,
                    data=f"Invalid datetime format: {str(e)}",
                    status_code=400
                )
            
            # Check for conflicts
            conflict_check = self._check_session_conflicts(ctx, payload)
            if conflict_check['has_conflicts']:
                return custom_response(
                    success=False,
                    data={
                        'message': 'Teaching session conflicts detected',
                        'conflicts': conflict_check['conflicts']
                    },
                    status_code=409
                )
            
            # Create the session
            session = TeachingSession(
                id=str(uuid.uuid4()),
                course_id=payload['course_id'],
                tutor_id=payload['tutor_id'],
                supervisor_tutor_id=payload.get('supervisor_tutor_id'),
                timetable_id=payload.get('timetable_id'),
                room=payload.get('location', 'TBD'),
                day_of_week=start_datetime.weekday(),
                start_time=start_datetime.time(),
                end_time=end_datetime.time(),
                status='scheduled',
                session_type=payload['session_type'],
                recurring=payload.get('recurring', True),
                notes=payload.get('notes'),
                created_at=datetime.utcnow(),
                updated_at=datetime.utcnow(),
                created_by=payload['created_by']
            )
            
            ctx.session.add(session)
            ctx.session.commit()
            
            # Send notifications if needed
            self._notify_about_new_session(session)
            
            return custom_response(
                success=True,
                data=self._session_to_dict(session),
                status_code=201
            )

    def get(self, session_id: str) -> Dict:
        """Get a specific teaching session by ID with full details"""
        with DatabaseContextManager() as ctx:
            session = ctx.session.query(TeachingSession).filter(
                TeachingSession.id == session_id
            ).first()
            
            if not session:
                return custom_response(
                    success=False,
                    data="Teaching session not found",
                    status_code=404
                )
            
            return custom_response(
                success=True,
                data=self._session_to_dict(session, include_details=True),
                status_code=200
            )

    def update(self, session_id: str, payload: Dict) -> Dict:
        """
        Update a teaching session after validating against conflicts
        
        Args:
            session_id: ID of the session to update
            payload: Update data (same structure as create but partial)
            
        Returns:
            Response with updated session or error
        """
        with DatabaseContextManager() as ctx:
            session = ctx.session.query(TeachingSession).filter(
                TeachingSession.id == session_id
            ).first()
            
            if not session:
                return custom_response(
                    success=False,
                    data="Teaching session not found",
                    status_code=404
                )
            
            # Check if time/date fields are being changed
            core_fields = ['start_time', 'end_time', 'tutor_id', 'course_id', 'room']
            needs_validation = any(field in payload for field in core_fields)
            
            # For time fields, parse first
            time_updates = {}
            if 'start_time' in payload:
                try:
                    if isinstance(payload['start_time'], str):
                        time_updates['start_time'] = datetime.strptime(payload['start_time'], '%H:%M').time()
                    else:
                        time_updates['start_time'] = payload['start_time']
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid start_time format. Use HH:MM format",
                        status_code=400
                    )
            
            if 'end_time' in payload:
                try:
                    if isinstance(payload['end_time'], str):
                        time_updates['end_time'] = datetime.strptime(payload['end_time'], '%H:%M').time()
                    else:
                        time_updates['end_time'] = payload['end_time']
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid end_time format. Use HH:MM format",
                        status_code=400
                    )
            
            # Check time validity if both are being updated
            if 'start_time' in payload and 'end_time' in payload:
                if time_updates['end_time'] <= time_updates['start_time']:
                    return custom_response(
                        success=False,
                        data="End time must be after start time",
                        status_code=400
                    )
            
            # Check for conflicts if changing time/tutor/location
            if needs_validation:
                test_session = {
                    'course_id': payload.get('course_id', session.course_id),
                    'tutor_id': payload.get('tutor_id', session.tutor_id),
                    'start_time': payload.get('start_time', session.start_time.strftime('%H:%M')),
                    'end_time': payload.get('end_time', session.end_time.strftime('%H:%M')),
                    'room': payload.get('room', session.room),
                    'timetable_id': payload.get('timetable_id', session.timetable_id)
                }
                
                conflict_check = self._check_session_conflicts(
                    ctx,
                    test_session,
                    exclude_session_id=session_id
                )
                
                if conflict_check['has_conflicts']:
                    return custom_response(
                        success=False,
                        data={
                            'message': 'Teaching session conflicts detected with proposed changes',
                            'conflicts': conflict_check['conflicts']
                        },
                        status_code=409
                    )
            
            # Apply updates
            if 'course_id' in payload:
                session.course_id = payload['course_id']
            
            if 'tutor_id' in payload:
                session.tutor_id = payload['tutor_id']
            
            if 'supervisor_tutor_id' in payload:
                session.supervisor_tutor_id = payload['supervisor_tutor_id']
            
            if 'timetable_id' in payload:
                session.timetable_id = payload['timetable_id']
            
            if 'room' in payload:
                session.room = payload['room']
            
            if 'day_of_week' in payload:
                session.day_of_week = payload['day_of_week']
            
            if 'start_time' in payload:
                session.start_time = time_updates['start_time']
            
            if 'end_time' in payload:
                session.end_time = time_updates['end_time']
            
            if 'session_type' in payload:
                session.session_type = payload['session_type']
            
            if 'recurring' in payload:
                session.recurring = payload['recurring']
            
            if 'notes' in payload:
                session.notes = payload['notes']
            
            if 'status' in payload:
                session.status = payload['status']
            
            session.updated_at = datetime.utcnow()
            
            ctx.session.commit()
            
            # Send notifications if status changed
            if 'status' in payload:
                self._notify_about_session_status_change(session)
            
            return custom_response(
                success=True,
                data=self._session_to_dict(session),
                status_code=200
            )

    def delete(self, session_id: str) -> Dict:
        """Delete a teaching session and related records"""
        with DatabaseContextManager() as ctx:
            session = ctx.session.query(TeachingSession).filter(
                TeachingSession.id == session_id
            ).first()
            
            if not session:
                return custom_response(
                    success=False,
                    data="Teaching session not found",
                    status_code=404
                )
            
            # Delete related attendance records
            ctx.session.query(Attendance).filter(
                Attendance.session_id == session_id
            ).delete()
            
            # Delete related reminders
            ctx.session.query(Reminder).filter(
                Reminder.session_id == session_id
            ).delete()
            
            # Delete the session
            ctx.session.delete(session)
            ctx.session.commit()
            
            return custom_response(
                success=True,
                data="Teaching session and all related records deleted successfully",
                status_code=200
            )

    def check_in_tutor(self, session_id: str, payload: Dict) -> Dict:
        """
        Record tutor check-in for a session with verification method
        
        Args:
            session_id: ID of the session
            payload: {
                'tutor_id': str,
                'checkin_time': str (ISO datetime, optional - defaults to now),
                'verification_method': str (from TeachingVerificationMethod enum),
                'latitude': float (optional),
                'longitude': float (optional),
                'device_info': str (optional),
                'ip_address': str (optional),
                'notes': str (optional)
            }
            
        Returns:
            Response with updated session or error
        """
        with DatabaseContextManager() as ctx:
            session = ctx.session.query(TeachingSession).filter(
                TeachingSession.id == session_id
            ).first()
            
            if not session:
                return custom_response(
                    success=False,
                    data="Teaching session not found",
                    status_code=404
                )
            
            # Verify tutor
            if session.tutor_id != payload['tutor_id']:
                return custom_response(
                    success=False,
                    data="Only the assigned tutor can check in to this session",
                    status_code=403
                )
            
            # Parse checkin time
            checkin_time = datetime.utcnow()
            if 'checkin_time' in payload:
                try:
                    checkin_time = datetime.fromisoformat(payload['checkin_time'])
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid checkin_time format. Use ISO format",
                        status_code=400
                    )
            
            # Validate verification method
            try:
                verification_method = TeachingVerificationMethod(payload['verification_method'])
            except ValueError:
                return custom_response(
                    success=False,
                    data=f"Invalid verification method. Valid methods: {[m.value for m in TeachingVerificationMethod]}",
                    status_code=400
                )
            
            # Update session
            session.tutor_checkin_time = checkin_time
            session.tutor_checkin_method = verification_method
            
            if 'latitude' in payload and 'longitude' in payload:
                session.tutor_location_lat = payload['latitude']
                session.tutor_location_long = payload['longitude']
            
            if 'device_info' in payload:
                session.device_used = payload['device_info']
            
            if 'ip_address' in payload:
                session.ip_address = payload['ip_address']
            
            if 'notes' in payload:
                session.session_notes = payload['notes']
            
            ctx.session.commit()
            
            return custom_response(
                success=True,
                data=self._session_to_dict(session),
                status_code=200
            )

    def check_out_tutor(self, session_id: str, payload: Dict) -> Dict:
        """
        Record tutor check-out for a session with verification method
        
        Args:
            session_id: ID of the session
            payload: {
                'tutor_id': str,
                'checkout_time': str (ISO datetime, optional - defaults to now),
                'verification_method': str (from TeachingVerificationMethod enum),
                'notes': str (optional),
                'teaching_materials_used': str (optional, JSON),
                'student_interaction_notes': str (optional),
                'issues_encountered': str (optional)
            }
            
        Returns:
            Response with updated session or error
        """
        with DatabaseContextManager() as ctx:
            session = ctx.session.query(TeachingSession).filter(
                TeachingSession.id == session_id
            ).first()
            
            if not session:
                return custom_response(
                    success=False,
                    data="Teaching session not found",
                    status_code=404
                )
            
            # Verify tutor
            if session.tutor_id != payload['tutor_id']:
                return custom_response(
                    success=False,
                    data="Only the assigned tutor can check out from this session",
                    status_code=403
                )
            
            # Must be checked in first
            if not session.tutor_checkin_time:
                return custom_response(
                    success=False,
                    data="Tutor must check in before checking out",
                    status_code=400
                )
            
            # Parse checkout time
            checkout_time = datetime.utcnow()
            if 'checkout_time' in payload:
                try:
                    checkout_time = datetime.fromisoformat(payload['checkout_time'])
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid checkout_time format. Use ISO format",
                        status_code=400
                    )
            
            # Validate verification method
            try:
                verification_method = TeachingVerificationMethod(payload['verification_method'])
            except ValueError:
                return custom_response(
                    success=False,
                    data=f"Invalid verification method. Valid methods: {[m.value for m in TeachingVerificationMethod]}",
                    status_code=400
                )
            
            # Update session
            session.tutor_checkout_time = checkout_time
            session.tutor_checkout_method = verification_method
            session.status = 'completed'
            
            if 'notes' in payload:
                session.session_notes = payload['notes']
            
            if 'teaching_materials_used' in payload:
                session.materials_used = payload['teaching_materials_used']
            
            if 'student_interaction_notes' in payload:
                session.student_interaction_notes = payload['student_interaction_notes']
            
            if 'issues_encountered' in payload:
                session.issues_encountered = payload['issues_encountered']
            
            # Create teaching log
            log = TutorTeachingLog(
                id=str(uuid.uuid4()),
                tutor_id=session.tutor_id,
                session_id=session.id,
                checkin_time=session.tutor_checkin_time,
                checkout_time=checkout_time,
                verification_method=verification_method,
                location_lat=session.tutor_location_lat,
                location_long=session.tutor_location_long,
                device_info=session.device_used,
                ip_address=session.ip_address,
                session_duration=(checkout_time - session.tutor_checkin_time).total_seconds() / 60,
                teaching_materials_used=payload.get('teaching_materials_used'),
                student_interaction_notes=payload.get('student_interaction_notes'),
                issues_encountered=payload.get('issues_encountered')
            )
            
            ctx.session.add(log)
            ctx.session.commit()
            
            return custom_response(
                success=True,
                data=self._session_to_dict(session),
                status_code=200
            )

    def verify_session(self, session_id: str, supervisor_id: str, payload: Dict) -> Dict:
        """
        Verify a completed teaching session by supervisor
        
        Args:
            session_id: ID of the session
            supervisor_id: ID of the verifying supervisor
            payload: {
                'verification_method': str (from TeachingVerificationMethod enum),
                'verification_notes': str (optional),
                'status': str ('verified' or 'needs_review'),
                'supervisor_notes': str (optional)
            }
            
        Returns:
            Response with verified session or error
        """
        with DatabaseContextManager() as ctx:
            session = ctx.session.query(TeachingSession).filter(
                TeachingSession.id == session_id
            ).first()
            
            if not session:
                return custom_response(
                    success=False,
                    data="Teaching session not found",
                    status_code=404
                )
            
            # Verify supervisor exists
            supervisor = ctx.session.query(Supervisor).filter(
                Supervisor.id == supervisor_id,
                Supervisor.is_active == True
            ).first()
            
            if not supervisor:
                return custom_response(
                    success=False,
                    data="Supervisor not found or inactive",
                    status_code=404
                )
            
            # Session must be completed first
            if session.status != 'completed':
                return custom_response(
                    success=False,
                    data="Only completed sessions can be verified",
                    status_code=400
                )
            
            # Validate verification method
            try:
                verification_method = TeachingVerificationMethod(payload['verification_method'])
            except ValueError:
                return custom_response(
                    success=False,
                    data=f"Invalid verification method. Valid methods: {[m.value for m in TeachingVerificationMethod]}",
                    status_code=400
                )
            
            # Validate status
            if payload['status'] not in ['verified', 'needs_review']:
                return custom_response(
                    success=False,
                    data="Invalid verification status. Must be 'verified' or 'needs_review'",
                    status_code=400
                )
            
            # Update session
            session.is_verified = payload['status'] == 'verified'
            session.verified_by = supervisor_id
            session.verified_at = datetime.utcnow()
            session.verification_method = verification_method
            session.status = payload['status']

            
            if 'supervisor_notes' in payload:
                session.supervisor_notes = payload['supervisor_notes']
            
            ctx.session.commit()
            
            # Notify tutor about verification
            self._notify_tutor_about_verification(session)
            
            return custom_response(
                success=True,
                data=self._session_to_dict(session),
                status_code=200
            )

    def record_attendance(self, session_id: str, payload: Dict) -> Dict:
        """
        Record attendance for students in a session
        
        Args:
            session_id: ID of the session
            payload: {
                'tutor_id': str (ID of tutor recording attendance),
                'attendances': [{
                    'student_id': str,
                    'status': str (from AttendanceStatus enum),
                    'notes': str (optional),
                    'late_minutes': int (optional),
                    'device_used': str (optional),
                    'ip_address': str (optional)
                }]
            }
            
        Returns:
            Response with attendance records or error
        """
        with DatabaseContextManager() as ctx:
            session = ctx.session.query(TeachingSession).filter(
                TeachingSession.id == session_id
            ).first()
            
            if not session:
                return custom_response(
                    success=False,
                    data="Teaching session not found",
                    status_code=404
                )
            
            # Verify tutor is the session tutor
            if session.tutor_id != payload['tutor_id']:
                return custom_response(
                    success=False,
                    data="Only the assigned tutor can record attendance for this session",
                    status_code=403
                )
            
            # Session must be completed or in progress
            if session.status not in ['completed', 'scheduled']:
                return custom_response(
                    success=False,
                    data="Attendance can only be recorded for scheduled or completed sessions",
                    status_code=400
                )
            
            # Process each attendance record
            attendance_records = []
            for attendance_data in payload['attendances']:
                # Validate status
                try:
                    status = AttendanceStatus(attendance_data['status'])
                except ValueError:
                    return custom_response(
                        success=False,
                        data=f"Invalid attendance status. Valid statuses: {[s.value for s in AttendanceStatus]}",
                        status_code=400
                    )
                
                # Check if student is enrolled in the course
                enrollment = ctx.session.query(Enrollment).filter(
                    Enrollment.student_id == attendance_data['student_id'],
                    Enrollment.course_id == session.course_id,
                    Enrollment.status == 'active'
                ).first()
                
                if not enrollment:
                    return custom_response(
                        success=False,
                        data=f"Student {attendance_data['student_id']} is not enrolled in this course",
                        status_code=400
                    )
                
                # Create or update attendance record
                attendance = ctx.session.query(Attendance).filter(
                    Attendance.session_id == session_id,
                    Attendance.student_id == attendance_data['student_id']
                ).first()
                
                if attendance:
                    # Update existing record
                    attendance.status = status
                    attendance.timestamp = datetime.utcnow()
                    attendance.notes = attendance_data.get('notes')
                    attendance.late_minutes = attendance_data.get('late_minutes', 0)
                    attendance.device_used = attendance_data.get('device_used')
                    attendance.ip_address = attendance_data.get('ip_address')
                else:
                    # Create new record
                    attendance = Attendance(
                        id=str(uuid.uuid4()),
                        session_id=session_id,
                        student_id=attendance_data['student_id'],
                        tutor_id=payload['tutor_id'],
                        status=status,
                        timestamp=datetime.utcnow(),
                        notes=attendance_data.get('notes'),
                        late_minutes=attendance_data.get('late_minutes', 0),
                        device_used=attendance_data.get('device_used'),
                        ip_address=attendance_data.get('ip_address')
                    )
                    ctx.session.add(attendance)
                
                attendance_records.append(attendance)
            
            ctx.session.commit()
            
            # Update session status if not already completed
            if session.status == 'scheduled':
                session.status = 'completed'
                ctx.session.commit()
            
            return custom_response(
                success=True,
                data=[self._attendance_to_dict(att) for att in attendance_records],
                status_code=200
            )

    def get_sessions_for_tutor(self, tutor_id: str, start_date: str = None, end_date: str = None) -> Dict:
        """
        Get teaching sessions for a tutor within a date range
        Note: This also includes sessions where a supervisor is acting as a tutor
        
        Args:
            tutor_id: ID of the tutor (can be a supervisor acting as tutor)
            start_date: Optional start date (ISO format)
            end_date: Optional end date (ISO format)
            
        Returns:
            Response with list of sessions
        """
        with DatabaseContextManager() as ctx:
            # Query for sessions where this user is the tutor (regardless of user type)
            query = ctx.session.query(TeachingSession).filter(
                TeachingSession.tutor_id == tutor_id
            ).order_by(TeachingSession.start_time)
            
            # Apply date filters if provided
            # Note: Sessions store only Time (no date) as they are recurring
            # We filter by day of week instead
            if start_date:
                try:
                    start_date_obj = date.fromisoformat(start_date)
                    # Get the day of week (0=Monday, 1=Tuesday, etc.)
                    day_of_week = start_date_obj.weekday()
                    query = query.filter(TeachingSession.day_of_week == day_of_week)
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid start_date format. Use YYYY-MM-DD",
                        status_code=400
                    )
            
            # For end_date, if it's the same as start_date, we already filtered by day
            # If different, we need to include multiple days
            if end_date and end_date != start_date:
                try:
                    end_date_obj = date.fromisoformat(end_date)
                    # For now, just use the start_date day filter
                    # In a more complex implementation, we could include multiple days
                    pass
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid end_date format. Use YYYY-MM-DD",
                        status_code=400
                    )
            
            sessions = query.all()
            
            return custom_response(
                success=True,
                data=[self._session_to_dict(session) for session in sessions],
                status_code=200
            )

    def get_sessions_for_course(self, course_id: str, start_date: str = None, end_date: str = None) -> Dict:
        """
        Get teaching sessions for a course within a date range
        
        Args:
            course_id: ID of the course
            start_date: Optional start date (ISO format)
            end_date: Optional end date (ISO format)
            
        Returns:
            Response with list of sessions
        """
        with DatabaseContextManager() as ctx:
            query = ctx.session.query(TeachingSession).filter(
                TeachingSession.course_id == course_id
            ).order_by(TeachingSession.start_time)
            
            # Apply date filters if provided
            # Note: Sessions store only Time (no date) as they are recurring
            # We filter by day of week instead
            if start_date:
                try:
                    start_date_obj = date.fromisoformat(start_date)
                    # Get the day of week (0=Monday, 1=Tuesday, etc.)
                    day_of_week = start_date_obj.weekday()
                    query = query.filter(TeachingSession.day_of_week == day_of_week)
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid start_date format. Use YYYY-MM-DD",
                        status_code=400
                    )
            
            # For end_date, if it's the same as start_date, we already filtered by day
            # If different, we need to include multiple days
            if end_date and end_date != start_date:
                try:
                    end_date_obj = date.fromisoformat(end_date)
                    # For now, just use the start_date day filter
                    # In a more complex implementation, we could include multiple days
                    pass
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid end_date format. Use YYYY-MM-DD",
                        status_code=400
                    )
            
            sessions = query.all()
            
            return custom_response(
                success=True,
                data=[self._session_to_dict(session) for session in sessions],
                status_code=200
            )

    def get_sessions_for_student(self, student_id: str, start_date: str = None, end_date: str = None) -> Dict:
        """
        Get teaching sessions for a student within a date range
        
        Args:
            student_id: ID of the student
            start_date: Optional start date (ISO format)
            end_date: Optional end date (ISO format)
            
        Returns:
            Response with list of sessions
        """
        with DatabaseContextManager() as ctx:
            # First get all courses the student is enrolled in
            enrollments = ctx.session.query(Enrollment).filter(
                Enrollment.student_id == student_id,
                Enrollment.status == 'active'
            ).all()
            
            if not enrollments:
                return custom_response(
                    success=True,
                    data=[],
                    status_code=200
                )
            
            course_ids = [e.course_id for e in enrollments]
            
            query = ctx.session.query(TeachingSession).filter(
                TeachingSession.course_id.in_(course_ids)
            ).order_by(TeachingSession.start_time)
            
            # Apply date filters if provided
            # Note: Sessions store only Time (no date) as they are recurring
            # We filter by day of week instead
            if start_date:
                try:
                    start_date_obj = date.fromisoformat(start_date)
                    # Get the day of week (0=Monday, 1=Tuesday, etc.)
                    day_of_week = start_date_obj.weekday()
                    query = query.filter(TeachingSession.day_of_week == day_of_week)
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid start_date format. Use YYYY-MM-DD",
                        status_code=400
                    )
            
            # For end_date, if it's the same as start_date, we already filtered by day
            # If different, we need to include multiple days
            if end_date and end_date != start_date:
                try:
                    end_date_obj = date.fromisoformat(end_date)
                    # For now, just use the start_date day filter
                    # In a more complex implementation, we could include multiple days
                    pass
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid end_date format. Use YYYY-MM-DD",
                        status_code=400
                    )
            
            sessions = query.all()
            
            return custom_response(
                success=True,
                data=[self._session_to_dict(session) for session in sessions],
                status_code=200
            )

    def get_sessions_for_supervisor(self, supervisor_id: str, start_date: str = None, end_date: str = None, status: str = None) -> Dict:
        """
        Get teaching sessions for courses supervised by a supervisor within a date range
        
        Args:
            supervisor_id: ID of the supervisor
            start_date: Optional start date (ISO format)
            end_date: Optional end date (ISO format)
            status: Optional status filter (scheduled, ongoing, completed, cancelled)
            
        Returns:
            Response with list of sessions
        """
        with DatabaseContextManager() as ctx:
            # First get all courses supervised by this supervisor
            courses = ctx.session.query(Course).filter(
                Course.supervisor_id == supervisor_id,
                Course.is_active == True
            ).all()
            
            if not courses:
                return custom_response(
                    success=True,
                    data=[],
                    status_code=200
                )
            
            course_ids = [course.id for course in courses]
            
            # Build the query
            query = ctx.session.query(TeachingSession).filter(
                TeachingSession.course_id.in_(course_ids)
            ).order_by(TeachingSession.start_time)
            
            # Apply status filter if provided
            if status:
                if status == 'ongoing':
                    # For ongoing sessions, check if current time is between start and end
                    now = datetime.utcnow()
                    query = query.filter(
                        TeachingSession.start_time <= now,
                        TeachingSession.end_time >= now,
                        TeachingSession.status == 'scheduled'
                    )
                else:
                    query = query.filter(TeachingSession.status == status)
            
            # Apply date filters if provided
            # Note: Sessions store only Time (no date) as they are recurring
            # We filter by day of week instead
            if start_date:
                try:
                    start_date_obj = date.fromisoformat(start_date)
                    # Get the day of week (0=Monday, 1=Tuesday, etc.)
                    day_of_week = start_date_obj.weekday()
                    query = query.filter(TeachingSession.day_of_week == day_of_week)
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid start_date format. Use YYYY-MM-DD",
                        status_code=400
                    )
            
            # For end_date, if it's the same as start_date, we already filtered by day
            # If different, we need to include multiple days
            if end_date and end_date != start_date:
                try:
                    end_date_obj = date.fromisoformat(end_date)
                    # For now, just use the start_date day filter
                    # In a more complex implementation, we could include multiple days
                    pass
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid end_date format. Use YYYY-MM-DD",
                        status_code=400
                    )
            
            sessions = query.all()
            
            # Convert to dictionary format with additional details
            sessions_data = []
            for session in sessions:
                session_dict = self._session_to_dict(session, include_details=True)
                
                # Add course details
                if session.course:
                    session_dict['course'] = {
                        'id': session.course.id,
                        'code': session.course.code,
                        'title': session.course.title,
                        'department': session.course.department
                    }
                
                # Add tutor details
                if session.tutor:
                    # Handle both Tutor and Supervisor objects
                    department = None
                    if hasattr(session.tutor, 'departments') and session.tutor.departments:
                        # For Supervisor objects with departments list
                        primary_dept = next((dept for dept in session.tutor.departments if dept.is_primary), None)
                        department = primary_dept.department_name if primary_dept else 'Unknown'
                    elif hasattr(session.tutor, 'department'):
                        # For Tutor objects with single department
                        department = session.tutor.department
                    else:
                        department = 'Unknown'
                    
                    session_dict['tutor'] = {
                        'id': session.tutor.id,
                        'first_name': session.tutor.first_name,
                        'last_name': session.tutor.last_name,
                        'email': session.tutor.email,
                        'phone': getattr(session.tutor, 'phone', None),
                        'department': department
                    }
                
                # Add participants count
                participants_count = ctx.session.query(Enrollment).filter(
                    Enrollment.course_id == session.course_id,
                    Enrollment.status == 'active'
                ).count()
                
                session_dict['participants_count'] = participants_count
                session_dict['max_participants'] = participants_count  # Use participants count as max for now
                
                sessions_data.append(session_dict)
            
            return custom_response(
                success=True,
                data=sessions_data,
                status_code=200
            )

    def get_attendance_for_session(self, session_id: str) -> Dict:
        """
        Get attendance records for a specific session
        
        Args:
            session_id: ID of the session
            
        Returns:
            Response with list of attendance records
        """
        with DatabaseContextManager() as ctx:
            session = ctx.session.query(TeachingSession).filter(
                TeachingSession.id == session_id
            ).first()
            
            if not session:
                return custom_response(
                    success=False,
                    data="Teaching session not found",
                    status_code=404
                )
            
            attendance_records = ctx.session.query(Attendance).filter(
                Attendance.session_id == session_id
            ).all()
            
            return custom_response(
                success=True,
                data=[self._attendance_to_dict(att) for att in attendance_records],
                status_code=200
            )

    def get_attendance_for_student(self, student_id: str, course_id: str = None) -> Dict:
        """
        Get attendance records for a student, optionally filtered by course
        
        Args:
            student_id: ID of the student
            course_id: Optional course ID to filter by
            
        Returns:
            Response with list of attendance records
        """
        with DatabaseContextManager() as ctx:
            query = ctx.session.query(Attendance).filter(
                Attendance.student_id == student_id
            ).join(
                TeachingSession,
                Attendance.session_id == TeachingSession.id
            ).order_by(TeachingSession.start_time)
            
            if course_id:
                query = query.filter(TeachingSession.course_id == course_id)
            
            attendance_records = query.all()
            
            return custom_response(
                success=True,
                data=[self._attendance_to_dict(att) for att in attendance_records],
                status_code=200
            )

    def generate_attendance_report(self, course_id: str, start_date: str = None, end_date: str = None) -> Dict:
        """
        Generate a comprehensive attendance report for a course
        
        Args:
            course_id: ID of the course
            start_date: Optional start date (ISO format)
            end_date: Optional end date (ISO format)
            
        Returns:
            Response with attendance report
        """
        with DatabaseContextManager() as ctx:
            # Get all sessions for the course
            sessions_query = ctx.session.query(TeachingSession).filter(
                TeachingSession.course_id == course_id
            )
            
            # Apply date filters if provided
            if start_date:
                try:
                    start_date = date.fromisoformat(start_date)
                    sessions_query = sessions_query.filter(TeachingSession.start_time >= start_date)
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid start_date format. Use YYYY-MM-DD",
                        status_code=400
                    )
            
            if end_date:
                try:
                    end_date = date.fromisoformat(end_date)
                    sessions_query = sessions_query.filter(TeachingSession.start_time <= end_date + timedelta(days=1))
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid end_date format. Use YYYY-MM-DD",
                        status_code=400
                    )
            
            sessions = sessions_query.order_by(TeachingSession.start_time).all()
            
            if not sessions:
                return custom_response(
                    success=False,
                    data="No sessions found for this course in the specified date range",
                    status_code=404
                )
            
            # Get all enrolled students
            enrollments = ctx.session.query(Enrollment).filter(
                Enrollment.course_id == course_id,
                Enrollment.status == 'active'
            ).all()
            
            if not enrollments:
                return custom_response(
                    success=False,
                    data="No active students enrolled in this course",
                    status_code=404
                )
            
            student_ids = [e.student_id for e in enrollments]
            students = ctx.session.query(Student).filter(
                Student.id.in_(student_ids)
            ).all()
            
            # Get all attendance records for these sessions and students
            attendance_records = ctx.session.query(Attendance).filter(
                Attendance.session_id.in_([s.id for s in sessions]),
                Attendance.student_id.in_(student_ids)
            ).all()
            
            # Organize attendance by student and session
            attendance_map = {}
            for att in attendance_records:
                if att.student_id not in attendance_map:
                    attendance_map[att.student_id] = {}
                attendance_map[att.student_id][att.session_id] = att
            
            # Build the report
            report = {
                'course_id': course_id,
                'course_title': sessions[0].course.title if sessions[0].course else 'Unknown',
                'start_date': start_date.isoformat() if start_date else None,
                'end_date': end_date.isoformat() if end_date else None,
                'total_sessions': len(sessions),
                'students': []
            }
            
            for student in students:
                student_data = {
                    'student_id': student.id,
                    'student_name': f"{student.first_name} {student.last_name}",
                    'student_id_number': student.student_id,
                    'total_attended': 0,
                    'total_absent': 0,
                    'total_late': 0,
                    'total_excused': 0,
                    'attendance_percentage': 0,
                    'sessions': []
                }
                
                for session in sessions:
                    session_data = {
                        'session_id': session.id,
                        'session_title': session.title,
                        'session_date': session.start_time.date().isoformat(),
                        'session_time': f"{session.start_time.time().strftime('%H:%M')} - {session.end_time.time().strftime('%H:%M')}",
                        'status': 'absent',  # Default status
                        'late_minutes': 0,
                        'notes': None
                    }
                    
                    if student.id in attendance_map and session.id in attendance_map[student.id]:
                        att = attendance_map[student.id][session.id]
                        session_data['status'] = att.status.value
                        session_data['late_minutes'] = att.late_minutes or 0
                        session_data['notes'] = att.notes
                        
                        # Update counters
                        if att.status == AttendanceStatus.present:
                            student_data['total_attended'] += 1
                        elif att.status == AttendanceStatus.absent:
                            student_data['total_absent'] += 1
                        elif att.status == AttendanceStatus.late:
                            student_data['total_late'] += 1
                        elif att.status == AttendanceStatus.excused:
                            student_data['total_excused'] += 1
                    
                    student_data['sessions'].append(session_data)
                
                # Calculate attendance percentage
                if len(sessions) > 0:
                    attended = student_data['total_attended'] + student_data['total_late'] * 0.5  # Late counts as half
                    student_data['attendance_percentage'] = round((attended / len(sessions)) * 100, 2)
                
                report['students'].append(student_data)
            
            return custom_response(
                success=True,
                data=report,
                status_code=200
            )

    def generate_tutor_teaching_report(self, tutor_id: str, start_date: str = None, end_date: str = None) -> Dict:
        """
        Generate a teaching report for a tutor
        
        Args:
            tutor_id: ID of the tutor
            start_date: Optional start date (ISO format)
            end_date: Optional end date (ISO format)
            
        Returns:
            Response with teaching report
        """
        with DatabaseContextManager() as ctx:
            # Get tutor info
            tutor = ctx.session.query(Tutor).filter(
                Tutor.id == tutor_id
            ).first()
            
            if not tutor:
                return custom_response(
                    success=False,
                    data="Tutor not found",
                    status_code=404
                )
            
            # Get all sessions for the tutor
            sessions_query = ctx.session.query(TeachingSession).filter(
                TeachingSession.tutor_id == tutor_id
            )
            
            # Apply date filters if provided
            if start_date:
                try:
                    start_date = date.fromisoformat(start_date)
                    sessions_query = sessions_query.filter(TeachingSession.start_time >= start_date)
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid start_date format. Use YYYY-MM-DD",
                        status_code=400
                    )
            
            if end_date:
                try:
                    end_date = date.fromisoformat(end_date)
                    sessions_query = sessions_query.filter(TeachingSession.start_time <= end_date + timedelta(days=1))
                except ValueError:
                    return custom_response(
                        success=False,
                        data="Invalid end_date format. Use YYYY-MM-DD",
                        status_code=400
                    )
            
            sessions = sessions_query.order_by(TeachingSession.start_time).all()
            
            # Get teaching logs
            logs = ctx.session.query(TutorTeachingLog).filter(
                TutorTeachingLog.tutor_id == tutor_id
            )
            
            if start_date:
                logs = logs.filter(TutorTeachingLog.checkin_time >= start_date)
            if end_date:
                logs = logs.filter(TutorTeachingLog.checkin_time <= end_date + timedelta(days=1))
            
            logs = logs.order_by(TutorTeachingLog.checkin_time).all()
            
            # Build the report
            report = {
                'tutor_id': tutor.id,
                'tutor_name': f"{tutor.first_name} {tutor.last_name}",
                'staff_id': tutor.staff_id,
                'department': tutor.department,
                'start_date': start_date.isoformat() if start_date else None,
                'end_date': end_date.isoformat() if end_date else None,
                'total_sessions': len(sessions),
                'completed_sessions': len([s for s in sessions if s.status == 'completed']),
                'verified_sessions': len([s for s in sessions if s.is_verified]),
                'total_teaching_hours': 0,
                'average_session_duration': 0,
                'courses': {},  # Will be keyed by course_id
                'monthly_breakdown': {},  # Will be keyed by year-month
                'verification_methods': {},  # Count of verification methods used
                'sessions': []
            }
            
            # Calculate total teaching hours and process sessions
            total_minutes = 0
            verification_methods = {}
            
            for session in sessions:
                # Calculate duration
                duration = (session.end_time - session.start_time).total_seconds() / 60
                total_minutes += duration
                
                # Track verification methods
                if session.tutor_checkin_method:
                    method = session.tutor_checkin_method.value
                    verification_methods[method] = verification_methods.get(method, 0) + 1
                
                # Add to courses breakdown
                course_id = session.course_id
                if course_id not in report['courses']:
                    report['courses'][course_id] = {
                        'course_id': course_id,
                        'course_title': session.course.title if session.course else 'Unknown',
                        'course_code': session.course.code if session.course else 'N/A',
                        'total_sessions': 0,
                        'total_hours': 0
                    }
                report['courses'][course_id]['total_sessions'] += 1
                report['courses'][course_id]['total_hours'] += duration / 60
                
                # Add to monthly breakdown
                month_key = session.start_time.strftime('%Y-%m')
                if month_key not in report['monthly_breakdown']:
                    report['monthly_breakdown'][month_key] = {
                        'year_month': month_key,
                        'total_sessions': 0,
                        'total_hours': 0
                    }
                report['monthly_breakdown'][month_key]['total_sessions'] += 1
                report['monthly_breakdown'][month_key]['total_hours'] += duration / 60
                
                # Add session details
                session_data = self._session_to_dict(session)
                session_data['duration_hours'] = round(duration / 60, 2)
                report['sessions'].append(session_data)
            
            # Calculate totals
            report['total_teaching_hours'] = round(total_minutes / 60, 2)
            report['average_session_duration'] = round(total_minutes / len(sessions) if sessions else 0, 2)
            report['verification_methods'] = verification_methods
            
            # Process teaching logs
            report['teaching_logs'] = []
            for log in logs:
                log_data = {
                    'log_id': log.id,
                    'session_id': log.session_id,
                    'checkin_time': log.checkin_time.isoformat() if log.checkin_time else None,
                    'checkout_time': log.checkout_time.isoformat() if log.checkout_time else None,
                    'verification_method': log.verification_method.value if log.verification_method else None,
                    'session_duration': log.session_duration,
                    'supervisor_review_status': log.supervisor_review_status,
                    'issues_encountered': log.issues_encountered
                }
                report['teaching_logs'].append(log_data)
            
            return custom_response(
                success=True,
                data=report,
                status_code=200
            )

    def _check_session_conflicts(self, ctx, session_data: Dict, exclude_session_id: str = None) -> Dict:
        """
        Check for conflicts with existing sessions, tutor availability, and other constraints
        
        Args:
            ctx: Database context
            session_data: Session data to check
            exclude_session_id: Optional ID of session to exclude from conflict checks
            
        Returns:
            Dictionary with conflict information
        """
        conflicts = []
        
        # Parse datetimes
        try:
            start_datetime = datetime.fromisoformat(session_data['start_datetime'])
            end_datetime = datetime.fromisoformat(session_data['end_datetime'])
            tutor_id = session_data['tutor_id']
            course_id = session_data['course_id']
            location = session_data.get('location')
            
            if end_datetime <= start_datetime:
                conflicts.append({
                    'type': SessionConflictType.OVERLAP.value,
                    'message': 'End datetime must be after start datetime',
                    'start_datetime': session_data['start_datetime'],
                    'end_datetime': session_data['end_datetime']
                })
                return {'has_conflicts': True, 'conflicts': conflicts}
        except ValueError as e:
            return {'has_conflicts': True, 'conflicts': [{
                'type': 'invalid_data',
                'message': str(e),
                'session': session_data
            }]}
        
        # Check tutor exists and is active
        tutor = ctx.session.query(Tutor).filter(
            Tutor.id == tutor_id,
            Tutor.is_active == True
        ).first()
        
        if not tutor:
            return {'has_conflicts': True, 'conflicts': [{
                'type': 'invalid_tutor',
                'message': 'Tutor not found or inactive'
            }]}
        
        # Check if tutor is on leave
        if tutor.is_on_leave and tutor.leave_start_date and tutor.leave_end_date:
            session_date = start_datetime.date()
            if tutor.leave_start_date <= session_date <= tutor.leave_end_date:
                conflicts.append({
                    'type': SessionConflictType.TUTOR_ON_LEAVE.value,
                    'message': 'Tutor is on leave during this time',
                    'start_datetime': session_data['start_datetime'],
                    'end_datetime': session_data['end_datetime'],
                    'leave_start': str(tutor.leave_start_date),
                    'leave_end': str(tutor.leave_end_date),
                    'leave_reason': tutor.leave_reason
                })
        
        # Check against tutor's timetable blocks
        overlapping_blocks = ctx.session.query(TimetableBlock).filter(
            TimetableBlock.tutor_id == tutor_id,
            TimetableBlock.day_of_week == start_datetime.weekday(),
            or_(
                and_(
                    TimetableBlock.recurring == True,
                    # Check if time overlaps with recurring block
                    TimetableBlock.start_time <= end_datetime.time(),
                    TimetableBlock.end_time >= start_datetime.time()
                ),
                and_(
                    TimetableBlock.recurring == False,
                    TimetableBlock.start_date <= end_datetime.date(),
                    TimetableBlock.end_date >= start_datetime.date(),
                    TimetableBlock.start_time <= end_datetime.time(),
                    TimetableBlock.end_time >= start_datetime.time()
                )
            )
        ).all()
        
        for block in overlapping_blocks:
            conflicts.append({
                'type': SessionConflictType.TIMETABLE_CONFLICT.value,
                'message': f"Overlaps with tutor's timetable block ({block.start_time.strftime('%H:%M')}-{block.end_time.strftime('%H:%M')})",
                'start_datetime': session_data['start_datetime'],
                'end_datetime': session_data['end_datetime'],
                'conflicting_block_id': block.id,
                'conflicting_course': block.course.title if block.course else 'Unknown',
                'conflicting_start': block.start_time.strftime('%H:%M'),
                'conflicting_end': block.end_time.strftime('%H:%M')
            })
        
        # Check against tutor's approved availability
        availabilities = ctx.session.query(TutorAvailability).filter(
            TutorAvailability.tutor_id == tutor_id,
            TutorAvailability.day_of_week == start_datetime.weekday(),
            TutorAvailability.is_approved == True
        ).all()
        
        is_available = False
        for avail in availabilities:
            if avail.start_time <= start_datetime.time() and avail.end_time >= end_datetime.time():
                if avail.is_recurring or (
                    avail.valid_from <= start_datetime.date() and
                    avail.valid_to >= end_datetime.date()
                ):
                    is_available = True
                    break
        
        if not is_available:
            conflicts.append({
                'type': SessionConflictType.TUTOR_UNAVAILABLE.value,
                'message': 'Session falls outside tutor approved availability',
                'start_datetime': session_data['start_datetime'],
                'end_datetime': session_data['end_datetime']
            })
        
        # Check for overlapping with existing sessions
        existing_sessions = ctx.session.query(TeachingSession).filter(
            or_(
                TeachingSession.tutor_id == tutor_id,
                TeachingSession.course_id == course_id,
                TeachingSession.location == location
            ) if location else or_(
                TeachingSession.tutor_id == tutor_id,
                TeachingSession.course_id == course_id
            ),
            TeachingSession.id != exclude_session_id if exclude_session_id else True,
            TeachingSession.status != 'cancelled',
            or_(
                # New session starts during existing session
                and_(
                    TeachingSession.start_time <= start_datetime,
                    TeachingSession.end_time >= start_datetime
                ),
                # New session ends during existing session
                and_(
                    TeachingSession.start_time <= end_datetime,
                    TeachingSession.end_time >= end_datetime
                ),
                # New session completely contains existing session
                and_(
                    TeachingSession.start_time >= start_datetime,
                    TeachingSession.end_time <= end_datetime
                )
            )
        ).all()
        
        for existing in existing_sessions:
            conflict_type = SessionConflictType.OVERLAP.value
            conflict_message = ""
            
            if existing.tutor_id == tutor_id:
                conflict_type = SessionConflictType.TUTOR_UNAVAILABLE.value
                conflict_message = f"Tutor already has a session at this time ({existing.start_datetime.strftime('%Y-%m-%d %H:%M')}-{existing.end_datetime.strftime('%H:%M')})"
            elif existing.course_id == course_id:
                conflict_type = SessionConflictType.COURSE_CONFLICT.value
                conflict_message = f"Course already has a session at this time ({existing.start_datetime.strftime('%Y-%m-%d %H:%M')}-{existing.end_datetime.strftime('%H:%M')})"
            elif existing.location == location and location:
                conflict_type = SessionConflictType.ROOM_CONFLICT.value
                conflict_message = f"Location already booked for another session at this time ({existing.start_datetime.strftime('%Y-%m-%d %H:%M')}-{existing.end_datetime.strftime('%H:%M')})"
            
            conflicts.append({
                'type': conflict_type,
                'message': conflict_message,
                'start_datetime': session_data['start_datetime'],
                'end_datetime': session_data['end_datetime'],
                'conflicting_session_id': existing.id,
                'conflicting_start': existing.start_datetime.strftime('%Y-%m-%d %H:%M'),
                'conflicting_end': existing.end_datetime.strftime('%H:%M'),
                'conflicting_course': existing.course.title if existing.course else 'Unknown',
                'conflicting_tutor': f"{existing.tutor.first_name} {existing.tutor.last_name}" if existing.tutor else 'Unknown',
                'conflicting_location': existing.location
            })
        
        return {
            'has_conflicts': len(conflicts) > 0,
            'conflicts': conflicts
        }

    def _session_to_dict(self, session: TeachingSession, include_details: bool = False) -> Dict:
        """Convert TeachingSession model to dictionary"""
        result = {
            'id': session.id,
            'course_id': session.course_id,
            'course_title': session.course.title if session.course else None,
            'course_code': session.course.code if session.course else None,
            'tutor_id': session.tutor_id,
            'tutor_name': f"{session.tutor.first_name} {session.tutor.last_name}" if session.tutor else "Unknown Tutor",
            'supervisor_tutor_id': session.supervisor_tutor_id,
            'supervisor_tutor_name': f"{session.supervisor_tutor.first_name} {session.supervisor_tutor.last_name}" if session.supervisor_tutor else None,
            'timetable_id': session.timetable_id,
            'room': session.room,
            'day_of_week': session.day_of_week,
            'day_name': ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][session.day_of_week] if session.day_of_week is not None else None,
            'start_time': session.start_time.strftime('%H:%M') if session.start_time else None,
            'end_time': session.end_time.strftime('%H:%M') if session.end_time else None,
            'duration_minutes': ((session.end_time.hour * 60 + session.end_time.minute) - (session.start_time.hour * 60 + session.start_time.minute)) if session.start_time and session.end_time else None,
            'status': session.status,
            'session_type': session.session_type,
            'recurring': session.recurring,
            'notes': session.notes,
            'created_at': session.created_at.isoformat() if session.created_at else None,
            'updated_at': session.updated_at.isoformat() if session.updated_at else None,
            'created_by': session.created_by,
            'creator_name': f"{session.creator.first_name} {session.creator.last_name}" if session.creator else None,
            'is_verified': session.is_verified,
            'verified_by': session.verified_by,
            'verifier_name': f"{session.verifier.first_name} {session.verifier.last_name}" if session.verifier else None,
            'verified_at': session.verified_at.isoformat() if session.verified_at else None,
            'verification_method': session.verification_method
        }
        
        if include_details:
            # Add additional details if needed
            pass
        
        return result

    def start_session(self, session_id: str, tutor_id: str) -> Dict:
        """
        Start a teaching session with verification measures
        
        Args:
            session_id: ID of the session to start
            tutor_id: ID of the tutor starting the session
            
        Returns:
            Response with updated session data
        """
        # Check if session can be started (10-minute rule)
        verification_result = continuous_session_manager.can_start_session(session_id)
        
        if not verification_result['can_start']:
            return custom_response(
                success=False,
                data={
                    'message': verification_result['reason'],
                    'error_code': verification_result['error_code'],
                    'earliest_start_time': verification_result.get('earliest_start_time'),
                    'current_time': verification_result.get('current_time')
                },
                status_code=400
            )
        
        with DatabaseContextManager() as ctx:
            # Get the session
            session = ctx.session.query(TeachingSession).filter(
                TeachingSession.id == session_id,
                TeachingSession.tutor_id == tutor_id
            ).first()
            
            if not session:
                return custom_response(
                    success=False,
                    data="Session not found or you don't have permission to start this session",
                    status_code=404
                )
            
            # Check if session can be started
            if session.status != 'scheduled':
                return custom_response(
                    success=False,
                    data=f"Cannot start session with status: {session.status}",
                    status_code=400
                )
            
            # Update session status to ongoing
            session.status = 'ongoing'
            session.updated_at = datetime.utcnow()
            
            try:
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    data=self._session_to_dict(session),
                    status_code=200
                )
            except Exception as e:
                ctx.session.rollback()
                return custom_response(
                    success=False,
                    data=f"Failed to start session: {str(e)}",
                    status_code=500
                )

    def end_session(self, session_id: str, tutor_id: str) -> Dict:
        """
        End a teaching session - change status from ongoing to completed
        
        Args:
            session_id: ID of the session to end
            tutor_id: ID of the tutor ending the session
            
        Returns:
            Response with updated session data
        """
        with DatabaseContextManager() as ctx:
            # Get the session
            session = ctx.session.query(TeachingSession).filter(
                TeachingSession.id == session_id,
                TeachingSession.tutor_id == tutor_id
            ).first()
            
            if not session:
                return custom_response(
                    success=False,
                    data="Session not found or you don't have permission to end this session",
                    status_code=404
                )
            
            # Check if session can be ended
            if session.status != 'ongoing':
                return custom_response(
                    success=False,
                    data=f"Cannot end session with status: {session.status}",
                    status_code=400
                )
            
            # Update session status to completed
            session.status = 'completed'
            session.updated_at = datetime.utcnow()
            
            try:
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    data=self._session_to_dict(session),
                    status_code=200
                )
            except Exception as e:
                ctx.session.rollback()
                return custom_response(
                    success=False,
                    data=f"Failed to end session: {str(e)}",
                    status_code=500
                )

    def get_session_attendees(self, session_id: str, tutor_id: str) -> Dict:
        """
        Get attendees for a specific session
        
        Args:
            session_id: ID of the session
            tutor_id: ID of the tutor (for permission check)
            
        Returns:
            Response with list of attendees
        """
        with DatabaseContextManager() as ctx:
            # Verify tutor has permission to view this session
            session = ctx.session.query(TeachingSession).filter(
                TeachingSession.id == session_id,
                TeachingSession.tutor_id == tutor_id
            ).first()
            
            if not session:
                return custom_response(
                    success=False,
                    data="Session not found or you don't have permission to view this session",
                    status_code=404
                )
            
            # Get attendance records for this session
            attendance_records = ctx.session.query(Attendance).filter(
                Attendance.session_id == session_id
            ).all()
            
            # Get enrolled students for this course
            enrolled_students = ctx.session.query(Enrollment).filter(
                Enrollment.course_id == session.course_id,
                Enrollment.status == 'active'
            ).all()
            
            # Create attendee list
            attendees = []
            attendance_dict = {att.student_id: att for att in attendance_records}
            
            for enrollment in enrolled_students:
                student = enrollment.student
                attendance = attendance_dict.get(student.id)
                
                attendee_data = {
                    'student_id': student.id,
                    'student_name': f"{student.first_name} {student.last_name}",
                    'student_id_number': student.student_id,
                    'email': student.email,
                    'phone': student.phone,
                    'attendance_status': attendance.status.value if attendance else 'absent',
                    'attendance_timestamp': attendance.timestamp.isoformat() if attendance else None,
                    'late_minutes': attendance.late_minutes if attendance else None,
                    'notes': attendance.notes if attendance else None
                }
                attendees.append(attendee_data)
            
            return custom_response(
                success=True,
                data={
                    'session': self._session_to_dict(session),
                    'attendees': attendees,
                    'total_enrolled': len(enrolled_students),
                    'present': len([a for a in attendees if a['attendance_status'] == 'present']),
                    'absent': len([a for a in attendees if a['attendance_status'] == 'absent']),
                    'late': len([a for a in attendees if a['attendance_status'] == 'late'])
                },
                status_code=200
            )

    def record_student_attendance(self, session_id: str, student_id: str, tutor_id: str, status: str, notes: str = None) -> Dict:
        """
        Record attendance for a specific student in a session
        
        Args:
            session_id: ID of the session
            student_id: ID of the student
            tutor_id: ID of the tutor recording attendance
            status: Attendance status (present, absent, late)
            notes: Optional notes
            
        Returns:
            Response with attendance record
        """
        with DatabaseContextManager() as ctx:
            # Verify tutor has permission to record attendance for this session
            session = ctx.session.query(TeachingSession).filter(
                TeachingSession.id == session_id,
                TeachingSession.tutor_id == tutor_id
            ).first()
            
            if not session:
                return custom_response(
                    success=False,
                    data="Session not found or you don't have permission to record attendance for this session",
                    status_code=404
                )
            
            # Verify student is enrolled in the course
            enrollment = ctx.session.query(Enrollment).filter(
                Enrollment.course_id == session.course_id,
                Enrollment.student_id == student_id,
                Enrollment.status == 'active'
            ).first()
            
            if not enrollment:
                return custom_response(
                    success=False,
                    data="Student is not enrolled in this course",
                    status_code=400
                )
            
            # Check if attendance already exists
            existing_attendance = ctx.session.query(Attendance).filter(
                Attendance.session_id == session_id,
                Attendance.student_id == student_id
            ).first()
            
            if existing_attendance:
                # Update existing attendance
                existing_attendance.status = AttendanceStatus(status)
                existing_attendance.timestamp = datetime.utcnow()
                existing_attendance.notes = notes
                existing_attendance.updated_at = datetime.utcnow()
                
                attendance_record = existing_attendance
            else:
                # Create new attendance record
                attendance_record = Attendance(
                    session_id=session_id,
                    student_id=student_id,
                    tutor_id=tutor_id,
                    status=AttendanceStatus(status),
                    timestamp=datetime.utcnow(),
                    notes=notes,
                    verification_method="Mannual"
                )
                ctx.session.add(attendance_record)
            
            try:
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    data=self._attendance_to_dict(attendance_record),
                    status_code=200
                )
            except Exception as e:
                ctx.session.rollback()
                return custom_response(
                    success=False,
                    data=f"Failed to record attendance: {str(e)}",
                    status_code=500
                )

    def get_ongoing_session_attendance(self, session_id: str, tutor_id: str) -> Dict:
        """
        Get attendance information for an ongoing session
        
        Args:
            session_id: ID of the session
            tutor_id: ID of the tutor (for permission check)
            
        Returns:
            Response with attendance data
        """
        # Verify tutor has permission
        with DatabaseContextManager() as ctx:
            session = ctx.session.query(TeachingSession).filter(
                TeachingSession.id == session_id,
                TeachingSession.tutor_id == tutor_id
            ).first()
            
            if not session:
                return custom_response(
                    success=False,
                    data="Session not found or you don't have permission to view this session",
                    status_code=404
                )
        
        # Use continuous session manager to get attendance
        result = continuous_session_manager.get_attendance_for_ongoing_session(session_id)
        
        if not result['success']:
            return custom_response(
                success=False,
                data=result['message'],
                status_code=400
            )
        
        return custom_response(
            success=True,
            data=result['data'],
            status_code=200
        )

    def record_bulk_attendance(self, session_id: str, tutor_id: str, attendance_data: List[Dict]) -> Dict:
        """
        Record attendance for multiple students in a session
        
        Args:
            session_id: ID of the session
            tutor_id: ID of the tutor recording attendance
            attendance_data: List of attendance records
            
        Returns:
            Response with success status and recorded attendance
        """
        result = continuous_session_manager.record_bulk_attendance(
            session_id, tutor_id, attendance_data
        )
        
        if result['success']:
            return custom_response(
                success=True,
                data={
                    'message': result['message'],
                    'recorded_count': result['recorded_count']
                },
                status_code=200
            )
        else:
            return custom_response(
                success=False,
                data=result['message'],
                status_code=400
            )

    def start_continuous_monitoring(self) -> Dict:
        """Start the continuous session monitoring system"""
        try:
            continuous_session_manager.start_monitoring()
            return custom_response(
                success=True,
                data="Continuous session monitoring started",
                status_code=200
            )
        except Exception as e:
            return custom_response(
                success=False,
                data=f"Failed to start monitoring: {str(e)}",
                status_code=500
            )

    def stop_continuous_monitoring(self) -> Dict:
        """Stop the continuous session monitoring system"""
        try:
            continuous_session_manager.stop_monitoring()
            return custom_response(
                success=True,
                data="Continuous session monitoring stopped",
                status_code=200
            )
        except Exception as e:
            return custom_response(
                success=False,
                data=f"Failed to stop monitoring: {str(e)}",
                status_code=500
            )

    def _attendance_to_dict(self, attendance: Attendance) -> Dict:
        """Convert Attendance model to dictionary"""
        return {
            'id': attendance.id,
            'session_id': attendance.session_id,
            'session_title': f"{attendance.session.course.code} - {attendance.session.session_type}" if attendance.session and attendance.session.course else None,
            'session_date': attendance.session.start_time.strftime('%Y-%m-%d') if attendance.session and attendance.session.start_time else None,
            'student_id': attendance.student_id,
            'student_name': f"{attendance.student.first_name} {attendance.student.last_name}" if attendance.student else None,
            'student_id_number': attendance.student.student_id if attendance.student else None,
            'tutor_id': attendance.tutor_id,
            'tutor_name': f"{attendance.tutor.first_name} {attendance.tutor.last_name}" if attendance.tutor else None,
            'status': attendance.status.value if attendance.status else None,
            'timestamp': attendance.timestamp.isoformat() if attendance.timestamp else None,
            'notes': attendance.notes,
            'late_minutes': attendance.late_minutes,
            'device_used': attendance.device_used,
            'ip_address': attendance.ip_address,
            'approved_by': attendance.approved_by,
            'approver_name': f"{attendance.approver.first_name} {attendance.approver.last_name}" if attendance.approver else None,
            'approval_date': attendance.approval_date.isoformat() if attendance.approval_date else None,
            'approval_notes': attendance.approval_notes,
            'is_disputed': attendance.is_disputed,
            'dispute_reason': attendance.dispute_reason,
            'dispute_resolved_by': attendance.dispute_resolved_by,
            'dispute_resolver_name': f"{attendance.dispute_resolver.first_name} {attendance.dispute_resolver.last_name}" if attendance.dispute_resolver else None,
            'dispute_resolution_date': attendance.dispute_resolution_date.isoformat() if attendance.dispute_resolution_date else None,
            'resolution_notes': attendance.resolution_notes,
            'verification_method': attendance.verification_method.value if attendance.verification_method else None
        }

    def _notify_about_new_session(self, session: TeachingSession) -> None:
        """Send notifications about a newly created session"""
        with DatabaseContextManager() as ctx:
            # Notify tutor
            tutor = ctx.session.query(Tutor).filter(
                Tutor.id == session.tutor_id
            ).first()
            
            if tutor and tutor.notification_preference and tutor.notification_preference.receive_email:
                subject = f"New Teaching Session Scheduled: {session.title}"
                
                message = f"""
                <html>
                    <body>
                        <h2>New Teaching Session</h2>
                        <p>Hello {tutor.first_name},</p>
                        
                        <p>A new teaching session has been scheduled for you:</p>
                        
                        <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; margin: 15px 0;">
                            <p><strong>Title:</strong> {session.title}</p>
                            <p><strong>Course:</strong> {session.course.title if session.course else 'N/A'}</p>
                            <p><strong>Date:</strong> {session.start_time.strftime('%A, %B %d, %Y')}</p>
                            <p><strong>Time:</strong> {session.start_time.strftime('%H:%M')} - {session.end_time.strftime('%H:%M')}</p>
                            <p><strong>Location:</strong> {session.location or 'TBD'}</p>
                            <p><strong>Type:</strong> {session.session_type}</p>
                        </div>
                        
                        <p>Please prepare any necessary materials and arrive on time.</p>
                        
                        <div style="text-align: center; margin-top: 20px;">
                            <a href="{current_app.config['FRONTEND_URL']}/sessions/{session.id}" 
                            style="background-color: #3182ce; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px;">
                                View Session Details
                            </a>
                        </div>
                        
                        <p>Best regards,<br>
                        {current_app.config['APP_NAME']} Team</p>
                    </body>
                </html>
                """
                
                try:
                    send_email(
                        sender_email=current_app.config['MAIL_SENDER'],
                        sender_password=current_app.config['MAIL_PASSWORD'],
                        receiver_email=tutor.email,
                        subject=subject,
                        message=message
                    )
                except Exception as e:
                    current_app.logger.error(f"Failed to send session notification to tutor {tutor.id}: {str(e)}")
            
            # Notify enrolled students
            students = ctx.session.query(Student).join(
                Enrollment,
                Student.id == Enrollment.student_id
            ).filter(
                Enrollment.course_id == session.course_id,
                Enrollment.status == 'active',
                Student.notification_preference.receive_email == True
            ).all()
            
            for student in students:
                subject = f"New Session Scheduled for {session.course.title if session.course else 'Your Course'}"
                
                message = f"""
                <html>
                    <body>
                        <h2>Upcoming Session</h2>
                        <p>Hello {student.first_name},</p>
                        
                        <p>A new session has been scheduled for your course:</p>
                        
                        <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; margin: 15px 0;">
                            <p><strong>Title:</strong> {session.title}</p>
                            <p><strong>Course:</strong> {session.course.title if session.course else 'N/A'}</p>
                            <p><strong>Date:</strong> {session.start_time.strftime('%A, %B %d, %Y')}</p>
                            <p><strong>Time:</strong> {session.start_time.strftime('%H:%M')} - {session.end_time.strftime('%H:%M')}</p>
                            <p><strong>Location:</strong> {session.location or 'TBD'}</p>
                            <p><strong>Tutor:</strong> {session.tutor.first_name} {session.tutor.last_name if session.tutor else 'N/A'}</p>
                            <p><strong>Mandatory:</strong> {'Yes' if session.is_mandatory else 'No'}</p>
                        </div>
                        
                        <p>Please mark your calendar and prepare any required materials.</p>
                        
                        <div style="text-align: center; margin-top: 20px;">
                            <a href="{current_app.config['FRONTEND_URL']}/sessions/{session.id}" 
                            style="background-color: #3182ce; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px;">
                                View Session Details
                            </a>
                        </div>
                        
                        <p>Best regards,<br>
                        {current_app.config['APP_NAME']} Team</p>
                    </body>
                </html>
                """
                
                try:
                    send_email(
                        sender_email=current_app.config['MAIL_SENDER'],
                        sender_password=current_app.config['MAIL_PASSWORD'],
                        receiver_email=student.email,
                        subject=subject,
                        message=message
                    )
                except Exception as e:
                    current_app.logger.error(f"Failed to send session notification to student {student.id}: {str(e)}")

    def _notify_about_session_status_change(self, session: TeachingSession) -> None:
        """Send notifications when a session's status changes"""
        with DatabaseContextManager() as ctx:
            # Notify tutor
            tutor = ctx.session.query(Tutor).filter(
                Tutor.id == session.tutor_id
            ).first()
            
            if tutor and tutor.notification_preference and tutor.notification_preference.receive_email:
                subject = f"Session Status Update: {session.title}"
                
                if session.status == 'cancelled':
                    status_message = f"Cancelled (Reason: {session.cancellation_reason or 'Not specified'})"
                else:
                    status_message = session.status.capitalize()
                
                message = f"""
                <html>
                    <body>
                        <h2>Session Status Update</h2>
                        <p>Hello {tutor.first_name},</p>
                        
                        <p>The status of your teaching session has been updated:</p>
                        
                        <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; margin: 15px 0;">
                            <p><strong>Title:</strong> {session.title}</p>
                            <p><strong>Course:</strong> {session.course.title if session.course else 'N/A'}</p>
                            <p><strong>Date:</strong> {session.start_time.strftime('%A, %B %d, %Y')}</p>
                            <p><strong>Time:</strong> {session.start_time.strftime('%H:%M')} - {session.end_time.strftime('%H:%M')}</p>
                            <p><strong>New Status:</strong> {status_message}</p>
                        </div>
                        
                        <div style="text-align: center; margin-top: 20px;">
                            <a href="{current_app.config['FRONTEND_URL']}/sessions/{session.id}" 
                            style="background-color: #3182ce; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px;">
                                View Session Details
                            </a>
                        </div>
                        
                        <p>Best regards,<br>
                        {current_app.config['APP_NAME']} Team</p>
                    </body>
                </html>
                """
                
                try:
                    send_email(
                        sender_email=current_app.config['MAIL_SENDER'],
                        sender_password=current_app.config['MAIL_PASSWORD'],
                        receiver_email=tutor.email,
                        subject=subject,
                        message=message
                    )
                except Exception as e:
                    current_app.logger.error(f"Failed to send session status notification to tutor {tutor.id}: {str(e)}")
            
            # Notify enrolled students if session is cancelled
            if session.status == 'cancelled':
                students = ctx.session.query(Student).join(
                    Enrollment,
                    Student.id == Enrollment.student_id
                ).filter(
                    Enrollment.course_id == session.course_id,
                    Enrollment.status == 'active',
                    Student.notification_preference.receive_email == True
                ).all()
                
                for student in students:
                    subject = f"Session Cancelled: {session.title}"
                    
                    message = f"""
                    <html>
                        <body>
                            <h2>Session Cancellation Notice</h2>
                            <p>Hello {student.first_name},</p>
                            
                            <p>The following session has been cancelled:</p>
                            
                            <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; margin: 15px 0;">
                                <p><strong>Title:</strong> {session.title}</p>
                                <p><strong>Course:</strong> {session.course.title if session.course else 'N/A'}</p>
                                <p><strong>Date:</strong> {session.start_time.strftime('%A, %B %d, %Y')}</p>
                                <p><strong>Time:</strong> {session.start_time.strftime('%H:%M')} - {session.end_time.strftime('%H:%M')}</p>
                                <p><strong>Reason:</strong> {session.cancellation_reason or 'Not specified'}</p>
                            </div>
                            
                            <p>Please check with your tutor or course coordinator for any rescheduled sessions or alternative arrangements.</p>
                            
                            <div style="text-align: center; margin-top: 20px;">
                                <a href="{current_app.config['FRONTEND_URL']}/course/{session.course_id}" 
                                style="background-color: #3182ce; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px;">
                                    View Course Details
                                </a>
                            </div>
                            
                            <p>Best regards,<br>
                            {current_app.config['APP_NAME']} Team</p>
                        </body>
                    </html>
                    """
                    
                    try:
                        send_email(
                            sender_email=current_app.config['MAIL_SENDER'],
                            sender_password=current_app.config['MAIL_PASSWORD'],
                            receiver_email=student.email,
                            subject=subject,
                            message=message
                        )
                    except Exception as e:
                        current_app.logger.error(f"Failed to send cancellation notice to student {student.id}: {str(e)}")

    def _notify_tutor_about_verification(self, session: TeachingSession) -> None:
        """Send notification to tutor about session verification"""
        with DatabaseContextManager() as ctx:
            tutor = ctx.session.query(Tutor).filter(
                Tutor.id == session.tutor_id
            ).first()
            
            if not tutor or not tutor.notification_preference or not tutor.notification_preference.receive_email:
                return
            
            subject = f"Session Verification: {session.title}"
            
            if session.is_verified:
                status_message = "verified"
                details = f"""
                <p>Your session has been successfully verified by {session.verifier.first_name} {session.verifier.last_name}.</p>
                <p><strong>Verification Method:</strong> {session.verification_method.value if session.verification_method else 'N/A'}</p>
                """
            else:
                status_message = "requires review"
                details = f"""
                <p>Your session has been marked as requiring review by {session.verifier.first_name} {session.verifier.last_name}.</p>
                <p><strong>Supervisor Notes:</strong> {session.supervisor_notes or 'None'}</p>
                <p>Please follow up with your supervisor for more information.</p>
                """
            
            message = f"""
            <html>
                <body>
                    <h2>Session Verification Update</h2>
                    <p>Hello {tutor.first_name},</p>
                    
                    <p>Your teaching session has been {status_message}:</p>
                    
                    <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; margin: 15px 0;">
                        <p><strong>Title:</strong> {session.title}</p>
                        <p><strong>Course:</strong> {session.course.title if session.course else 'N/A'}</p>
                        <p><strong>Date:</strong> {session.start_time.strftime('%A, %B %d, %Y')}</p>
                        <p><strong>Duration:</strong> {(session.end_time - session.start_time).total_seconds() / 3600:.1f} hours</p>
                        <p><strong>Status:</strong> {session.status.capitalize()}</p>
                    </div>
                    
                    {details}
                    
                    <div style="text-align: center; margin-top: 20px;">
                        <a href="{current_app.config['FRONTEND_URL']}/sessions/{session.id}" 
                        style="background-color: #3182ce; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px;">
                            View Session Details
                        </a>
                    </div>
                    
                    <p>Best regards,<br>
                    {current_app.config['APP_NAME']} Team</p>
                </body>
            </html>
            """
            
            try:
                send_email(
                    sender_email=current_app.config['MAIL_SENDER'],
                    sender_password=current_app.config['MAIL_PASSWORD'],
                    receiver_email=tutor.email,
                    subject=subject,
                    message=message
                )
            except Exception as e:
                current_app.logger.error(f"Failed to send verification notification to tutor {tutor.id}: {str(e)}")

    # Makeup Session Methods
    def get_makeup_sessions_for_tutor(self, tutor_id: str, start_date: str = None, end_date: str = None, status: str = None) -> Dict:
        """Get makeup sessions for a specific tutor"""
        try:
            with DatabaseContextManager() as ctx:
                query = ctx.session.query(MakeupSession).filter(MakeupSession.tutor_id == tutor_id)
                
                # Apply date filters
                if start_date:
                    query = query.filter(MakeupSession.session_date >= datetime.strptime(start_date, '%Y-%m-%d').date())
                if end_date:
                    query = query.filter(MakeupSession.session_date <= datetime.strptime(end_date, '%Y-%m-%d').date())
                
                # Apply status filter
                if status:
                    query = query.filter(MakeupSession.status == status)
                
                # Join with related tables
                query = query.join(Course, MakeupSession.course_id == Course.id)
                query = query.join(Tutor, MakeupSession.tutor_id == Tutor.id)
                
                sessions = query.all()
                
                # Serialize sessions
                sessions_data = []
                for session in sessions:
                    session_data = {
                        'id': session.id,
                        'daily_session_id': session.daily_session_id,
                        'timetable_block_id': session.timetable_block_id,
                        'course_id': session.course_id,
                        'tutor_id': session.tutor_id,
                        'session_date': session.session_date.isoformat() if session.session_date else None,
                        'start_time': session.start_time.isoformat() if session.start_time else None,
                        'end_time': session.end_time.isoformat() if session.end_time else None,
                        'room': session.room,
                        'session_type': session.session_type,
                        'status': session.status,
                        'reason': session.reason,
                        'original_session_date': session.original_session_date.isoformat() if session.original_session_date else None,
                        'is_dynamic_block': session.is_dynamic_block,
                        'conflict_resolved': session.conflict_resolved,
                        'created_at': session.created_at.isoformat() if session.created_at else None,
                        'updated_at': session.updated_at.isoformat() if session.updated_at else None,
                        'created_by': session.created_by,
                        'is_verified': session.is_verified,
                        'verified_by': session.verified_by,
                        'verified_at': session.verified_at.isoformat() if session.verified_at else None,
                        'verification_method': session.verification_method,
                        'notes': session.notes,
                        'attendance_taken': session.attendance_taken,
                        'course': {
                            'id': session.course.id,
                            'title': session.course.title,
                            'code': session.course.code,
                            'department': getattr(session.course, 'department', 'General')
                        } if session.course else None,
                        'tutor': {
                            'id': session.tutor.id,
                            'first_name': session.tutor.first_name,
                            'last_name': session.tutor.last_name,
                            'staff_id': getattr(session.tutor, 'staff_id', 'N/A')
                        } if session.tutor else None
                    }
                    sessions_data.append(session_data)
                
                return custom_response(
                    success=True,
                    data=sessions_data
                )
                
        except Exception as e:
            current_app.logger.error(f"Error getting makeup sessions for tutor {tutor_id}: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to get makeup sessions: {str(e)}",
                status_code=500
            )

    def get_makeup_sessions_for_course(self, course_id: str, start_date: str = None, end_date: str = None, status: str = None) -> Dict:
        """Get makeup sessions for a specific course"""
        try:
            with DatabaseContextManager() as ctx:
                query = ctx.session.query(MakeupSession).filter(MakeupSession.course_id == course_id)
                
                # Apply date filters
                if start_date:
                    query = query.filter(MakeupSession.session_date >= datetime.strptime(start_date, '%Y-%m-%d').date())
                if end_date:
                    query = query.filter(MakeupSession.session_date <= datetime.strptime(end_date, '%Y-%m-%d').date())
                
                # Apply status filter
                if status:
                    query = query.filter(MakeupSession.status == status)
                
                sessions = query.all()
                
                # Serialize sessions (similar to tutor method)
                sessions_data = []
                for session in sessions:
                    session_data = {
                        'id': session.id,
                        'daily_session_id': session.daily_session_id,
                        'timetable_block_id': session.timetable_block_id,
                        'course_id': session.course_id,
                        'tutor_id': session.tutor_id,
                        'session_date': session.session_date.isoformat() if session.session_date else None,
                        'start_time': session.start_time.isoformat() if session.start_time else None,
                        'end_time': session.end_time.isoformat() if session.end_time else None,
                        'room': session.room,
                        'session_type': session.session_type,
                        'status': session.status,
                        'reason': session.reason,
                        'original_session_date': session.original_session_date.isoformat() if session.original_session_date else None,
                        'is_dynamic_block': session.is_dynamic_block,
                        'conflict_resolved': session.conflict_resolved,
                        'created_at': session.created_at.isoformat() if session.created_at else None,
                        'updated_at': session.updated_at.isoformat() if session.updated_at else None,
                        'created_by': session.created_by,
                        'is_verified': session.is_verified,
                        'verified_by': session.verified_by,
                        'verified_at': session.verified_at.isoformat() if session.verified_at else None,
                        'verification_method': session.verification_method,
                        'notes': session.notes,
                        'attendance_taken': session.attendance_taken
                    }
                    sessions_data.append(session_data)
                
                return custom_response(
                    success=True,
                    data=sessions_data
                )
                
        except Exception as e:
            current_app.logger.error(f"Error getting makeup sessions for course {course_id}: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to get makeup sessions: {str(e)}",
                status_code=500
            )

    def create_makeup_session(self, payload: Dict) -> Dict:
        """Create a new makeup session"""
        try:
            with DatabaseContextManager() as ctx:
                # Validate required fields
                required_fields = ['course_id', 'tutor_id', 'session_date', 'start_time', 'end_time', 'room', 'session_type']
                for field in required_fields:
                    if field not in payload:
                        return custom_response(
                            success=False,
                            data=f"Missing required field: {field}",
                            status_code=400
                        )
                
                # Create makeup session
                makeup_session = MakeupSession(
                    id=str(uuid.uuid4()),
                    daily_session_id=payload.get('daily_session_id'),
                    timetable_block_id=payload.get('timetable_block_id'),
                    course_id=payload['course_id'],
                    tutor_id=payload['tutor_id'],
                    session_date=datetime.strptime(payload['session_date'], '%Y-%m-%d').date(),
                    start_time=datetime.strptime(payload['start_time'], '%H:%M').time(),
                    end_time=datetime.strptime(payload['end_time'], '%H:%M').time(),
                    room=payload['room'],
                    session_type=payload['session_type'],
                    status=payload.get('status', 'scheduled'),
                    reason=payload.get('reason', 'Makeup session'),
                    original_session_date=datetime.strptime(payload['original_session_date'], '%Y-%m-%d').date() if payload.get('original_session_date') else None,
                    is_dynamic_block=payload.get('is_dynamic_block', False),
                    conflict_resolved=payload.get('conflict_resolved', False),
                    created_by=payload.get('created_by'),
                    is_verified=False,
                    notes=payload.get('notes'),
                    attendance_taken=False
                )
                
                ctx.session.add(makeup_session)
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    data={'id': makeup_session.id},
                    status_code=201
                )
                
        except Exception as e:
            current_app.logger.error(f"Error creating makeup session: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to create makeup session: {str(e)}",
                status_code=500
            )

    def get_makeup_session(self, session_id: str) -> Dict:
        """Get a specific makeup session"""
        try:
            with DatabaseContextManager() as ctx:
                session = ctx.session.query(MakeupSession).filter(MakeupSession.id == session_id).first()
                
                if not session:
                    return custom_response(
                        success=False,
                        data="Makeup session not found",
                        status_code=404
                    )
                
                session_data = {
                    'id': session.id,
                    'daily_session_id': session.daily_session_id,
                    'timetable_block_id': session.timetable_block_id,
                    'course_id': session.course_id,
                    'tutor_id': session.tutor_id,
                    'session_date': session.session_date.isoformat() if session.session_date else None,
                    'start_time': session.start_time.isoformat() if session.start_time else None,
                    'end_time': session.end_time.isoformat() if session.end_time else None,
                    'room': session.room,
                    'session_type': session.session_type,
                    'status': session.status,
                    'reason': session.reason,
                    'original_session_date': session.original_session_date.isoformat() if session.original_session_date else None,
                    'is_dynamic_block': session.is_dynamic_block,
                    'conflict_resolved': session.conflict_resolved,
                    'created_at': session.created_at.isoformat() if session.created_at else None,
                    'updated_at': session.updated_at.isoformat() if session.updated_at else None,
                    'created_by': session.created_by,
                    'is_verified': session.is_verified,
                    'verified_by': session.verified_by,
                    'verified_at': session.verified_at.isoformat() if session.verified_at else None,
                    'verification_method': session.verification_method,
                    'notes': session.notes,
                    'attendance_taken': session.attendance_taken
                }
                
                return custom_response(
                    success=True,
                    data=session_data
                )
                
        except Exception as e:
            current_app.logger.error(f"Error getting makeup session {session_id}: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to get makeup session: {str(e)}",
                status_code=500
            )

    def update_makeup_session(self, session_id: str, payload: Dict) -> Dict:
        """Update a makeup session"""
        try:
            with DatabaseContextManager() as ctx:
                session = ctx.session.query(MakeupSession).filter(MakeupSession.id == session_id).first()
                
                if not session:
                    return custom_response(
                        success=False,
                        data="Makeup session not found",
                        status_code=404
                    )
                
                # Update fields
                if 'session_date' in payload:
                    session.session_date = datetime.strptime(payload['session_date'], '%Y-%m-%d').date()
                if 'start_time' in payload:
                    session.start_time = datetime.strptime(payload['start_time'], '%H:%M').time()
                if 'end_time' in payload:
                    session.end_time = datetime.strptime(payload['end_time'], '%H:%M').time()
                if 'room' in payload:
                    session.room = payload['room']
                if 'session_type' in payload:
                    session.session_type = payload['session_type']
                if 'status' in payload:
                    session.status = payload['status']
                if 'reason' in payload:
                    session.reason = payload['reason']
                if 'notes' in payload:
                    session.notes = payload['notes']
                
                session.updated_at = datetime.utcnow()
                
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    data={'id': session.id}
                )
                
        except Exception as e:
            current_app.logger.error(f"Error updating makeup session {session_id}: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to update makeup session: {str(e)}",
                status_code=500
            )

    def delete_makeup_session(self, session_id: str) -> Dict:
        """Delete a makeup session"""
        try:
            with DatabaseContextManager() as ctx:
                session = ctx.session.query(MakeupSession).filter(MakeupSession.id == session_id).first()
                
                if not session:
                    return custom_response(
                        success=False,
                        data="Makeup session not found",
                        status_code=404
                    )
                
                ctx.session.delete(session)
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    message="Makeup session deleted successfully"
                )
                
        except Exception as e:
            current_app.logger.error(f"Error deleting makeup session {session_id}: {str(e)}")
            return custom_response(
                success=False,
                message=f"Failed to delete makeup session: {str(e)}"
            ), 500

    def cancel_makeup_session(self, session_id: str) -> Dict:
        """Cancel a makeup session"""
        try:
            with DatabaseContextManager() as ctx:
                session = ctx.session.query(MakeupSession).filter(MakeupSession.id == session_id).first()
                
                if not session:
                    return custom_response(
                        success=False,
                        data="Makeup session not found",
                        status_code=404
                    )
                
                session.status = 'cancelled'
                session.updated_at = datetime.utcnow()
                
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    message="Makeup session cancelled successfully",
                    data={'id': session.id}
                )
                
        except Exception as e:
            current_app.logger.error(f"Error cancelling makeup session {session_id}: {str(e)}")
            return custom_response(
                success=False,
                message=f"Failed to cancel makeup session: {str(e)}"
            ), 500

    def send_makeup_session_reminders(self, session_id: str, requester_id: str, requester_type: str = 'tutor') -> Dict:
        """Send reminders for a makeup session"""
        try:
            with DatabaseContextManager() as ctx:
                session = ctx.session.query(MakeupSession).filter(MakeupSession.id == session_id).first()
                
                if not session:
                    return custom_response(
                        success=False,
                        data="Makeup session not found",
                        status_code=404
                    )
                
                # Get course and tutor info
                course = ctx.session.query(Course).filter(Course.id == session.course_id).first()
                tutor = ctx.session.query(Tutor).filter(Tutor.id == session.tutor_id).first()
                
                if not course or not tutor:
                    return custom_response(
                        success=False,
                        message="Course or tutor not found"
                    ), 404
                
                # Send email reminders (simplified version)
                subject = f"Makeup Session Reminder - {course.title}"
                message = f"""
                <html>
                    <body>
                        <h2>Makeup Session Reminder</h2>
                        <p>Dear {tutor.first_name},</p>
                        <p>This is a reminder about your upcoming makeup session:</p>
                        
                        <div style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; margin: 15px 0;">
                            <p><strong>Course:</strong> {course.title}</p>
                            <p><strong>Date:</strong> {session.session_date}</p>
                            <p><strong>Time:</strong> {session.start_time} - {session.end_time}</p>
                            <p><strong>Room:</strong> {session.room}</p>
                            <p><strong>Reason:</strong> {session.reason}</p>
                        </div>
                        
                        <p>Please ensure you're prepared for this makeup session.</p>
                        
                        <p>Best regards,<br>
                        Kisiwa Tech Team</p>
                    </body>
                </html>
                """
                
                try:
                    send_email(
                        sender_email='kisiwa@mutabletech.co.ke',
                        sender_password='z}Y{WN$jV=Sv',
                        receiver_email=tutor.email,
                        subject=subject,
                        message=message
                    )
                    
                    return custom_response(
                        success=True,
                        message="Reminders sent successfully",
                        data={
                            'tutors_notified': 1,
                            'supervisors_notified': 0,
                            'students_notified': 0,
                            'reminders_sent': 1
                        }
                    )
                    
                except Exception as email_error:
                    current_app.logger.error(f"Failed to send email reminder: {str(email_error)}")
                    return custom_response(
                        success=False,
                        message=f"Failed to send reminders: {str(email_error)}"
                    ), 500
                
        except Exception as e:
            current_app.logger.error(f"Error sending makeup session reminders {session_id}: {str(e)}")
            return custom_response(
                success=False,
                message=f"Failed to send reminders: {str(e)}"
            ), 500

    def send_bulk_makeup_session_reminders(self, session_ids: List[str], requester_id: str, requester_type: str = 'tutor') -> Dict:
        """Send bulk reminders for multiple makeup sessions"""
        try:
            successful_count = 0
            failed_count = 0
            
            for session_id in session_ids:
                try:
                    result = self.send_makeup_session_reminders(session_id, requester_id, requester_type)
                    if result[0].get('success'):
                        successful_count += 1
                    else:
                        failed_count += 1
                except Exception:
                    failed_count += 1
            
            return custom_response(
                success=True,
                message=f"Bulk reminders completed: {successful_count} successful, {failed_count} failed",
                data={
                    'successful_count': successful_count,
                    'failed_count': failed_count,
                    'total_sessions': len(session_ids)
                }
            )
            
        except Exception as e:
            current_app.logger.error(f"Error sending bulk makeup session reminders: {str(e)}")
            return custom_response(
                success=False,
                message=f"Failed to send bulk reminders: {str(e)}"
            ), 500

    # Daily Teaching Sessions Methods
    def get_daily_sessions_for_user(self, user_id, start_date=None, end_date=None, status=None, include_course=False, include_tutor=False):
        """Get daily teaching sessions for a user (any role)"""
        try:
            with DatabaseContextManager() as ctx:
                query = ctx.session.query(DailyTeachingSession)
                
                # Join with course if requested
                if include_course:
                    query = query.join(Course, DailyTeachingSession.course_id == Course.id)
                
                # Join with tutor if requested
                if include_tutor:
                    query = query.join(User, DailyTeachingSession.tutor_id == User.id)
                
                # Filter by user - check if user is tutor, student, or supervisor
                from src.models.models import Student, Supervisor, Tutor
                
                # Check if user is a tutor
                tutor = ctx.session.query(Tutor).filter(Tutor.id == user_id).first()
                if tutor:
                    query = query.filter(DailyTeachingSession.tutor_id == user_id)
                else:
                    # Check if user is a student
                    student = ctx.session.query(Student).filter(Student.id == user_id).first()
                    if student:
                        # Get courses the student is enrolled in
                        from src.models.models import enrollment_courses
                        enrolled_courses = ctx.session.query(enrollment_courses.c.course_id).join(
                            Enrollment, enrollment_courses.c.enrollment_id == Enrollment.id
                        ).filter(Enrollment.student_id == student.id).subquery()
                        query = query.filter(DailyTeachingSession.course_id.in_(enrolled_courses))
                    else:
                        # Check if user is a supervisor
                        supervisor = ctx.session.query(Supervisor).filter(Supervisor.id == user_id).first()
                        if supervisor:
                            # Get courses in supervisor's department
                            from src.models.models import SupervisorDepartment
                            dept_courses = ctx.session.query(Course.id).join(
                                SupervisorDepartment, Course.department == SupervisorDepartment.department_name
                            ).filter(SupervisorDepartment.supervisor_id == supervisor.id).subquery()
                            query = query.filter(DailyTeachingSession.course_id.in_(dept_courses))
                        else:
                            # User not found in any role
                            return custom_response(
                                success=False,
                                data="User not found or has no assigned role"
                            ), 404
                
                # Apply filters
                if start_date:
                    query = query.filter(DailyTeachingSession.session_date >= start_date)
                if end_date:
                    query = query.filter(DailyTeachingSession.session_date <= end_date)
                if status:
                    query = query.filter(DailyTeachingSession.status == status)
                
                # Order by date and time
                query = query.order_by(DailyTeachingSession.session_date.desc(), DailyTeachingSession.start_time.desc())
                
                sessions = query.all()
                
                # Serialize sessions
                session_data = []
                for session in sessions:
                    session_dict = {
                        'id': session.id,
                        'timetable_block_id': session.timetable_block_id,
                        'teaching_session_id': getattr(session, 'teaching_session_id', None),
                        'course_id': session.course_id,
                        'tutor_id': session.tutor_id,
                        'session_date': session.session_date.isoformat() if session.session_date else None,
                        'start_time': session.start_time.isoformat() if session.start_time else None,
                        'end_time': session.end_time.isoformat() if session.end_time else None,
                        'room': session.room,
                        'session_type': session.session_type,
                        'status': session.status,
                        'created_at': session.created_at.isoformat() if session.created_at else None,
                        'updated_at': session.updated_at.isoformat() if session.updated_at else None,
                        'created_by': session.created_by,
                        'is_verified': session.is_verified,
                        'verified_by': session.verified_by,
                        'verified_at': session.verified_at.isoformat() if session.verified_at else None,
                        'verification_method': session.verification_method,
                        'notes': session.notes,
                        'attendance_taken': session.attendance_taken
                    }
                    
                    # Add course information if requested
                    if include_course and hasattr(session, 'course'):
                        session_dict['course'] = {
                            'id': session.course.id,
                            'title': session.course.title,
                            'code': session.course.code,
                            'department': session.course.department
                        }
                    
                    # Add tutor information if requested
                    if include_tutor and hasattr(session, 'tutor'):
                        session_dict['tutor'] = {
                            'id': session.tutor.id,
                            'name': f"{session.tutor.first_name} {session.tutor.last_name}",
                            'email': session.tutor.email
                        }
                    
                    session_data.append(session_dict)
                
                return custom_response(
                    success=True,
                    data=session_data
                )
                
        except Exception as e:
            current_app.logger.error(f"Error getting daily sessions for user: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to retrieve daily sessions: {str(e)}"
            ), 500

    def get_daily_sessions_for_tutor(self, tutor_id, start_date=None, end_date=None, status=None, include_course=False, include_tutor=False):
        """Get daily teaching sessions for a specific tutor"""
        try:
            with DatabaseContextManager() as ctx:
                query = DailyTeachingSession.safe_query(ctx.session).filter(DailyTeachingSession.tutor_id == tutor_id)
                
                # Join with course if requested
                if include_course:
                    query = query.join(Course, DailyTeachingSession.course_id == Course.id)
                
                # Join with tutor if requested
                if include_tutor:
                    query = query.join(User, DailyTeachingSession.tutor_id == User.id)
                
                # Apply filters
                if start_date:
                    query = query.filter(DailyTeachingSession.session_date >= start_date)
                if end_date:
                    query = query.filter(DailyTeachingSession.session_date <= end_date)
                if status:
                    query = query.filter(DailyTeachingSession.status == status)
                
                # Order by date and time
                query = query.order_by(DailyTeachingSession.session_date.desc(), DailyTeachingSession.start_time.desc())
                
                sessions = query.all()
                
                # Serialize sessions (same as above)
                session_data = []
                for session in sessions:
                    session_dict = {
                        'id': session.id,
                        'timetable_block_id': session.timetable_block_id,
                        'teaching_session_id': getattr(session, 'teaching_session_id', None),
                        'course_id': session.course_id,
                        'tutor_id': session.tutor_id,
                        'session_date': session.session_date.isoformat() if session.session_date else None,
                        'start_time': session.start_time.isoformat() if session.start_time else None,
                        'end_time': session.end_time.isoformat() if session.end_time else None,
                        'room': session.room,
                        'session_type': session.session_type,
                        'status': session.status,
                        'created_at': session.created_at.isoformat() if session.created_at else None,
                        'updated_at': session.updated_at.isoformat() if session.updated_at else None,
                        'created_by': session.created_by,
                        'is_verified': session.is_verified,
                        'verified_by': session.verified_by,
                        'verified_at': session.verified_at.isoformat() if session.verified_at else None,
                        'verification_method': session.verification_method,
                        'notes': session.notes,
                        'attendance_taken': session.attendance_taken
                    }
                    
                    # Add course information if requested
                    if include_course and hasattr(session, 'course'):
                        session_dict['course'] = {
                            'id': session.course.id,
                            'title': session.course.title,
                            'code': session.course.code,
                            'department': session.course.department
                        }
                    
                    # Add tutor information if requested
                    if include_tutor and hasattr(session, 'tutor'):
                        session_dict['tutor'] = {
                            'id': session.tutor.id,
                            'name': f"{session.tutor.first_name} {session.tutor.last_name}",
                            'email': session.tutor.email
                        }
                    
                    session_data.append(session_dict)
                
                return custom_response(
                    success=True,
                    data=session_data
                )
                
        except Exception as e:
            current_app.logger.error(f"Error getting daily sessions for tutor: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to retrieve daily sessions for tutor: {str(e)}"
            ), 500

    def get_daily_sessions_for_course(self, course_id, start_date=None, end_date=None, status=None, include_course=False, include_tutor=False):
        """Get daily teaching sessions for a specific course"""
        try:
            with DatabaseContextManager() as ctx:
                query = DailyTeachingSession.safe_query(ctx.session).filter(DailyTeachingSession.course_id == course_id)
                
                # Join with course if requested
                if include_course:
                    query = query.join(Course, DailyTeachingSession.course_id == Course.id)
                
                # Join with tutor if requested
                if include_tutor:
                    query = query.join(User, DailyTeachingSession.tutor_id == User.id)
                
                # Apply filters
                if start_date:
                    query = query.filter(DailyTeachingSession.session_date >= start_date)
                if end_date:
                    query = query.filter(DailyTeachingSession.session_date <= end_date)
                if status:
                    query = query.filter(DailyTeachingSession.status == status)
                
                # Order by date and time
                query = query.order_by(DailyTeachingSession.session_date.desc(), DailyTeachingSession.start_time.desc())
                
                sessions = query.all()
                
                # Serialize sessions (same as above)
                session_data = []
                for session in sessions:
                    session_dict = {
                        'id': session.id,
                        'timetable_block_id': session.timetable_block_id,
                        'teaching_session_id': getattr(session, 'teaching_session_id', None),
                        'course_id': session.course_id,
                        'tutor_id': session.tutor_id,
                        'session_date': session.session_date.isoformat() if session.session_date else None,
                        'start_time': session.start_time.isoformat() if session.start_time else None,
                        'end_time': session.end_time.isoformat() if session.end_time else None,
                        'room': session.room,
                        'session_type': session.session_type,
                        'status': session.status,
                        'created_at': session.created_at.isoformat() if session.created_at else None,
                        'updated_at': session.updated_at.isoformat() if session.updated_at else None,
                        'created_by': session.created_by,
                        'is_verified': session.is_verified,
                        'verified_by': session.verified_by,
                        'verified_at': session.verified_at.isoformat() if session.verified_at else None,
                        'verification_method': session.verification_method,
                        'notes': session.notes,
                        'attendance_taken': session.attendance_taken
                    }
                    
                    # Add course information if requested
                    if include_course and hasattr(session, 'course'):
                        session_dict['course'] = {
                            'id': session.course.id,
                            'title': session.course.title,
                            'code': session.course.code,
                            'department': session.course.department
                        }
                    
                    # Add tutor information if requested
                    if include_tutor and hasattr(session, 'tutor'):
                        session_dict['tutor'] = {
                            'id': session.tutor.id,
                            'name': f"{session.tutor.first_name} {session.tutor.last_name}",
                            'email': session.tutor.email
                        }
                    
                    session_data.append(session_dict)
                
                return custom_response(
                    success=True,
                    data=session_data
                )
                
        except Exception as e:
            current_app.logger.error(f"Error getting daily sessions for course: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to retrieve daily sessions for course: {str(e)}"
            ), 500

    def get_daily_sessions_for_teaching_session(self, teaching_session_id, start_date=None, end_date=None, status=None, include_course=False, include_tutor=False):
        """Get daily teaching sessions for a specific teaching session"""
        try:
            with DatabaseContextManager() as ctx:
                # Get the teaching session to find the tutor_id
                teaching_session = ctx.session.query(TeachingSession).filter(
                    TeachingSession.id == teaching_session_id
                ).first()
                
                if not teaching_session:
                    # Return empty response instead of error to match expected format
                        return custom_response(
                            success=True,
                            data={
                            'sessions': [],
                            'total_sessions': 0
                        }
                    )
                
                # Get all daily sessions for this tutor - let frontend handle filtering
                sessions = ctx.session.query(DailyTeachingSession).filter(
                    DailyTeachingSession.tutor_id == teaching_session.tutor_id
                ).all()
                
                # Serialize sessions
                session_data = []
                for session in sessions:
                    session_dict = {
                        'id': session.id,
                        'timetable_block_id': session.timetable_block_id,
                        'teaching_session_id': getattr(session, 'teaching_session_id', None),
                        'course_id': session.course_id,
                        'tutor_id': session.tutor_id,
                        'session_date': session.session_date.isoformat() if session.session_date else None,
                        'start_time': session.start_time.isoformat() if session.start_time else None,
                        'end_time': session.end_time.isoformat() if session.end_time else None,
                        'room': session.room,
                        'session_type': session.session_type,
                        'status': session.status,
                        'created_at': session.created_at.isoformat() if session.created_at else None,
                        'updated_at': session.updated_at.isoformat() if session.updated_at else None,
                        'created_by': session.created_by,
                        'is_verified': session.is_verified,
                        'verified_by': session.verified_by,
                        'verified_at': session.verified_at.isoformat() if session.verified_at else None,
                        'verification_method': session.verification_method,
                        'notes': session.notes,
                        'attendance_taken': session.attendance_taken
                    }
                    
                    # Add course information if requested
                    if include_course:
                        course = ctx.session.query(Course).filter(Course.id == session.course_id).first()
                        if course:
                            session_dict['course'] = {
                                    'id': course.id,
                                    'title': course.title,
                                    'code': course.code,
                                    'department': course.department
                            }
                    
                    # Add tutor information if requested
                    if include_tutor:
                        tutor = ctx.session.query(User).filter(User.id == session.tutor_id).first()
                        if tutor:
                            session_dict['tutor'] = {
                                    'id': tutor.id,
                                    'first_name': tutor.first_name,
                                    'last_name': tutor.last_name,
                                    'email': tutor.email
                            }
                    
                    session_data.append(session_dict)
                
                # Return all sessions without grouping - let frontend handle filtering
                return custom_response(
                    success=True,
                    data={
                        'sessions': session_data,
                        'total_sessions': len(session_data)
                    }
                )
                
        except Exception as e:
            current_app.logger.error(f"Error getting daily sessions for teaching session: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to retrieve daily sessions for teaching session: {str(e)}"
            ), 500

    def get_daily_session(self, session_id):
        """Get a specific daily teaching session"""
        try:
            with DatabaseContextManager() as ctx:
                session = ctx.session.query(DailyTeachingSession).filter(DailyTeachingSession.id == session_id).first()
                
                if not session:
                    return custom_response(
                        success=False,
                        data="Daily teaching session not found"
                    ), 404
                
                session_dict = {
                    'id': session.id,
                    'timetable_block_id': session.timetable_block_id,
                    'teaching_session_id': getattr(session, 'teaching_session_id', None),
                    'course_id': session.course_id,
                    'tutor_id': session.tutor_id,
                    'session_date': session.session_date.isoformat() if session.session_date else None,
                    'start_time': session.start_time.isoformat() if session.start_time else None,
                    'end_time': session.end_time.isoformat() if session.end_time else None,
                    'room': session.room,
                    'session_type': session.session_type,
                    'status': session.status,
                    'created_at': session.created_at.isoformat() if session.created_at else None,
                    'updated_at': session.updated_at.isoformat() if session.updated_at else None,
                    'created_by': session.created_by,
                    'is_verified': session.is_verified,
                    'verified_by': session.verified_by,
                    'verified_at': session.verified_at.isoformat() if session.verified_at else None,
                    'verification_method': session.verification_method,
                    'notes': session.notes,
                    'attendance_taken': session.attendance_taken
                }
                
                return custom_response(
                    success=True,
                    data=session_dict
                )
                
        except Exception as e:
            current_app.logger.error(f"Error getting daily session: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to retrieve daily session: {str(e)}"
            ), 500

    def create_daily_session(self, payload):
        """Create a new daily teaching session"""
        try:
            with DatabaseContextManager() as ctx:
                # Validate required fields
                required_fields = ['timetable_block_id', 'course_id', 'tutor_id', 'session_date', 'start_time', 'end_time']
                for field in required_fields:
                    if field not in payload:
                        return custom_response(
                            success=False,
                            data=f"Missing required field: {field}"
                        ), 400
                
                # Create new daily session
                daily_session = DailyTeachingSession(
                    timetable_block_id=payload['timetable_block_id'],
                    course_id=payload['course_id'],
                    tutor_id=payload['tutor_id'],
                    session_date=payload['session_date'],
                    start_time=payload['start_time'],
                    end_time=payload['end_time'],
                    room=payload.get('room'),
                    session_type=payload.get('session_type', 'lecture'),
                    status=payload.get('status', 'scheduled'),
                    created_by=payload.get('created_by'),
                    notes=payload.get('notes')
                )
                
                ctx.session.add(daily_session)
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    data={'id': daily_session.id}
                )
                
        except Exception as e:
            current_app.logger.error(f"Error creating daily session: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to create daily session: {str(e)}"
            ), 500

    def update_daily_session(self, session_id, payload):
        """Update a daily teaching session"""
        try:
            with DatabaseContextManager() as ctx:
                session = ctx.session.query(DailyTeachingSession).filter(DailyTeachingSession.id == session_id).first()
                
                if not session:
                    return custom_response(
                        success=False,
                        data="Daily teaching session not found"
                    ), 404
                
                # Update fields
                updatable_fields = ['room', 'session_type', 'status', 'notes', 'is_verified', 'verified_by', 'verification_method', 'attendance_taken']
                for field in updatable_fields:
                    if field in payload:
                        setattr(session, field, payload[field])
                
                session.updated_at = datetime.utcnow()
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    data="Daily teaching session updated successfully"
                )
                
        except Exception as e:
            current_app.logger.error(f"Error updating daily session: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to update daily session: {str(e)}"
            ), 500

    def delete_daily_session(self, session_id):
        """Delete a daily teaching session"""
        try:
            with DatabaseContextManager() as ctx:
                session = ctx.session.query(DailyTeachingSession).filter(DailyTeachingSession.id == session_id).first()
                
                if not session:
                    return custom_response(
                        success=False,
                        data="Daily teaching session not found"
                    ), 404
                
                ctx.session.delete(session)
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    data="Daily teaching session deleted successfully"
                )
                
        except Exception as e:
            current_app.logger.error(f"Error deleting daily session: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to delete daily session: {str(e)}"
            ), 500

    def start_daily_session(self, session_id, payload=None):
        """Start a daily teaching session with automatic tutor attendance recording"""
        try:
            with DatabaseContextManager() as ctx:
                session = ctx.session.query(DailyTeachingSession).filter(DailyTeachingSession.id == session_id).first()
                
                if not session:
                    return custom_response(
                        success=False,
                        data="Daily teaching session not found"
                    ), 404
                
                if session.status != 'scheduled':
                    return custom_response(
                        success=False,
                        data="Session is not in scheduled status"
                    ), 400
                
                # Check timing constraints
                now = datetime.now()
                session_date = session.session_date
                start_time = datetime.combine(session_date, session.start_time)
                
                # Check if it's too early to start (more than 10 minutes before)
                ten_minutes_before = start_time - timedelta(minutes=10)
                if now < ten_minutes_before:
                    return custom_response(
                        success=False,
                        data="Cannot start session more than 10 minutes before scheduled time"
                    ), 400
                
                # Update session status
                session.status = 'ongoing'
                session.updated_at = now
                
                # Auto-record tutor attendance if requested
                if payload and payload.get('auto_record_tutor_attendance'):
                    # Determine if tutor is on time or late
                    ten_minutes_after = start_time + timedelta(minutes=10)
                    twenty_minutes_after = start_time + timedelta(minutes=20)
                    
                    tutor_status = 'present'
                    if now > twenty_minutes_after:
                        tutor_status = 'late'
                    
                    # Create tutor attendance record
                    tutor_attendance = Attendance(
                        id=str(uuid.uuid4()),
                        student_id=session.tutor_id,  # Tutor is treated as a student for attendance
                        daily_session_id=session_id,
                        status=tutor_status,
                        timestamp=now,
                        notes=f"Auto-recorded when starting session. Status: {tutor_status}"
                    )
                    ctx.session.add(tutor_attendance)
                
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    data={
                        'message': 'Daily session started successfully',
                        'session_id': session_id,
                        'status': 'ongoing',
                        'tutor_attendance_recorded': payload.get('auto_record_tutor_attendance', False) if payload else False
                    }
                )
                
        except Exception as e:
            current_app.logger.error(f"Error starting daily session: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to start daily session: {str(e)}"
            ), 500

    def end_daily_session(self, session_id):
        """End a daily teaching session"""
        try:
            with DatabaseContextManager() as ctx:
                session = ctx.session.query(DailyTeachingSession).filter(DailyTeachingSession.id == session_id).first()
                
                if not session:
                    return custom_response(
                        success=False,
                        data="Daily teaching session not found"
                    ), 404
                
                if session.status != 'ongoing':
                    return custom_response(
                        success=False,
                        data="Session is not currently ongoing"
                    ), 400
                
                # Update session status
                session.status = 'completed'
                session.updated_at = datetime.now()
                
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    data={
                        'message': 'Daily session ended successfully',
                        'session_id': session_id,
                        'status': 'completed'
                    }
                )
                
        except Exception as e:
            current_app.logger.error(f"Error ending daily session: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to end daily session: {str(e)}"
            ), 500

    def send_daily_session_reminder(self, session_id, payload=None):
        """Send reminder emails to all students in the class"""
        try:
            with DatabaseContextManager() as ctx:
                session = ctx.session.query(DailyTeachingSession).filter(DailyTeachingSession.id == session_id).first()
                
                if not session:
                    return custom_response(
                        success=False,
                        data="Daily teaching session not found"
                    ), 404
                
                # Get all students enrolled in the course
                students = ctx.session.query(Student).join(Enrollment).filter(
                    Enrollment.course_id == session.course_id,
                    Enrollment.status == 'active'
                ).all()
                
                if not students:
                    return custom_response(
                        success=False,
                        data="No students found for this course"
                    ), 404
                
                # Get course and tutor information
                course = ctx.session.query(Course).filter(Course.id == session.course_id).first()
                tutor = ctx.session.query(User).filter(User.id == session.tutor_id).first()
                
                if not course or not tutor:
                    return custom_response(
                        success=False,
                        data="Course or tutor information not found"
                    ), 404
                
                # Prepare email content
                session_date = session.session_date.strftime('%A, %B %d, %Y')
                start_time = session.start_time.strftime('%I:%M %p')
                end_time = session.end_time.strftime('%I:%M %p')
                tutor_name = f"{tutor.first_name} {tutor.last_name}"
                
                subject = f"Class Reminder: {course.title} - {session_date}"
                
                # Send emails to all students
                emails_sent = 0
                for student in students:
                    try:
                        # Get student user information
                        student_user = ctx.session.query(User).filter(User.id == student.user_id).first()
                        if not student_user:
                            continue
                        
                        body = f"""
Dear {student_user.first_name},

This is a reminder about your upcoming class:

Course: {course.title} ({course.code})
Date: {session_date}
Time: {start_time} - {end_time}
Room: {session.room}
Tutor: {tutor_name}
Session Type: {session.session_type}

Please make sure to:
1. Join the class on time
2. Record your attendance when you arrive
3. Bring any required materials

If you have any questions, please contact your tutor or the course supervisor.

Best regards,
Tutor Management System
                        """
                        
                        # Send email
                        send_email(
                            to_email=student_user.email,
                            subject=subject,
                            body=body
                        )
                        emails_sent += 1
                        
                    except Exception as e:
                        current_app.logger.error(f"Failed to send email to student {student_user.email}: {str(e)}")
                        continue
                
                return custom_response(
                    success=True,
                    data={
                        'message': 'Reminders sent successfully',
                        'students_notified': emails_sent,
                        'total_students': len(students)
                    }
                )
                
        except Exception as e:
            current_app.logger.error(f"Error sending daily session reminder: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to send reminder: {str(e)}"
            ), 500

    def record_tutor_attendance(self, session_id, payload):
        """Record tutor attendance for a daily session"""
        try:
            with DatabaseContextManager() as ctx:
                session = ctx.session.query(DailyTeachingSession).filter(DailyTeachingSession.id == session_id).first()
                
                if not session:
                    return custom_response(
                        success=False,
                        data="Daily teaching session not found"
                    ), 404
                
                status = payload.get('status')
                recorded_by = payload.get('recorded_by')
                
                if not status or not recorded_by:
                    return custom_response(
                        success=False,
                        data="Status and recorded_by are required"
                    ), 400
                
                if status not in ['present', 'absent', 'late']:
                    return custom_response(
                        success=False,
                        data="Invalid status. Must be 'present', 'absent', or 'late'"
                    ), 400
                
                # Check if attendance already exists for this tutor
                existing_attendance = ctx.session.query(Attendance).filter(
                    Attendance.daily_session_id == session_id,
                    Attendance.student_id == session.tutor_id
                ).first()
                
                if existing_attendance:
                    # Update existing attendance
                    existing_attendance.status = status
                    existing_attendance.timestamp = datetime.now()
                    existing_attendance.notes = payload.get('notes', f"Updated by {recorded_by}")
                else:
                    # Create new attendance record
                    attendance = Attendance(
                        id=str(uuid.uuid4()),
                        student_id=session.tutor_id,
                        daily_session_id=session_id,
                        status=status,
                        timestamp=datetime.now(),
                        notes=payload.get('notes', f"Recorded by {recorded_by}")
                    )
                    ctx.session.add(attendance)
                
                ctx.session.commit()
                
                return custom_response(
                    success=True,
                    data={
                        'message': f'Tutor attendance recorded as {status}',
                        'session_id': session_id,
                        'status': status
                    }
                )
                
        except Exception as e:
            current_app.logger.error(f"Error recording tutor attendance: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to record tutor attendance: {str(e)}"
            ), 500