from flask import Flask, request
from sqlalchemy import func, and_, or_, case, desc, asc, text
from src.models import DatabaseContextManager
from src.models.models import (
    Student, Course, TeachingSession, DailyTeachingSession, Attendance, Enrollment,
    AssignmentSubmission, Assignment, User, Speciality
)
from src.utils import custom_response
from datetime import datetime, timedelta, date
from typing import Dict, List, Any
import logging

logger = logging.getLogger(__name__)

class StudentAnalyticsManager:
    """Manages student analytics and reporting functionality"""
    
    def __init__(self):
        self.table = Student
    
    def get_student_overview_analytics(self, period: str = '30d', **filters) -> Dict:
        """
        Get overview statistics for student analytics dashboard
        
        Args:
            period: Time period for analytics ('7d', '30d', '90d', '1y')
            filters: Additional filters like student, status, etc.
            
        Returns:
            Response with overview analytics data
        """
        try:
            start_date, end_date = self._calculate_date_range(period)
            
            with DatabaseContextManager() as ctx:
                # Use simple queries to avoid ambiguous joins
                
                # Get total students
                total_students_query = text("""
                    SELECT COUNT(*) FROM users 
                    WHERE user_type = 'student' AND is_active = 1
                """)
                total_students = ctx.session.execute(total_students_query).scalar()
                
                # Get active students with GPA
                active_students_query = text("""
                    SELECT COUNT(*) FROM students s
                    JOIN users u ON s.id = u.id
                    WHERE u.user_type = 'student' AND u.is_active = 1 
                    AND s.cumulative_gpa IS NOT NULL
                """)
                active_students = ctx.session.execute(active_students_query).scalar()
                
                # Calculate inactive students
                inactive_students = max(0, total_students - active_students)
                
                # Calculate average GPA
                avg_gpa_query = text("""
                    SELECT AVG(cumulative_gpa) FROM students s
                    JOIN users u ON s.id = u.id
                    WHERE u.user_type = 'student' AND u.is_active = 1 
                    AND s.cumulative_gpa IS NOT NULL
                """)
                avg_gpa_result = ctx.session.execute(avg_gpa_query).scalar()
                average_gpa = float(avg_gpa_result) if avg_gpa_result else 0.0
                
                # Get students on probation
                probation_query = text("""
                    SELECT COUNT(*) FROM students s
                    JOIN users u ON s.id = u.id
                    WHERE u.user_type = 'student' AND u.is_active = 1 
                    AND s.is_on_probation = 1
                """)
                probation_count = ctx.session.execute(probation_query).scalar()
                
                # Get unique departments
                departments_query = text("""
                    SELECT COUNT(DISTINCT sp.department) FROM students s
                    JOIN users u ON s.id = u.id
                    JOIN specialities sp ON s.speciality_id = sp.id
                    WHERE u.user_type = 'student' AND u.is_active = 1
                    AND sp.department IS NOT NULL
                """)
                total_departments = ctx.session.execute(departments_query).scalar()
                
                # Get course count  
                courses_query = text("SELECT COUNT(*) FROM courses WHERE is_active = 1")
                total_courses = ctx.session.execute(courses_query).scalar()
                
                # Get graduating students (year 3+)
                graduating_query = text("""
                    SELECT COUNT(*) FROM students s
                    JOIN users u ON s.id = u.id
                    WHERE u.user_type = 'student' AND u.is_active = 1
                    AND s.year_of_study >= 3
                """)
                graduating_this_year = ctx.session.execute(graduating_query).scalar()
                
                overview_data = {
                    'total_students': total_students or 0,
                    'active_students': active_students or 0,
                    'inactive_students': inactive_students,
                    'average_gpa': round(average_gpa, 2),
                    'students_on_probation': probation_count or 0,
                    'total_departments': total_departments or 0,
                    'total_courses': total_courses or 0,
                    'graduating_this_year': graduating_this_year or 0
                }
                
                return custom_response(
                    success=True,
                    data=overview_data,
                    status_code=200
                )
                
        except Exception as e:
            logger.error(f"Error getting student overview analytics: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to get overview analytics: {str(e)}",
                status_code=500
            )
    
    def _calculate_date_range(self, period: str):
        """Calculate start and end dates based on period"""
        end_date = date.today()
        
        if period == '7d':
            start_date = end_date - timedelta(days=7)
        elif period == '30d':
            start_date = end_date - timedelta(days=30)
        elif period == '90d':
            start_date = end_date - timedelta(days=90)
        elif period == '1y':
            start_date = end_date - timedelta(days=365)
        else:
            start_date = end_date - timedelta(days=30)  # Default to 30 days
            
        return start_date, end_date

    def get_attendance_analytics(self, period: str = '30d', **filters) -> Dict:
        """
        Get comprehensive attendance analytics for all students
        
        Args:
            period: Time period for analytics
            filters: Additional filters
            
        Returns:
            Response with attendance analytics data
        """
        try:
            start_date, end_date = self._calculate_date_range(period)
            
            with DatabaseContextManager() as ctx:
                # Get daily attendance trends using raw SQL
                daily_attendance_query = text("""
                    SELECT DATE(dt.session_date) as date,
                           COUNT(DISTINCT att.id) as total_attendance,
                           SUM(CASE WHEN att.status = 'present' THEN 1 ELSE 0 END) as present,
                           SUM(CASE WHEN att.status = 'absent' THEN 1 ELSE 0 END) as absent,
                           SUM(CASE WHEN att.status = 'late' THEN 1 ELSE 0 END) as late
                    FROM daily_teaching_sessions dt
                    LEFT JOIN attendance att ON dt.id = att.daily_session_id
                    WHERE dt.session_date >= :start_date 
                    AND dt.session_date <= :end_date
                    GROUP BY DATE(dt.session_date)
                    ORDER BY DATE(dt.session_date)
                """)
                
                daily_result = ctx.session.execute(daily_attendance_query, {
                    'start_date': start_date,
                    'end_date': end_date
                }).fetchall()
                
                # Process daily attendance data
                daily_trend = []
                for record in daily_result:
                    daily_trend.append({
                        'date': str(record.date),
                        'present': record.present or 0,
                        'absent': record.absent or 0,
                        'late': record.late or 0,
                        'total': record.total_attendance or 0
                    })
                
                # Get department-wise attendance
                dept_attendance_query = text("""
                    SELECT sp.department,
                           COUNT(DISTINCT att.id) as total_sessions,
                           SUM(CASE WHEN att.status = 'present' THEN 1 ELSE 0 END) as present,
                           SUM(CASE WHEN att.status = 'absent' THEN 1 ELSE 0 END) as absent,
                           SUM(CASE WHEN att.status = 'late' THEN 1 ELSE 0 END) as late
                    FROM attendance att
                    JOIN students s ON att.student_id = s.id
                    JOIN users u ON s.id = u.id
                    JOIN specialities sp ON s.speciality_id = sp.id
                    JOIN daily_teaching_sessions dt ON att.daily_session_id = dt.id
                    WHERE dt.session_date >= :start_date 
                    AND dt.session_date <= :end_date
                    AND sp.department IS NOT NULL
                    GROUP BY sp.department
                """)
                
                dept_result = ctx.session.execute(dept_attendance_query, {
                    'start_date': start_date,
                    'end_date': end_date
                }).fetchall()
                
                # Process department attendance data
                department_stats = []
                for record in dept_result:
                    total = record.total_sessions or 0
                    present = record.present or 0
                    late = record.late or 0
                    attendance_rate = ((present + late) / total * 100) if total > 0 else 0
                    
                    department_stats.append({
                        'department': record.department,
                        'attendance_rate': round(attendance_rate, 1),
                        'total_sessions': total,
                        'present': present,
                        'late': late,
                        'absent': record.absent or 0
                    })
                
                # Calculate overall statistics
                overall_query = text("""
                    SELECT COUNT(DISTINCT att.id) as total,
                           SUM(CASE WHEN att.status = 'present' THEN 1 ELSE 0 END) as present,
                           SUM(CASE WHEN att.status = 'absent' THEN 1 ELSE 0 END) as absent,
                           SUM(CASE WHEN att.status = 'late' THEN 1 ELSE 0 END) as late
                    FROM attendance att
                    JOIN daily_teaching_sessions dt ON att.daily_session_id = dt.id
                    WHERE dt.session_date >= :start_date 
                    AND dt.session_date <= :end_date
                """)
                
                overall_result = ctx.session.execute(overall_query, {
                    'start_date': start_date,
                    'end_date': end_date
                }).first()
                
                total_sessions = overall_result.total or 0
                total_present = overall_result.present or 0
                total_late = overall_result.late or 0
                
                attendance_summary = {
                    'total_sessions': total_sessions,
                    'average_attendance': round(((total_present + total_late) / total_sessions * 100), 1) if total_sessions > 0 else 0,
                    'best_day': 'Friday',  # Could be calculated from actual data
                    'worst_day': 'Monday',   # Could be calculated from actual data
                    'improvement_trend': '+5.2%'  # Placeholder
                }
                
                analytics_data = {
                    'daily_trend': daily_trend,
                    'department_stats': department_stats,
                    'summary': attendance_summary,
                    'date_range': {
                        'start': start_date.isoformat(),
                        'end': end_date.isoformat(),
                        'period': period
                    }
                }
                
                return custom_response(
                    success=True,
                    data=analytics_data,
                    status_code=200
                )
                
        except Exception as e:
            logger.error(f"Error getting attendance analytics: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to get attendance analytics: {str(e)}",
                status_code=500
            )

    def get_performance_analytics(self, period: str = '30d', **filters) -> Dict:
        """
        Get comprehensive performance analytics for all students
        
        Args:
            period: Time period for analytics
            filters: Additional filters
            
        Returns:
            Response with performance analytics data
        """
        try:
            start_date, end_date = self._calculate_date_range(period)
            
            with DatabaseContextManager() as ctx:
                # Get GPA distribution using raw SQL
                gpa_distribution_query = text("""
                    SELECT 
                        CASE 
                            WHEN s.cumulative_gpa >= 3.7 THEN 'A'
                            WHEN s.cumulative_gpa >= 3.0 THEN 'B'
                            WHEN s.cumulative_gpa >= 2.5 THEN 'C'
                            WHEN s.cumulative_gpa >= 2.0 THEN 'D'
                            ELSE 'F'
                        END as grade_range,
                        COUNT(*) as count
                    FROM students s
                    JOIN users u ON s.id = u.id
                    WHERE u.user_type = 'student' AND u.is_active = 1 
                    AND s.cumulative_gpa IS NOT NULL
                    GROUP BY grade_range
                """)
                
                gpa_result = ctx.session.execute(gpa_distribution_query).fetchall()
                
                # Process GPA distribution
                grade_distribution = []
                total_count = sum(record.count for record in gpa_result)
                
                for record in gpa_result:
                    percentage = round(record.count / total_count * 100, 1) if total_count > 0 else 0
                    grade_distribution.append({
                        'grade': record.grade_range,
                        'count': record.count,
                        'percentage': percentage
                    })
                
                # Get course performance data
                course_performance_query = text("""
                    SELECT c.code, c.title, AVG(s.cumulative_gpa) as avg_gpa, COUNT(DISTINCT s.id) as student_count
                    FROM courses c
                    JOIN specialities sp ON c.speciality_id = sp.id
                    JOIN students s ON s.speciality_id = sp.id
                    JOIN users u ON s.id = u.id
                    WHERE u.user_type = 'student' AND u.is_active = 1
                    AND s.cumulative_gpa IS NOT NULL
                    GROUP BY c.code, c.title
                """)
                
                course_result = ctx.session.execute(course_performance_query).fetchall()
                
                # Process course performance data
                course_perf_data = []
                for record in course_result:
                    course_perf_data.append({
                        'course_code': record.code,
                        'course_title': record.title,
                        'average_gpa': round(float(record.avg_gpa), 2) if record.avg_gpa else 0,
                        'student_count': record.student_count
                    })
                
                # Get student performance tiers
                tiers_query = text("""
                    SELECT 
                        COUNT(CASE WHEN s.cumulative_gpa >= 3.7 THEN 1 END) as excellent,
                        COUNT(CASE WHEN s.cumulative_gpa >= 3.0 AND s.cumulative_gpa < 3.7 THEN 1 END) as good,
                        COUNT(CASE WHEN s.cumulative_gpa >= 2.5 AND s.cumulative_gpa < 3.0 THEN 1 END) as satisfactory,
                        COUNT(CASE WHEN s.cumulative_gpa < 2.5 THEN 1 END) as need_support
                    FROM students s
                    JOIN users u ON s.id = u.id
                    WHERE u.user_type = 'student' AND u.is_active = 1
                    AND s.cumulative_gpa IS NOT NULL
                """)
                
                tiers_result = ctx.session.execute(tiers_query).first()
                
                # Process performance tiers
                student_tiers = {
                    'excellent': tiers_result.excellent or 0,
                    'good': tiers_result.good or 0,
                    'satisfactory': tiers_result.satisfactory or 0,
                    'need_support': tiers_result.need_support or 0
                }
                
                # Calculate overall analytics
                overall_query = text("""
                    SELECT AVG(s.cumulative_gpa) as avg_gpa,
                           MIN(s.cumulative_gpa) as min_gpa,
                           MAX(s.cumulative_gpa) as max_gpa,
                           COUNT(DISTINCT s.id) as total_students
                    FROM students s
                    JOIN users u ON s.id = u.id
                    WHERE u.user_type = 'student' AND u.is_active = 1
                    AND s.cumulative_gpa IS NOT NULL
                """)
                
                overall_result = ctx.session.execute(overall_query).first()
                
                performance_summary = {
                    'average_gpa': round(float(overall_result.avg_gpa), 2) if overall_result.avg_gpa else 0,
                    'highest_gpa': round(float(overall_result.max_gpa), 2) if overall_result.max_gpa else 0,
                    'lowest_gpa': round(float(overall_result.min_gpa), 2) if overall_result.min_gpa else 0,
                    'total_students': overall_result.total_students or 0,
                    'improvement_trend': '+0.15'  # Placeholder
                }
                
                analytics_data = {
                    'grade_distribution': grade_distribution,
                    'course_performance': course_perf_data,
                    'student_tiers': student_tiers,
                    'summary': performance_summary,
                    'date_range': {
                        'start': start_date.isoformat(),
                        'end': end_date.isoformat(),
                        'period': period
                    }
                }
                
                return custom_response(
                    success=True,
                    data=analytics_data,
                    status_code=200
                )
                
        except Exception as e:
            logger.error(f"Error getting performance analytics: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to get performance analytics: {str(e)}",
                status_code=500
            )

    def get_assignment_analytics(self, period: str = '30d', **filters) -> Dict:
        """
        Get comprehensive assignment analytics for all students
        
        Args:
            period: Time period for analytics
            filters: Additional filters
            
        Returns:
            Response with assignment analytics data
        """
        try:
            start_date, end_date = self._calculate_date_range(period)
            
            with DatabaseContextManager() as ctx:
                # Get assignment submission trends using raw SQL
                submission_trends_query = text("""
                    SELECT DATE(asb.submitted_at) as date,
                           COUNT(CASE WHEN asb.status = 'submitted' THEN 1 END) as submitted,
                           COUNT(CASE WHEN asb.status = 'in_progress' THEN 1 END) as in_progress,
                           COUNT(CASE WHEN asb.status = 'late' THEN 1 END) as late,
                           COUNT(CASE WHEN asb.status = 'graded' THEN 1 END) as graded
                    FROM assignment_submissions asb
                    JOIN students s ON asb.student_id = s.id
                    JOIN users u ON s.id = u.id
                    WHERE asb.submitted_at >= :start_date 
                    AND asb.submitted_at <= :end_date
                    AND u.user_type = 'student' AND u.is_active = 1
                    GROUP BY DATE(asb.submitted_at)
                    ORDER BY DATE(asb.submitted_at)
                """)
                
                trends_result = ctx.session.execute(submission_trends_query, {
                    'start_date': start_date,
                    'end_date': end_date
                }).fetchall()
                
                # Process submission trends data
                submission_trends = []
                for record in trends_result:
                    submission_trends.append({
                        'date': str(record.date),
                        'submitted': record.submitted or 0,
                        'pending': record.in_progress or 0,
                        'late': record.late or 0,
                        'not_submitted': 0  # We'll calculate this from assignment counts
                    })
                
                # Get assignment type performance
                assignment_types_query = text("""
                    SELECT a.assignment_type,
                           COUNT(*) as total_assignments,
                           COUNT(CASE WHEN asb.status = 'submitted' THEN 1 END) as submitted,
                           COUNT(CASE WHEN asb.status = 'late' THEN 1 END) as late,
                           COUNT(CASE WHEN asb.status = 'graded' THEN 1 END) as graded,
                           AVG(asb.grade) as avg_score
                    FROM assignments a
                    LEFT JOIN assignment_submissions asb ON a.id = asb.assignment_id
                    LEFT JOIN students s ON asb.student_id = s.id
                    LEFT JOIN users u ON s.id = u.id
                    WHERE u.user_type = 'student' AND u.is_active = 1
                    AND a.due_date >= :start_date AND a.due_date <= :end_date
                    GROUP BY a.assignment_type
                """)
                
                types_result = ctx.session.execute(assignment_types_query, {
                    'start_date': start_date,
                    'end_date': end_date
                }).fetchall()
                
                # Process assignment types data
                assignment_types = []
                for record in types_result:
                    total = record.total_assignments or 0
                    submitted = record.submitted or 0
                    late = record.late or 0
                    not_submitted = record.not_submitted or 0
                    
                    assignment_types.append({
                        'assignment_type': record.assignment_type,
                        'total_assignments': total,
                        'submission_rate': round(((submitted + late) / total * 100), 1) if total > 0 else 0,
                        'late_rate': round((late / total * 100), 1) if total > 0 else 0,
                        'not_submitted_rate': round((not_submitted / total * 100), 1) if total > 0 else 0,
                        'avg_score': round(float(record.avg_score), 2) if record.avg_score else 0
                    })
                
                # Get departmental assignment statistics
                departmental_stats_query = text("""
                    SELECT sp.department,
                           COUNT(*) as total_submissions,
                           COUNT(CASE WHEN asb.status = 'submitted' THEN 1 END) as submitted,
                           COUNT(CASE WHEN asb.status = 'late' THEN 1 END) as late,
                           COUNT(CASE WHEN asb.status = 'not_submitted' THEN 1 END) as not_submitted,
                           AVG(asb.grade) as avg_score,
                           AVG(CASE WHEN asb.submitted_at <= a.due_date THEN 1 ELSE 0 END) as on_time_rate
                    FROM assignment_submissions asb
                    JOIN students s ON asb.student_id = s.id
                    JOIN users u ON s.id = u.id
                    JOIN specialities sp ON s.speciality_id = sp.id
                    JOIN assignments a ON asb.assignment_id = a.id
                    WHERE u.user_type = 'student' AND u.is_active = 1
                    AND a.due_date >= :start_date AND a.due_date <= :end_date
                    AND sp.department IS NOT NULL
                    GROUP BY sp.department
                """)
                
                dept_result = ctx.session.execute(departmental_stats_query, {
                    'start_date': start_date,
                    'end_date': end_date
                }).fetchall()
                
                # Process departmental stats
                departmental_stats = []
                for record in dept_result:
                    total = record.total_submissions or 0
                    submitted = record.submitted or 0
                    late = record.late or 0
                    
                    departmental_stats.append({
                        'department': record.department,
                        'total_submissions': total,
                        'submission_rate': round(((submitted + late) / total * 100), 1) if total > 0 else 0,
                        'avg_score': round(float(record.avg_score), 2) if record.avg_score else 0,
                        'on_time_rate': round(float(record.on_time_rate * 100), 1) if record.on_time_rate else 0
                    })
                
                # Get late submission trends
                late_submissions_query = text("""
                    SELECT s.student_id,
                           u.first_name || ' ' || u.last_name as student_name,
                           COUNT(CASE WHEN asb.status = 'late' THEN 1 END) as late_count,
                           COUNT(*) as total_submissions,
                           AVG(asb.grade) as avg_score,
                           sp.department
                    FROM assignment_submissions asb
                    JOIN students s ON asb.student_id = s.id
                    JOIN users u ON s.id = u.id
                    JOIN specialities sp ON s.speciality_id = sp.id
                    WHERE u.user_type = 'student' AND u.is_active = 1
                    AND asb.submitted_at >= :start_date AND asb.submitted_at <= :end_date
                    GROUP BY s.student_id, u.first_name, u.last_name, sp.department
                    HAVING COUNT(CASE WHEN asb.status = 'late' THEN 1 END) > 0
                    ORDER BY late_count DESC
                    LIMIT 20
                """)
                
                late_result = ctx.session.execute(late_submissions_query, {
                    'start_date': start_date,
                    'end_date': end_date
                }).fetchall()
                
                # Process late submissions data
                late_submissions = []
                for record in late_result:
                    late_submissions.append({
                        'student_id': record.student_id,
                        'student_name': record.student_name,
                        'late_count': record.late_count,
                        'total_submissions': record.total_submissions,
                        'late_percentage': round((record.late_count / record.total_submissions * 100), 1),
                        'avg_score': round(float(record.avg_score), 2) if record.avg_score else 0,
                        'department': record.department
                    })
                
                # Get top performers by assignment score
                top_performers_query = text("""
                    SELECT s.student_id,
                           u.first_name || ' ' || u.last_name as student_name,
                           COUNT(*) as total_assignments,
                           AVG(asb.grade) as avg_score,
                           MAX(asb.grade) as best_score,
                           sp.department
                    FROM assignment_submissions asb
                    JOIN students s ON asb.student_id = s.id
                    JOIN users u ON s.id = u.id
                    JOIN specialities sp ON s.speciality_id = sp.id
                    WHERE u.user_type = 'student' AND u.is_active = 1
                    AND asb.submitted_at >= :start_date AND asb.submitted_at <= :end_date
                    AND asb.status IN ('submitted', 'late')
                    GROUP BY s.student_id, u.first_name, u.last_name, sp.department
                    HAVING COUNT(*) >= 3  -- At least 3 completed assignments
                    ORDER BY avg_score DESC, best_score DESC
                    LIMIT 20
                """)
                
                top_result = ctx.session.execute(top_performers_query, {
                    'start_date': start_date,
                    'end_date': end_date
                }).fetchall()
                
                # Process top performers data
                top_performers = []
                for record in top_result:
                    top_performers.append({
                        'student_id': record.student_id,
                        'student_name': record.student_name,
                        'total_assignments': record.total_assignments,
                        'avg_score': round(float(record.avg_score), 2),
                        'best_score': round(float(record.best_score), 2),
                        'department': record.department
                    })
                
                # Calculate summary statistics
                summary_query = text("""
                    SELECT COUNT(*) as total_submissions,
                           COUNT(CASE WHEN asb.status = 'submitted' THEN 1 END) as submitted,
                           COUNT(CASE WHEN asb.status = 'late' THEN 1 END) as late,
                           COUNT(CASE WHEN asb.status = 'not_submitted' THEN 1 END) as not_submitted,
                           AVG(asb.grade) as overall_avg_score,
                           MIN(asb.submitted_at) as earliest_submission,
                           MAX(asb.submitted_at) as latest_submission
                    FROM assignment_submissions asb
                    JOIN students s ON asb.student_id = s.id
                    JOIN users u ON s.id = u.id
                    WHERE u.user_type = 'student' AND u.is_active = 1
                    AND asb.submitted_at >= :start_date AND asb.submitted_at <= :end_date
                """)
                
                summary_result = ctx.session.execute(summary_query, {
                    'start_date': start_date,
                    'end_date': end_date
                }).first()
                
                total_submissions = summary_result.total_submissions or 0
                submitted = summary_result.submitted or 0
                late = summary_result.late or 0
                not_submitted = summary_result.not_submitted or 0
                
                assignment_summary = {
                    'total_submissions': total_submissions,
                    'total_submitted': submitted + late,
                    'submission_rate': round(((submitted + late) / total_submissions * 100), 1) if total_submissions > 0 else 0,
                    'late_rate': round((late / total_submissions * 100), 1) if total_submissions > 0 else 0,
                    'not_submitted_rate': round((not_submitted / total_submissions * 100), 1) if total_submissions > 0 else 0,
                    'overall_avg_score': round(float(summary_result.overall_avg_score), 2) if summary_result.overall_avg_score else 0,
                    'improvement_trend': '+2.3%'  # Placeholder - could be calculated from historical data
                }
                
                analytics_data = {
                    'submission_trends': submission_trends,
                    'assignment_types': assignment_types,
                    'departmental_stats': departmental_stats,
                    'late_submissions': late_submissions,
                    'top_performers': top_performers,
                    'summary': assignment_summary,
                    'date_range': {
                        'start': start_date.isoformat(),
                        'end': end_date.isoformat(),
                        'period': period
                    }
                }
                
                return custom_response(
                    success=True,
                    data=analytics_data,
                    status_code=200
                )
                
        except Exception as e:
            logger.error(f"Error getting assignment analytics: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to get assignment analytics: {str(e)}",
                status_code=500
            )

    def get_detailed_attendance_analytics(self, period: str = '30d', **filters) -> Dict:
        """
        Get detailed student attendance analytics for the attendance dashboard
        
        Args:
            period: Time period for analytics ('today', '7d', '30d', '90d', 'custom')
            **filters: Additional filters (start_date, end_date, department, speciality, course, status, student_search)
            
        Returns:
            Response with comprehensive attendance analytics data
        """
        try:
            start_date, end_date = self._calculate_date_range_with_filters(period, **filters)
            
            with DatabaseContextManager() as ctx:
                # Build base query for attendance records
                attendance_query = text("""
                    SELECT 
                        a.id,
                        a.student_id,
                        COALESCE(u.first_name || ' ' || u.last_name, s.id) as student_name,
                        COALESCE(s.department, 'Unknown') as department,
                        COALESCE(sp.name, 'Unknown') as speciality,
                        COALESCE(c.code, 'N/A') as course_code,
                        COALESCE(c.title, 'Unknown Course') as course_title,
                        COALESCE(dts.session_date, DATE('now')) as session_date,
                        COALESCE(ts.start_time, dts.start_time, TIME('09:00:00')) as session_time,
                        90 as session_duration,
                        a.status,
                        a.notes,
                        a.timestamp,
                        a.created_at
                    FROM attendance a
                    LEFT JOIN students s ON a.student_id = s.id
                    LEFT JOIN users u ON s.id = u.id
                    LEFT JOIN specialities sp ON sp.id = s.speciality_id
                    LEFT JOIN teaching_session ts ON a.session_id = ts.id
                    LEFT JOIN daily_teaching_sessions dts ON a.daily_session_id = dts.id
                    LEFT JOIN courses c ON (
                        (ts.course_id IS NOT NULL AND ts.course_id = c.id) OR 
                        (dts.course_id IS NOT NULL AND dts.course_id = c.id)
                    )
                    WHERE COALESCE(dts.session_date, DATE('now')) BETWEEN :start_date AND :end_date
                """)
                
                # Apply filters
                query_params = {'start_date': start_date, 'end_date': end_date}
                
                if filters.get('department'):
                    attendance_query = text(str(attendance_query) + " AND s.department = :department")
                    query_params['department'] = filters['department']
                
                if filters.get('speciality'):
                    attendance_query = text(str(attendance_query) + " AND sp.name = :speciality")
                    query_params['speciality'] = filters['speciality']
                
                if filters.get('course'):
                    attendance_query = text(str(attendance_query) + " AND c.id = :course")
                    query_params['course'] = filters['course']
                
                if filters.get('status'):
                    attendance_query = text(str(attendance_query) + " AND a.status = :status")
                    query_params['status'] = filters['status']
                
                if filters.get('student_search'):
                    attendance_query = text(str(attendance_query) + " AND CONCAT(u.first_name, ' ', u.last_name) ILIKE :student_search")
                    query_params['student_search'] = f"%{filters['student_search']}%"
                
                # Get attendance records
                attendance_records = ctx.session.execute(attendance_query, query_params).fetchall()
                
                # Convert to list of dictionaries
                records_data = []
                for record in attendance_records:
                    records_data.append({
                        'id': record.id,
                        'student_id': record.student_id,
                        'student_name': record.student_name,
                        'department': record.department or 'Unknown',
                        'speciality': record.speciality or 'Unknown',
                        'course_code': record.course_code or 'N/A',
                        'course_title': record.course_title or 'Unknown Course',
                        'session_date': str(record.session_date),
                        'session_time': str(record.session_time),
                        'session_duration': record.session_duration or 90,
                        'status': record.status,
                        'notes': record.notes,
                        'timestamp': record.timestamp.isoformat() if record.timestamp else None,
                        'created_at': record.created_at.isoformat() if record.created_at else None
                    })
                
                # Calculate summary statistics
                summary_query = text("""
                    SELECT 
                        COUNT(*) as total_records,
                        COUNT(CASE WHEN a.status = 'present' THEN 1 END) as present_count,
                        COUNT(CASE WHEN a.status = 'absent' THEN 1 END) as absent_count,
                        COUNT(CASE WHEN a.status = 'late' THEN 1 END) as late_count,
                        COUNT(CASE WHEN a.status = 'excused' THEN 1 END) as excused_count,
                        COUNT(DISTINCT a.student_id) as unique_students,
                        COUNT(DISTINCT COALESCE(ts.course_id, dts.course_id)) as unique_courses,
                        COUNT(DISTINCT s.department) as unique_departments
                    FROM attendance a
                    LEFT JOIN students s ON a.student_id = s.id
                    LEFT JOIN teaching_session ts ON a.session_id = ts.id
                    LEFT JOIN daily_teaching_sessions dts ON a.daily_session_id = dts.id
                    WHERE COALESCE(dts.session_date, DATE('now')) BETWEEN :start_date AND :end_date
                """)
                
                # Apply the same filters to summary query
                summary_params = {'start_date': start_date, 'end_date': end_date}
                if filters.get('department'):
                    summary_query = text(str(summary_query) + " AND s.department = :department")
                    summary_params['department'] = filters['department']
                if filters.get('speciality'):
                    summary_query = text(str(summary_query) + " AND s.speciality_id IN (SELECT id FROM specialities WHERE name = :speciality)")
                    summary_params['speciality'] = filters['speciality']
                if filters.get('course'):
                    summary_query = text(str(summary_query) + " AND (ts.course_id = :course OR dts.course_id = :course)")
                    summary_params['course'] = filters['course']
                if filters.get('status'):
                    summary_query = text(str(summary_query) + " AND a.status = :status")
                    summary_params['status'] = filters['status']
                
                summary_result = ctx.session.execute(summary_query, summary_params).fetchone()
                
                if summary_result and summary_result.total_records > 0:
                    total_records = summary_result.total_records
                    present_percentage = (summary_result.present_count / total_records) * 100
                    absent_percentage = (summary_result.absent_count / total_records) * 100
                    late_percentage = (summary_result.late_count / total_records) * 100
                    excused_percentage = (summary_result.excused_count / total_records) * 100
                    
                    summary_stats = {
                        'total_records': total_records,
                        'present_percentage': round(present_percentage, 1),
                        'absent_percentage': round(absent_percentage, 1),
                        'late_percentage': round(late_percentage, 1),
                        'excused_percentage': round(excused_percentage, 1),
                        'total_students': summary_result.unique_students,
                        'total_sessions': total_records,
                        'unique_courses': summary_result.unique_courses,
                        'unique_departments': summary_result.unique_departments
                    }
                else:
                    summary_stats = {
                        'total_records': 0,
                        'present_percentage': 0,
                        'absent_percentage': 0,
                        'late_percentage': 0,
                        'excused_percentage': 0,
                        'total_students': 0,
                        'total_sessions': 0,
                        'unique_courses': 0,
                        'unique_departments': 0
                    }
                
                # Get comprehensive breakdowns
                query_params = {'start_date': start_date, 'end_date': end_date}
                
                # Get department breakdown (with attendance data)
                department_breakdown_query = text("""
                    SELECT 
                        COALESCE(s.department, 'Unknown') as department,
                        COUNT(*) as total_sessions,
                        COUNT(CASE WHEN a.status = 'present' THEN 1 END) as present_count,
                        COUNT(CASE WHEN a.status = 'absent' THEN 1 END) as absent_count,
                        COUNT(CASE WHEN a.status = 'late' THEN 1 END) as late_count,
                        COUNT(CASE WHEN a.status = 'excused' THEN 1 END) as excused_count,
                        COUNT(DISTINCT a.student_id) as students_count
                    FROM attendance a
                    LEFT JOIN students s ON a.student_id = s.id
                    LEFT JOIN teaching_session ts ON a.session_id = ts.id
                    LEFT JOIN daily_teaching_sessions dts ON a.daily_session_id = dts.id
                    WHERE COALESCE(dts.session_date, DATE('now')) BETWEEN :start_date AND :end_date
                    GROUP BY COALESCE(s.department, 'Unknown')
                """)
                
                # Get all departments (even without attendance records)
                all_departments_query = text("""
                    SELECT DISTINCT COALESCE(department, 'Unknown') as department
                    FROM students 
                    WHERE department IS NOT NULL
                """)
                
                # Get speciality breakdown (with attendance data)
                speciality_breakdown_query = text("""
                    SELECT 
                        COALESCE(sp.name, 'Unknown') as speciality,
                        COALESCE(s.department, 'Unknown') as department,
                        COUNT(*) as total_sessions,
                        COUNT(CASE WHEN a.status = 'present' THEN 1 END) as present_count,
                        COUNT(CASE WHEN a.status = 'absent' THEN 1 END) as absent_count,
                        COUNT(CASE WHEN a.status = 'late' THEN 1 END) as late_count,
                        COUNT(CASE WHEN a.status = 'excused' THEN 1 END) as excused_count,
                        COUNT(DISTINCT a.student_id) as students_count
                    FROM attendance a
                    LEFT JOIN students s ON a.student_id = s.id
                    LEFT JOIN specialities sp ON s.speciality_id = sp.id
                    LEFT JOIN teaching_session ts ON a.session_id = ts.id
                    LEFT JOIN daily_teaching_sessions dts ON a.daily_session_id = dts.id
                    WHERE COALESCE(dts.session_date, DATE('now')) BETWEEN :start_date AND :end_date
                    GROUP BY COALESCE(sp.name, 'Unknown'), COALESCE(s.department, 'Unknown')
                """)
                
                # Get all specialities (even without attendance records)
                all_specialities_query = text("""
                    SELECT DISTINCT sp.name as speciality, s.department
                    FROM specialities sp
                    LEFT JOIN students s ON s.speciality_id = sp.id
                    WHERE sp.name IS NOT NULL
                """)
                
                # Get course breakdown (with attendance data)
                course_breakdown_query = text("""
                    SELECT 
                        COALESCE(c.code, 'Unknown') as course_code,
                        COALESCE(c.title, 'Unknown Course') as course_title,
                        COALESCE(s.department, 'Unknown') as department,
                        COALESCE(sp.name, 'Unknown') as speciality,
                        COUNT(*) as total_sessions,
                        COUNT(CASE WHEN a.status = 'present' THEN 1 END) as present_count,
                        COUNT(CASE WHEN a.status = 'absent' THEN 1 END) as absent_count,
                        COUNT(CASE WHEN a.status = 'late' THEN 1 END) as late_count,
                        COUNT(CASE WHEN a.status = 'excused' THEN 1 END) as excused_count,
                        COUNT(DISTINCT a.student_id) as students_count
                    FROM attendance a
                    LEFT JOIN students s ON a.student_id = s.id
                    LEFT JOIN specialities sp ON s.speciality_id = sp.id
                    LEFT JOIN teaching_session ts ON a.session_id = ts.id
                    LEFT JOIN daily_teaching_sessions dts ON a.daily_session_id = dts.id
                    LEFT JOIN courses c ON (
                        (ts.course_id IS NOT NULL AND ts.course_id = c.id) OR 
                        (dts.course_id IS NOT NULL AND dts.course_id = c.id)
                    )
                    WHERE COALESCE(dts.session_date, DATE('now')) BETWEEN :start_date AND :end_date
                    GROUP BY COALESCE(c.code, 'Unknown'), c.title, COALESCE(s.department, 'Unknown'), COALESCE(sp.name, 'Unknown')
                """)
                
                # Get all courses (even without attendance records)
                all_courses_query = text("""
                    SELECT DISTINCT c.code as course_code, c.title as course_title
                    FROM courses c
                    WHERE c.code IS NOT NULL
                """)
                
                # Execute queries
                department_breakdown_result = ctx.session.execute(department_breakdown_query, query_params).fetchall()
                all_departments_result = ctx.session.execute(all_departments_query).fetchall()
                speciality_breakdown_result = ctx.session.execute(speciality_breakdown_query, query_params).fetchall()
                all_specialities_result = ctx.session.execute(all_specialities_query).fetchall()
                course_breakdown_result = ctx.session.execute(course_breakdown_query, query_params).fetchall()
                all_courses_result = ctx.session.execute(all_courses_query).fetchall()
                
                # Create comprehensive breakdown data
                breakdown_data = self._create_comprehensive_breakdown(
                    department_breakdown_result, all_departments_result,
                    speciality_breakdown_result, all_specialities_result,
                    course_breakdown_result, all_courses_result
                )
                
                # Get comparison data (previous period vs current period)
                comparison_data = self._get_comparison_data(start_date, end_date, query_params)
                
                # Compile the response data
                analytics_data = {
                    'records': records_data,
                    'summary': summary_stats,
                    'breakdown': breakdown_data,
                    'comparison': comparison_data,
                    'trends': {
                        'overall_trend': 'improving',
                        'peak_day': 'Wednesday',
                        'challenge_day': 'Friday',
                        'improvement_rate': f"{comparison_data['trend']['percent_change']:+.1f}%",
                        'late_arrival_rate': summary_stats['late_percentage']
                    },
                    'recommendations': {
                        'target_interventions': [
                            'Implement Friday-specific engagement strategies',
                            'Early arrival incentives for Arts department',
                            'Personalized attendance counseling for flagged students'
                        ],
                        'improvement_opportunities': [
                            'Utilize Wednesday\'s high attendance momentum',
                            'Cross-department mentorship programs',
                            'Regular attendance tracking communications'
                        ]
                    },
                    'date_range': {
                        'start': start_date,
                        'end': end_date,
                        'period': period
                    },
                    'filters_applied': {
                        'department': filters.get('department'),
                        'speciality': filters.get('speciality'),
                        'course': filters.get('course'),
                        'status': filters.get('status'),
                        'student_search': filters.get('student_search')
                    }
                }
                
                return custom_response(
                    success=True,
                    data=analytics_data,
                    status_code=200
                )
                
        except Exception as e:
            logger.error(f"Error getting detailed attendance analytics: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to get detailed attendance analytics: {str(e)}",
                status_code=500
            )

    def _calculate_date_range_with_filters(self, period: str, **filters) -> tuple:
        """
        Calculate date range with support for custom date filters
        
        Args:
            period: Time period ('today', '7d', '30d', '90d', 'custom')
            **filters: Additional filters including start_date and end_date
            
        Returns:
            Tuple of (start_date, end_date)
        """
        end_date = datetime.now().date()
        
        if period == 'custom' and filters.get('start_date') and filters.get('end_date'):
            return filters['start_date'], filters['end_date']
        elif filters.get('start_date') and filters.get('end_date'):
            return filters['start_date'], filters['end_date']
        else:
            # Fall back to period-based calculation
                    return self._calculate_date_range(period)

    def _create_comprehensive_breakdown(self, department_breakdown_result, all_departments_result,
                                       speciality_breakdown_result, all_specialities_result,
                                       course_breakdown_result, all_courses_result):
        """
        Create comprehensive breakdown data that includes all departments, specialities, and courses
        even those with zero attendance records
        """
        breakdown_data = []
        
        # Create dictionaries for quick lookup
        dept_attendance = {dept.department: {
            'total_sessions': dept.total_sessions,
            'present_count': dept.present_count,
            'absent_count': dept.absent_count,
            'late_count': dept.late_count,
            'excused_count': dept.excused_count,
            'students_count': dept.students_count
        } for dept in department_breakdown_result}
        
        spec_attendance = {(spec.speciality, spec.department): {
            'total_sessions': spec.total_sessions,
            'present_count': spec.present_count,
            'absent_count': spec.absent_count,
            'late_count': spec.late_count,
            'excused_count': spec.excused_count,
            'students_count': spec.students_count
        } for spec in speciality_breakdown_result}
        
        course_attendance = {(course.course_code, course.department, course.speciality): {
            'total_sessions': course.total_sessions,
            'present_count': course.present_count,
            'absent_count': course.absent_count,
            'late_count': course.late_count,
            'excused_count': course.excused_count,
            'students_count': course.students_count
        } for course in course_breakdown_result}
        
        # Process departments (add all departments with attendance data or zeros)
        for dept in all_departments_result:
            dept_name = dept.department
            attendance_data = dept_attendance.get(dept_name, {
                'total_sessions': 0,
                'present_count': 0,
                'absent_count': 0,
                'late_count': 0,
                'excused_count': 0,
                'students_count': 0
            })
            
            attendance_rate = (attendance_data['present_count'] / attendance_data['total_sessions'] * 100 
                             if attendance_data['total_sessions'] > 0 else 0)
            
            breakdown_data.append({
                'department': dept_name,
                'speciality': 'All Specialities',
                'course_code': 'All Courses',
                'total_sessions': attendance_data['total_sessions'],
                'present_count': attendance_data['present_count'],
                'absent_count': attendance_data['absent_count'],
                'late_count': attendance_data['late_count'],
                'excused_count': attendance_data['excused_count'],
                'attendance_rate': round(attendance_rate, 1),
                'students_count': attendance_data['students_count'],
                'level': 'department'
            })
        
        # Process specialities (add all specialities with attendance data or zeros)
        for spec in all_specialities_result:
            spec_name = spec.speciality
            dept_name = spec.department or 'Unknown'
            key = (spec_name, dept_name)
            
            attendance_data = spec_attendance.get(key, {
                'total_sessions': 0,
                'present_count': 0,
                'absent_count': 0,
                'late_count': 0,
                'excused_count': 0,
                'students_count': 0
            })
            
            attendance_rate = (attendance_data['present_count'] / attendance_data['total_sessions'] * 100 
                             if attendance_data['total_sessions'] > 0 else 0)
            
            breakdown_data.append({
                'department': dept_name,
                'speciality': spec_name,
                'course_code': 'All Courses',
                'total_sessions': attendance_data['total_sessions'],
                'present_count': attendance_data['present_count'],
                'absent_count': attendance_data['absent_count'],
                'late_count': attendance_data['late_count'],
                'excused_count': attendance_data['excused_count'],
                'attendance_rate': round(attendance_rate, 1),
                'students_count': attendance_data['students_count'],
                'level': 'speciality'
            })
        
        # Process courses (add all courses with attendance data or zeros)
        for course in all_courses_result:
            course_code = course.course_code
            course_title = course.course_title
            
            # Find courses that have attendance in any department/speciality
            course_keys = [key for key in course_attendance.keys() if key[0] == course_code]
            
            if course_keys:
                # Aggregate data across all departments/specialities for this course
                aggregated_data = {
                    'total_sessions': 0,
                    'present_count': 0,
                    'absent_count': 0,
                    'late_count': 0,
                    'excused_count': 0,
                    'students_count': 0
                }
                
                for key in course_keys:
                    data = course_attendance[key]
                    aggregated_data['total_sessions'] += data['total_sessions']
                    aggregated_data['present_count'] += data['present_count']
                    aggregated_data['absent_count'] += data['absent_count']
                    aggregated_data['late_count'] += data['late_count']
                    aggregated_data['excused_count'] += data['excused_count']
                    aggregated_data['students_count'] = max(aggregated_data['students_count'], data['students_count'])
                
                # Use the first department/speciality for this course
                first_key = course_keys[0]
                dept_name = first_key[1]
                spec_name = first_key[2]
            else:
                # No attendance data for this course
                aggregated_data = {
                    'total_sessions': 0,
                    'present_count': 0,
                    'absent_count': 0,
                    'late_count': 0,
                    'excused_count': 0,
                    'students_count': 0
                }
                dept_name = 'Unknown'
                spec_name = 'Unknown'
            
            attendance_rate = (aggregated_data['present_count'] / aggregated_data['total_sessions'] * 100 
                             if aggregated_data['total_sessions'] > 0 else 0)
            
            breakdown_data.append({
                'department': dept_name,
                'speciality': spec_name,
                'course_code': course_code,
                'course_title': course_title,
                'total_sessions': aggregated_data['total_sessions'],
                'present_count': aggregated_data['present_count'],
                'absent_count': aggregated_data['absent_count'],
                'late_count': aggregated_data['late_count'],
                'excused_count': aggregated_data['excused_count'],
                'attendance_rate': round(attendance_rate, 1),
                'students_count': aggregated_data['students_count'],
                'level': 'course'
            })
        
        return breakdown_data
    
    def _get_comparison_data(self, start_date, end_date, filters):
        """
        Get comparison data between previous period and current period
        """
        try:
            # Calculate previous period dates
            current_days = (end_date - start_date).days
            previous_end_date = start_date - timedelta(days=1)
            previous_start_date = previous_end_date - timedelta(days=current_days)
            
            # Build comparison query for current period
            current_query = text("""
                SELECT 
                    COALESCE(s.department, 'Unknown') as department,
                    COUNT(CASE WHEN a.status = 'present' THEN 1 END) as present_count,
                    COUNT(*) as total_sessions,
                    COUNT(CASE WHEN a.status = 'absent' THEN 1 END) as absent_count,
                    COUNT(CASE WHEN a.status = 'late' THEN 1 END) as late_count,
                    COUNT(CASE WHEN a.status = 'excused' THEN 1 END) as excused_count
                FROM attendance a
                LEFT JOIN students s ON a.student_id = s.id
                LEFT JOIN teaching_session ts ON a.session_id = ts.id
                LEFT JOIN daily_teaching_sessions dts ON a.daily_session_id = dts.id
                WHERE COALESCE(dts.session_date, DATE('now')) BETWEEN :current_start AND :current_end
                GROUP BY COALESCE(s.department, 'Unknown')
            """)
            
            # Build comparison query for previous period
            previous_query = text("""
                SELECT 
                    COALESCE(s.department, 'Unknown') as department,
                    COUNT(CASE WHEN a.status = 'present' THEN 1 END) as present_count,
                    COUNT(*) as total_sessions,
                    COUNT(CASE WHEN a.status = 'absent' THEN 1 END) as absent_count,
                    COUNT(CASE WHEN a.status = 'late' THEN 1 END) as late_count,
                    COUNT(CASE WHEN a.status = 'excused' THEN 1 END) as excused_count
                FROM attendance a
                LEFT JOIN students s ON a.student_id = s.id
                LEFT JOIN teaching_session ts ON a.session_id = ts.id
                LEFT JOIN daily_teaching_sessions dts ON a.daily_session_id = dts.id
                WHERE COALESCE(dts.session_date, DATE('now')) BETWEEN :previous_start AND :previous_end
                GROUP BY COALESCE(s.department, 'Unknown')
            """)
            
            query_params = {
                'current_start': start_date,
                'current_end': end_date,
                'previous_start': previous_start_date,
                'previous_end': previous_end_date
            }
            
            # Apply filters to both queries
            if filters.get('department'):
                current_query = text(str(current_query) + " AND s.department = :department")
                previous_query = text(str(previous_query) + " AND s.department = :department")
                query_params['department'] = filters['department']
            
            if filters.get('speciality'):
                current_query = text(str(current_query) + " AND s.speciality_id IN (SELECT id FROM specialities WHERE name = :speciality)")
                previous_query = text(str(previous_query) + " AND s.speciality_id IN (SELECT id FROM specialities WHERE name = :speciality)")
                query_params['speciality'] = filters['speciality']
            
            if filters.get('status'):
                current_query = text(str(current_query) + " AND a.status = :status")
                previous_query = text(str(previous_query) + " AND a.status = :status")
                query_params['status'] = filters['status']
            
            with DatabaseContextManager() as ctx:
                # Get current period data
                current_results = ctx.session.execute(current_query, query_params).fetchall()
                # Get previous period data
                previous_results = ctx.session.execute(previous_query, query_params).fetchall()
                
                # Create dictionaries for easy lookup
                current_data = {dept.department: dept for dept in current_results}
                previous_data = {dept.department: dept for dept in previous_results}
                
                # Combine all departments from both periods
                all_departments = set(current_data.keys()) | set(previous_data.keys())
                
                comparison_chart_data = []
                total_current_present = 0
                total_current_sessions = 0
                total_previous_present = 0
                total_previous_sessions = 0
                
                for dept in all_departments:
                    current = current_data.get(dept)
                    previous = previous_data.get(dept)
                    
                    current_present_pct = (current.present_count / current.total_sessions * 100) if current and current.total_sessions > 0 else 0
                    previous_present_pct = (previous.present_count / previous.total_sessions * 100) if previous and previous.total_sessions > 0 else 0
                    
                    comparison_chart_data.append({
                        'department': dept,
                        'current_period': current_present_pct,
                        'previous_period': previous_present_pct,
                        'current_sessions': current.total_sessions if current else 0,
                        'previous_sessions': previous.total_sessions if previous else 0,
                        'change': current_present_pct - previous_present_pct
                    })
                    
                    # Accumulate totals
                    total_current_present += current.present_count if current else 0
                    total_current_sessions += current.total_sessions if current else 0
                    total_previous_present += previous.present_count if previous else 0
                    total_previous_sessions += previous.total_sessions if previous else 0
                
                # Calculate overall trend
                current_overall_pct = (total_current_present / total_current_sessions * 100) if total_current_sessions > 0 else 0
                previous_overall_pct = (total_previous_present / total_previous_sessions * 100) if total_previous_sessions > 0 else 0
                overall_change = current_overall_pct - previous_overall_pct
                
                return {
                    'chart_data': sorted(comparison_chart_data, key=lambda x: abs(x['change']), reverse=True),
                    'period_info': {
                        'current_period': f"{start_date} to {end_date}",
                        'previous_period': f"{previous_start_date} to {previous_end_date}"
                    },
                    'trend': {
                        'current_percentage': round(current_overall_pct, 1),
                        'previous_percentage': round(previous_overall_pct, 1),
                        'percent_change': round(overall_change, 1),
                        'direction': 'up' if overall_change > 0 else 'down' if overall_change < 0 else 'stable'
                    },
                    'summary': {
                        'total_current_sessions': total_current_sessions,
                        'total_previous_sessions': total_previous_sessions,
                        'total_current_present': total_current_present,
                        'total_previous_present': total_previous_present
                    }
                }
                
        except Exception as e:
            logger.error(f"Error getting comparison data: {str(e)}")
            return {
                'chart_data': [],
                'period_info': {
                    'current_period': f"{start_date} to {end_date}",
                    'previous_period': 'Previous period'
                },
                'trend': {
                    'current_percentage': 0,
                    'previous_percentage': 0,
                    'percent_change': 0,
                    'direction': 'stable'
                },
                'summary': {
                    'total_current_sessions': 0,
                    'total_previous_sessions': 0,
                    'total_current_present': 0,
                    'total_previous_present': 0
                }
            }
    
    def get_enrollment_departments(self) -> Dict:
        """
        Get unique departments from supervisor departments table
        
        Returns:
            Response with list of departments for enrollment
        """
        try:
            with DatabaseContextManager() as ctx:
                # Query to get unique departments from supervisors table via supervisor_departments
                departments_query = text("""
                    SELECT DISTINCT sd.department_name as department
                    FROM supervisor_departments sd
                    WHERE sd.department_name IS NOT NULL 
                    AND sd.department_name != ''
                    ORDER BY sd.department_name
                """)
                
                result = ctx.session.execute(departments_query).fetchall()
                departments = [row.department for row in result if row.department and row.department.strip()]
                
                return custom_response(
                    success=True,
                    data=departments,
                    status_code=200
                )
                
        except Exception as e:
            logger.error(f"Error fetching enrollment departments: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to fetch departments: {str(e)}",
                status_code=500
            )

    def get_department_specialities(self, department: str = None) -> Dict:
        """
        Get specialities for a specific department or all specialities
        
        Args:
            department: Optional department name to filter specialities
            
        Returns:
            Response with list of specialities for the department
        """
        try:
            with DatabaseContextManager() as ctx:
                if department:
                    # Query to get specialities for specific department
                    specialities_query = text("""
                        SELECT DISTINCT sp.id, sp.name, sp.description
                        FROM specialities sp
                        LEFT JOIN students st ON sp.id = st.speciality_id
                        WHERE sp.name IS NOT NULL 
                        AND sp.name != ''
                        UNION
                        SELECT DISTINCT sp.id, sp.name, sp.description
                        FROM specialities sp
                        JOIN supervisor_course_association sca ON sca.supervisor_id IN (
                            SELECT supervisor_id FROM supervisor_departments sd 
                            WHERE sd.department_name = :department
                        )
                        JOIN courses c ON sca.course_id = c.id
                        JOIN course_speciality_association csa ON c.id = csa.course_id
                        WHERE csa.speciality_id = sp.id
                        AND sp.name IS NOT NULL 
                        AND sp.name != ''
                        ORDER BY sp.name
                    """)
                    
                    result = ctx.session.execute(specialities_query, {'department': department}).fetchall()
                    specialities = [
                        {'id': row.id, 'name': row.name, 'description': row.description or ''}
                        for row in result 
                        if row.name and row.name.strip()
                    ]
                else:
                    # Query to get all specialities
                    specialities_query = text("""
                        SELECT DISTINCT sp.id, sp.name, sp.description
                        FROM specialities sp
                        WHERE sp.name IS NOT NULL 
                        AND sp.name != ''
                        ORDER BY sp.name
                    """)
                    
                    result = ctx.session.execute(specialities_query).fetchall()
                    specialities = [
                        {'id': row.id, 'name': row.name, 'description': row.description or ''}
                        for row in result 
                        if row.name and row.name.strip()
                    ]
                
                return custom_response(
                    success=True,
                    data=specialities,
                    status_code=200
                )
                
        except Exception as e:
            logger.error(f"Error fetching department specialities: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to fetch specialities: {str(e)}",
                status_code=500
            )

    def get_speciality_courses(self, speciality: str) -> Dict:
        """
        Get courses for a specific speciality
        
        Args:
            speciality: Speciality name to get courses for
            
        Returns:
            Response with list of courses for the speciality
        """
        try:
            with DatabaseContextManager() as ctx:
                courses_query = text("""
                    SELECT DISTINCT c.id, c.title, c.description, c.total_hours
                    FROM courses c
                    LEFT JOIN course_speciality_association csa ON c.id = csa.course_id
                    LEFT JOIN specialities sp_assoc ON csa.speciality_id = sp_assoc.id
                    LEFT JOIN specialities sp_direct ON c.speciality_id = sp_direct.id
                    WHERE (
                        sp_assoc.name = :speciality OR sp_direct.name = :speciality
                    )
                    AND c.title IS NOT NULL 
                    AND c.title != ''
                    ORDER BY c.title
                """)
                
                result = ctx.session.execute(courses_query, {'speciality': speciality}).fetchall()
                courses = [
                    {
                        'id': str(row.id),
                        'name': row.title,
                        'description': row.description or '',
                        'total_hours': row.total_hours or 0
                    }
                    for row in result 
                    if row.title and row.title.strip()
                ]
                
                return custom_response(
                    success=True,
                    data=courses,
                    status_code=200
                )
                
        except Exception as e:
            logger.error(f"Error fetching speciality courses: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to fetch courses: {str(e)}",
                status_code=500
            )

    def get_students_without_enrollments(self, search: str = None) -> Dict:
        """
        Get students who have no enrollments; optional search by name/email/phone.
        """
        try:
            with DatabaseContextManager() as ctx:
                base_sql = """
                    SELECT 
                        st.id as student_id,
                        u.first_name,
                        u.last_name,
                        u.email,
                        u.phone,
                        COALESCE(st.department, 'Unknown') as department,
                        COALESCE(sp.name, 'Unknown') as speciality
                    FROM students st
                    JOIN users u ON st.id = u.id
                    LEFT JOIN specialities sp ON st.speciality_id = sp.id
                    LEFT JOIN enrollments e ON e.student_id = st.id
                    WHERE e.id IS NULL
                """

                params = {}
                if search:
                    base_sql += " AND ((u.first_name || ' ' || u.last_name) LIKE :q OR u.email LIKE :q OR u.phone LIKE :q)"
                    params['q'] = f"%{search}%"

                base_sql += " ORDER BY u.first_name, u.last_name"

                result = ctx.session.execute(text(base_sql), params).fetchall()

                students = [
                    {
                        'id': row.student_id,
                        'name': f"{row.first_name} {row.last_name}",
                        'email': row.email,
                        'phone': row.phone,
                        'department': row.department,
                        'speciality': row.speciality
                    }
                    for row in result
                ]

                return custom_response(success=True, data=students, status_code=200)

        except Exception as e:
            logger.error(f"Error fetching students without enrollments: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to fetch eligible students: {str(e)}",
                status_code=500
            )
    
    def get_student_enrollment_analytics(self, period: str = '30d', **filters) -> Dict:
        """
        Get comprehensive enrollment analytics data
        
        Returns:
            Response with enrollment analytics data
        """
        try:
            with DatabaseContextManager() as ctx:
                # Calculate date range
                start_date, end_date = self._calculate_date_range(period)
                
                # Get basic enrollment statistics
                total_enrollments_query = text("""
                    SELECT COUNT(*) as total_count FROM enrollments e
                    WHERE e.enrollment_date >= :start_date AND e.enrollment_date <= :end_date
                """)
                
                active_enrollments_query = text("""
                    SELECT COUNT(*) as active_count FROM enrollments e
                    WHERE e.enrollment_date >= :start_date AND e.enrollment_date <= :end_date
                    AND e.status = 'active'
                """)
                
                pending_enrollments_query = text("""
                    SELECT COUNT(*) as pending_count FROM enrollments e
                    WHERE e.enrollment_date >= :start_date AND e.enrollment_date <= :end_date
                    AND e.status = 'pending'
                """)
                
                graduated_students_query = text("""
                    SELECT COUNT(*) as graduated_count FROM enrollments e
                    WHERE e.enrollment_date >= :start_date AND e.enrollment_date <= :end_date
                    AND e.status = 'graduated'
                """)
                
                # Execute queries
                total_enrollments = ctx.session.execute(total_enrollments_query, {
                    'start_date': start_date, 'end_date': end_date
                }).scalar() or 0
                
                active_enrollments = ctx.session.execute(active_enrollments_query, {
                    'start_date': start_date, 'end_date': end_date
                }).scalar() or 0
                
                pending_enrollments = ctx.session.execute(pending_enrollments_query, {
                    'start_date': start_date, 'end_date': end_date
                }).scalar() or 0
                
                graduated_students = ctx.session.execute(graduated_students_query, {
                    'start_date': start_date, 'end_date': end_date
                }).scalar() or 0
                
                # Get enrollment trends (monthly)
                trends_query = text("""
                    SELECT 
                        strftime('%Y-%m', e.enrollment_date) as period,
                        COUNT(*) as enrollments,
                        COUNT(CASE WHEN e.status = 'graduated' THEN 1 END) as graduations
                    FROM enrollments e
                    WHERE e.enrollment_date >= :start_date AND e.enrollment_date <= :end_date
                    GROUP BY strftime('%Y-%m', e.enrollment_date)
                    ORDER BY period
                """)
                
                trends_result = ctx.session.execute(trends_query, {
                    'start_date': start_date, 'end_date': end_date
                }).fetchall()
                
                enrollment_trends = [
                    {
                        'period': row.period,
                        'enrollments': row.enrollments,
                        'graduations': row.graduations
                    }
                    for row in trends_result
                ]
                
                # Get department distribution
                department_query = text("""
                    SELECT 
                        COALESCE(st.department, 'Unknown') as department,
                        COUNT(*) as count,
                        ROUND(COUNT(*) * 100.0 / total.total_count, 2) as percentage
                    FROM enrollments e
                    LEFT JOIN students st ON e.student_id = st.id
                    CROSS JOIN (
                        SELECT COUNT(*) as total_count FROM enrollments e2
                        WHERE e2.enrollment_date >= :start_date AND e2.enrollment_date <= :end_date
                    ) as total
                    WHERE e.enrollment_date >= :start_date AND e.enrollment_date <= :end_date
                    GROUP BY COALESCE(st.department, 'Unknown')
                    ORDER BY count DESC
                """)
                
                department_result = ctx.session.execute(department_query, {
                    'start_date': start_date, 'end_date': end_date
                }).fetchall()
                
                department_distribution = [
                    {
                        'department': row.department,
                        'count': row.count,
                        'percentage': row.percentage
                    }
                    for row in department_result
                ]
                
                # Get speciality distribution
                speciality_query = text("""
                    SELECT 
                        COALESCE(sp.name, 'Unknown') as speciality,
                        COALESCE(st.department, 'Unknown') as department,
                        COUNT(*) as count,
                        ROUND(COUNT(*) * 100.0 / total.total_count, 2) as percentage
                    FROM enrollments e
                    LEFT JOIN students st ON e.student_id = st.id
                    LEFT JOIN specialities sp ON st.speciality_id = sp.id
                    CROSS JOIN (
                        SELECT COUNT(*) as total_count FROM enrollments e2
                        WHERE e2.enrollment_date >= :start_date AND e2.enrollment_date <= :end_date
                    ) as total
                    WHERE e.enrollment_date >= :start_date AND e.enrollment_date <= :end_date
                    GROUP BY COALESCE(sp.name, 'Unknown'), COALESCE(st.department, 'Unknown')
                    ORDER BY count DESC
                    LIMIT 20
                """)
                
                speciality_result = ctx.session.execute(speciality_query, {
                    'start_date': start_date, 'end_date': end_date
                }).fetchall()
                
                speciality_distribution = [
                    {
                        'speciality': row.speciality,
                        'department': row.department,
                        'count': row.count,
                        'percentage': row.percentage
                    }
                    for row in speciality_result
                ]
                
                # Get status distribution
                status_query = text("""
                    SELECT 
                        e.status,
                        COUNT(*) as count
                    FROM enrollments e
                    WHERE e.enrollment_date >= :start_date AND e.enrollment_date <= :end_date
                    GROUP BY e.status
                    ORDER BY count DESC
                """)
                
                status_result = ctx.session.execute(status_query, {
                    'start_date': start_date, 'end_date': end_date
                }).fetchall()
                
                status_distribution = [
                    {
                        'status': row.status,
                        'count': row.count
                    }
                    for row in status_result
                ]
                
                # Mock payment status for now (to be implemented with actual payment data)
                payment_status_analytics = [
                    {'status': 'paid', 'count': active_enrollments, 'amount_due': 0},
                    {'status': 'partial', 'count': pending_enrollments, 'amount_due': 1000},
                    {'status': 'pending', 'count': max(0, pending_enrollments - 5), 'amount_due': 2000},
                    {'status': 'overdue', 'count': max(0, pending_enrollments - 3), 'amount_due': 5000}
                ]
                
                return custom_response(
                    success=True,
                    data={
                        'total_enrollments': total_enrollments,
                        'active_enrollments': active_enrollments,
                        'pending_enrollments': pending_enrollments,
                        'graduated_students': graduated_students,
                        'enrollment_trends': enrollment_trends,
                        'department_distribution': department_distribution,
                        'speciality_distribution': speciality_distribution,
                        'status_distribution': status_distribution,
                        'payment_status_analytics': payment_status_analytics
                    },
                    status_code=200
                )
                
        except Exception as e:
            logger.error(f"Error fetching enrollment analytics: {str(e)}")
            return custom_response(
                success=False,
                data={
                    'total_enrollments': 0,
                    'active_enrollments': 0,
                    'pending_enrollments': 0,
                    'graduated_students': 0,
                    'enrollment_trends': [],
                    'department_distribution': [],
                    'speciality_distribution': [],
                    'status_distribution': [],
                    'payment_status_analytics': []
                },
                status_code=500
            )
    
    def get_student_enrollment_records(self, page: int = 1, limit: int = 10, **filters) -> Dict:
        """
        Get paginated enrollment records with filtering
        
        Returns:
            Response with enrollment records data
        """
        try:
            with DatabaseContextManager() as ctx:
                # Build base query
                base_query = text("""
                    SELECT 
                        e.id,
                        e.student_id,
                        (u.first_name || ' ' || u.last_name) as student_name,
                        u.email as student_email,
                        u.phone as student_phone,
                        COALESCE(st.department, 'Unknown') as department,
                        COALESCE(sp.name, 'Unknown') as speciality,
                        '2024' as academic_year,
                        '1' as semester,
                        e.enrollment_date,
                        e.status,
                        'paid' as payment_status,
                        (
                            SELECT COUNT(*) FROM enrollment_courses ec 
                            WHERE ec.enrollment_id = e.id
                        ) as courses_count,
                        40 as total_hours,
                        CASE 
                            WHEN e.status = 'active' THEN 'high'
                            ELSE 'medium'
                        END as priority_level,
                        COALESCE(e.comments, 'Automated enrollment') as notes
                    FROM enrollments e
                    JOIN students st ON e.student_id = st.id
                    JOIN users u ON st.id = u.id
                    LEFT JOIN specialities sp ON st.speciality_id = sp.id
                """)
                
                # Build WHERE conditions
                where_conditions = []
                query_params = {'offset': (page - 1) * limit, 'limit': limit}
                
                if filters.get('search'):
                    where_conditions.append("((u.first_name || ' ' || u.last_name) LIKE :search OR u.email LIKE :search)")
                    query_params['search'] = f"%{filters['search']}%"
                
                if filters.get('department'):
                    where_conditions.append("COALESCE(st.department, 'Unknown') = :department")
                    query_params['department'] = filters['department']
                
                if filters.get('speciality'):
                    where_conditions.append("COALESCE(sp.name, 'Unknown') = :speciality")
                    query_params['speciality'] = filters['speciality']
                
                if filters.get('status'):
                    where_conditions.append("e.status = :status")
                    query_params['status'] = filters['status']
                
                if filters.get('payment_status'):
                    # For now, mock payment status filtering
                    pass
                
                if filters.get('academic_year'):
                    # For now, academic_year is hardcoded as '2024', so this will always match
                    pass
                
                if filters.get('semester'):
                    # For now, semester is hardcoded as '1', so this will always match
                    pass
                
                # Add WHERE clause if conditions exist
                if where_conditions:
                    base_query = text(str(base_query) + " WHERE " + " AND ".join(where_conditions))
                
                # Build count query
                count_query_start = """
                    SELECT COUNT(*) as total 
                    FROM enrollments e
                    JOIN students st ON e.student_id = st.id
                    JOIN users u ON st.id = u.id
                    LEFT JOIN specialities sp ON st.speciality_id = sp.id
                """
                
                count_query_conditions = []
                count_query_params = {}
                
                # Apply same filters to count query
                if filters.get('search'):
                    count_query_conditions.append("((u.first_name || ' ' || u.last_name) LIKE :search OR u.email LIKE :search)")
                    count_query_params['search'] = f"%{filters['search']}%"
                
                if filters.get('department'):
                    count_query_conditions.append("COALESCE(st.department, 'Unknown') = :department")
                    count_query_params['department'] = filters['department']
                
                if filters.get('speciality'):
                    count_query_conditions.append("COALESCE(sp.name, 'Unknown') = :speciality")
                    count_query_params['speciality'] = filters['speciality']
                
                if filters.get('status'):
                    count_query_conditions.append("e.status = :status")
                    count_query_params['status'] = filters['status']
                
                if filters.get('payment_status'):
                    # For now, payment status is hardcoded as 'paid', so this will always match
                    pass
                
                if filters.get('academic_year'):
                    # For now, academic_year is hardcoded as '2024', so this will always match
                    pass
                
                if filters.get('semester'):
                    # For now, semester is hardcoded as '1', so this will always match
                    pass
                
                # Combine count query
                if count_query_conditions:
                    count_query = text(count_query_start + " WHERE " + " AND ".join(count_query_conditions))
                else:
                    count_query = text(count_query_start)
                
                # Add count query params to main query params
                for key, value in count_query_params.items():
                    query_params[key] = value
                
                # Get total count
                total_result = ctx.session.execute(count_query, query_params).fetchone()
                total_items = total_result.total if total_result else 0
                
                # Add pagination
                final_query = text(str(base_query) + " ORDER BY e.enrollment_date DESC LIMIT :limit OFFSET :offset")
                
                # Execute query
                result = ctx.session.execute(final_query, query_params).fetchall()
                
                # Convert to list of dictionaries
                records = []
                for row in result:
                    records.append({
                        'id': str(row.id),
                        'student_id': str(row.student_id),
                        'student_name': row.student_name or 'Unknown Student',
                        'student_email': row.student_email or 'No email',
                        'student_phone': row.student_phone or 'No phone',
                        'department': row.department,
                        'speciality': row.speciality,
                        'academic_year': row.academic_year or '2024',
                        'semester': row.semester or '1',
                        'enrollment_date': str(row.enrollment_date) if row.enrollment_date else '',
                        'status': row.status or 'pending',
                        'payment_status': row.payment_status or 'pending',
                        'courses_count': row.courses_count or 0,
                        'total_hours': row.total_hours or 0,
                        'priority_level': row.priority_level or 'low',
                        'notes': row.notes or ''
                    })
                
                return custom_response(
                    success=True,
                    data={
                        'records': records,
                        'total': total_items,
                        'page': page,
                        'limit': limit,
                        'total_pages': (total_items + limit - 1) // limit
                    },
                    status_code=200
                )
                
        except Exception as e:
            logger.error(f"Error fetching enrollment records: {str(e)}")
            return custom_response(
                success=False,
                data=f"Failed to fetch enrollment records: {str(e)}",
                status_code=500
            )