<?php
/**
 * Dashboard Class
 * 
 * Handles user dashboard functionality with role-based access
 * 
 * @package Spacetree
 * @subpackage Dashboard
 * @since 1.0.0
 * @v2.1.0 - checking
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

class ST_Dashboard {
    
    /**
     * Current user ID
     * 
     * @var int
     */
    private $user_id;
    
    /**
     * Normalized user role (admin, teacher, or student)
     * 
     * @var string
     */
    private $role;
    
    /**
     * Current user object with all necessary data
     * 
     * @var object
     */
    private $current_user;
    
    /**
     * Courses array
     * 
     * @var array
     */
    private $courses = array();
    
    /**
     * Quiz analytics object
     * 
     * @var object
     */
    private $quizzes_analytics;
    
    /**
     * Evaluation settings
     * 
     * @var object
     */
    private $evaluation_settings;
    
    /**
     * Submissions table name
     * 
     * @var string
     */
    private $submissions_table;
    
    /**
     * Submissions meta table name
     * 
     * @var string
     */
    private $meta_table;

    /**
     * Score table name
     * 
     * @var string
     */
    public $score_table;
    
    /**
     * Groups table name
     * 
     * @var string
     */
    private $groups_table;

    /**
     * Session table name
     * 
     * @var string
     */
    private $session_table;
    
    /**
     * Users table name
     * 
     * @var string
     */
    private $users_table;

    /**
     * Evaluation metadata table name
     * 
     * @var string
     */
    public $evaluation_meta_table;

    /**
     * Review meta table name
     * 
     * @var string
     */
    public $review_meta_table;
    /**
     * review core table name
     * 
     * @var string
     */
    public $review_table;
    
    /**
     * Constructor
     * 
     * Initializes the dashboard with current user data
     * 
     * @param int $user_id WordPress user ID
     * @param bool $lightweight If true, skip heavy calculations (for AJAX with cache)
     */
    public function __construct( $user_id, $lightweight = false ) {
        global $wpdb;
        
        // Initialize table names
        $this->submissions_table = $wpdb->prefix . 'st_proqyz_v3_progress_submissions';
        $this->meta_table = $wpdb->prefix . 'st_proqyz_v3_progress_submissions_meta';
        $this->score_table = $wpdb->prefix . 'st_proqyz_v3_progress_submissions_score';
        $this->groups_table = $wpdb->prefix . 'st_proqyz_groups';
        $this->users_table = $wpdb->prefix . 'users';
        $this->evaluation_meta_table = $wpdb->prefix . 'st_proqyz_v3_submissions_evaluation_meta';
        $this->session_table = $wpdb->prefix . 'st_proqyz_v3_progress_submissions_session';
        $this->review_table = $wpdb->prefix . 'st_proqyz_v3_submissions_review';
        $this->review_meta_table = $wpdb->prefix . 'st_proqyz_v3_submissions_review_meta';
        
        // Store user ID
        $this->user_id = absint( $user_id );
        
        if ( $lightweight ) {
            // Lightweight mode - only basic initialization
            // Get user role (needed for rendering)
            $wp_user = get_userdata( $this->user_id );
            if ( ! $wp_user ) {
                wp_die( 'Invalid user ID' );
            }
            $this->role = $this->normalize_user_role( $wp_user->roles );
            
            // Initialize minimal current_user object
            $this->current_user = (object) array(
                'user_id' => $this->user_id,
                'role'    => $this->role,
            );
            
            // Initialize evaluation settings (lightweight - just checks options/products)
            $this->init_evaluation_settings();
            
        } else {
            // Full initialization
            // Initialize user data
            $this->init_user_data();
            
            // Initialize courses
            $this->init_courses();
            
            // Calculate quiz analytics
            $this->calculate_quizzes();
            
            // Initialize evaluation settings (for writing/speaking score display)
            $this->init_evaluation_settings();
        }
    }
    
    /**
     * Initialize user data
     * 
     * Fetches and stores all necessary user information
     * 
     * @return void
     */
    private function init_user_data() {
        // Get WordPress user object
        $wp_user = get_userdata( $this->user_id );
        
        // Validate user exists
        if ( ! $wp_user ) {
            wp_die( 'Invalid user ID' );
        }
        
        // Determine and normalize user role
        $this->role = $this->normalize_user_role( $wp_user->roles );
        
        // Build current_user object
        $this->current_user = (object) array(
            'user_id'      => $this->user_id,
            'role'         => $this->role,
            'username'     => $wp_user->user_login,
            'nickname'     => $wp_user->nickname,
            'email'        => $wp_user->user_email,
            'display_name' => $this->get_display_name( $wp_user ),
            'avatar'       => get_avatar_url( $this->user_id, array( 'size' => 96 ) ),
            'first_name'   => get_user_meta( $this->user_id, 'first_name', true ),
            'last_name'    => get_user_meta( $this->user_id, 'last_name', true ),
        );
        
        // Extend user object with role-specific data
        $this->extend_user_data();
    }
    
    /**
     * Normalize user role
     * 
     * Maps WordPress roles to simplified dashboard roles:
     * - admin → admin
     * - instructor, teacher, trainer → teacher
     * - everything else → student
     * 
     * @param array $roles Array of user roles
     * @return string Normalized role (admin, teacher, or student)
     */
    private function normalize_user_role( $roles ) {
        // Handle empty roles
        if ( empty( $roles ) || ! is_array( $roles ) ) {
            return 'student';
        }
        
        // Check for admin role first (highest priority)
        if ( in_array( 'administrator', $roles, true ) ) {
            return 'admin';
        }
        
        // Define teacher-equivalent roles
        $teacher_roles = array( 'instructor', 'teacher', 'trainer' );
        
        // Check if user has any teacher role
        foreach ( $roles as $role ) {
            if ( in_array( strtolower( $role ), $teacher_roles, true ) ) {
                return 'teacher';
            }
        }
        
        // Default to student for all other roles
        return 'student';
    }
    
    /**
     * Get display name
     * 
     * Returns display_name if set, otherwise constructs from first_name + last_name
     * Falls back to username if no name is available
     * 
     * @param WP_User $wp_user WordPress user object
     * @return string Display name
     */
    private function get_display_name( $wp_user ) {
        // First try display_name
        if ( ! empty( $wp_user->display_name ) ) {
            return $wp_user->display_name;
        }
        
        // Get first and last name from metadata
        $first_name = get_user_meta( $this->user_id, 'first_name', true );
        $last_name  = get_user_meta( $this->user_id, 'last_name', true );
        
        // Construct full name if both exist
        if ( ! empty( $first_name ) || ! empty( $last_name ) ) {
            return trim( $first_name . ' ' . $last_name );
        }
        
        // Fall back to username
        return $wp_user->user_login;
    }
    
    /**
     * Extend user data with role-specific information
     * 
     * Adds student_ids, teacher_ids, or admin_ids based on role
     * 
     * @return void
     */
    private function extend_user_data() {
        if ( $this->role === 'admin' || $this->role === 'teacher') {
            $this->extend_admin_data();
        } elseif ( $this->role === 'student' ) {
            $this->extend_student_data();
        }
    }
    
    /**
     * Extend admin user data
     * 
     * Gets all distinct student user_ids from submissions table
     * 
     * @return void
     */
    private function extend_admin_data() {
        global $wpdb;
        
        // Get distinct user_ids from submissions
        $user_ids = $wpdb->get_col(
            "SELECT DISTINCT user_id 
            FROM {$this->submissions_table} 
            WHERE user_id IS NOT NULL"
        );
        
        if ( empty( $user_ids ) ) {
            $this->current_user->student_ids = array();
            $this->current_user->students_count = 0;
            return;
        }
        
        // Filter only users with student role and collect data for sorting
        $students_data = array();
        foreach ( $user_ids as $user_id ) {
            $user = get_userdata( $user_id );
            if ( $user && ! is_wp_error( $user ) ) {
                // Check if user has student role (or subscriber, or any non-admin/teacher role)
                $user_roles = $user->roles;
                $user_username = $user->user_login;
                // user email
                $user_email = $user->user_email;
                $is_student = true;
                
                // Exclude if user is admin or teacher
                foreach ( $user_roles as $role ) {
                    if ( in_array( strtolower( $role ), array( 'administrator', 'instructor', 'teacher', 'trainer' ), true ) ) {
                        $is_student = false;
                        break;
                    }
                }
                
                if ( $is_student ) {
                    $students_data[] = array(
                        'user_id' => (string) $user_id,
                        'username' => $user_username,
                        'email' => $user_email
                    );
                }
            }
        }
        
        // Sort students by username in alphabetical order (A-Z, then 0-9)
        usort( $students_data, function( $a, $b ) {
            return strcasecmp( $a['username'], $b['username'] );
        });
        
        // Extract sorted user IDs
        $student_ids = array_column( $students_data, 'user_id' );
        
        $this->current_user->student_ids = $student_ids;
        $this->current_user->students_count = count( $student_ids );
    }
    
    /**
     * Extend student user data
     * 
     * Gets teacher_ids and admin_ids
     * - Teachers: From groups where student is assigned
     * - Admins: All users with administrator role
     * 
     * @return void
     */
    private function extend_student_data() {

        // Get all administrators
        $admin_users = get_users( array( 'role' => 'administrator' ) );
        $admin_ids = array();
        foreach ( $admin_users as $admin_user ) {
            $admin_ids[] = (string) $admin_user->ID;
        }
        
        $this->current_user->teacher_ids = [];
        $this->current_user->teachers_count = 0;
        $this->current_user->admin_ids = $admin_ids;
        $this->current_user->admins_count = count( $admin_ids );
    }
    
    /**
     * Get user ID
     * 
     * @return int User ID
     */
    public function get_user_id() {
        return $this->user_id;
    }
    
    /**
     * Get user role
     * 
     * @return string Normalized role (admin, teacher, or student)
     */
    public function get_role() {
        return $this->role;
    }
    
    /**
     * Get current user object
     * 
     * @return object Current user data
     */
    public function get_current_user() {
        return $this->current_user;
    }
    
    /**
     * Check if user is admin
     * 
     * @return bool True if admin
     */
    public function is_admin() {
        return $this->role === 'admin';
    }
    
    /**
     * Check if user is teacher
     * 
     * @return bool True if teacher
     */
    public function is_teacher() {
        return $this->role === 'teacher';
    }
    
    /**
     * Check if user is student
     * 
     * @return bool True if student
     */
    public function is_student() {
        return $this->role === 'student';
    }
    
    /**
     * Initialize courses
     * 
     * Fetches distinct courses from submissions table based on user role
     * - Admin: All courses from all submissions
     * - Student: Courses from user's submissions only
     * - Teacher: Courses from groups where teacher is assigned
     * 
     * @return void
     */
    private function init_courses() {
        global $wpdb;
        
        // Build query based on role (admin or student)
        if ( $this->role === 'admin' || $this->role === 'teacher') {
            // Admin: Get all distinct courses
            $query = $wpdb->prepare(
                "SELECT DISTINCT course_id, course_category 
                FROM {$this->submissions_table} 
                WHERE course_id IS NOT NULL 
                AND course_id != '' AND `status` = 1 AND `session_status` != 3
                ORDER BY course_id ASC"
            );
        } else {
            // Student: Get courses for current user only
            $query = $wpdb->prepare(
                "SELECT DISTINCT course_id, course_category 
                FROM {$this->submissions_table} 
                WHERE user_id = %d 
                AND course_id IS NOT NULL 
                AND course_id != '' 
                AND `status` = 1 AND `session_status` != 3
                ORDER BY course_id ASC",
                $this->user_id
            );
        }
        
        // Get distinct courses
        $distinct_courses = $wpdb->get_results( $query, ARRAY_A );
        
        if ( empty( $distinct_courses ) ) {
            $this->courses = array();
            return;
        }
        
        // Build courses array with course titles
        foreach ( $distinct_courses as $course_row ) {
            $course_id = $course_row['course_id'];
            $course_category = $course_row['course_category'];
            
            // Get course title from meta table
            // First, get a submission_id for this course
            if ( $this->role === 'admin' ) {
                $submission_id = $wpdb->get_var( $wpdb->prepare(
                    "SELECT ID FROM {$this->submissions_table} 
                    WHERE course_id = %s 
                    LIMIT 1",
                    $course_id
                ) );
            } else {
                $submission_id = $wpdb->get_var( $wpdb->prepare(
                    "SELECT ID FROM {$this->submissions_table} 
                    WHERE course_id = %s 
                    AND user_id = %d 
                    LIMIT 1",
                    $course_id,
                    $this->user_id
                ) );
            }
            
            // Get course_title from meta table
            $course_title = '';
            if ( $submission_id ) {
                $course_title = $wpdb->get_var( $wpdb->prepare(
                    "SELECT meta_value FROM {$this->meta_table} 
                    WHERE submission_id = %d 
                    AND meta_key = 'course_title' 
                    LIMIT 1",
                    $submission_id
                ) );
            }
            
            // If no course title found, use course_id as fallback
            if ( empty( $course_title ) ) {
                $course_title = 'Course ' . $course_id;
            }
            
            // Add to courses array
            $this->courses[] = (object) array(
                'id'              => $course_id,
                'course_title'    => $course_title,
                'course_category' => $course_category,
            );
        }
    }
    
    /**
     * Get courses
     * 
     * @return array Array of course objects
     */
    public function get_courses() {
        return $this->courses;
    }
    
    /**
     * Get courses count
     * 
     * @return int Number of courses
     */
    public function get_courses_count() {
        return count( $this->courses );
    }
    
    /**
     * Calculate quiz analytics
     * 
     * Counts various quiz types based on user role and enabled LMS modules
     * Uses optimized queries on v2 submissions table
     * 
     * @return void
     */
    private function calculate_quizzes() {
        global $wpdb, $ST_OPTION_st_proqyz__IELTS_LMS, $ST_OPTION_st_proqyz__GOV_LMS, $ST_OPTION_st_proqyz__PDF_QUIZ_LMS;
        
        // Get enabled LMS modules
        $enable_ielts_lms = get_option( $ST_OPTION_st_proqyz__IELTS_LMS, 0 );
        $enable_gov_lms = get_option( $ST_OPTION_st_proqyz__GOV_LMS, 0 );
        $enable_proqyz_pdfquiz = get_option( $ST_OPTION_st_proqyz__PDF_QUIZ_LMS, 0 );
        
        // Initialize analytics object
        $this->quizzes_analytics = (object) array(
            'ielts_listenings'          => 0,
            'ielts_readings'            => 0,
            'ielts_writings'            => 0,
            'ielts_speakings'           => 0,
            'ielts_writings_unreviewed' => 0,
            'ielts_speakings_unreviewed'=> 0,
            'gov_sectional_timing'      => 0,
            'gov_non_sectional_timing'  => 0,
            'competitive_exams'         => 0,
            'proqyz_pdf_quiz'           => 0,
        );
        
        // Build user filter based on role
        $user_ids_filter = $this->get_user_ids_filter_for_analytics();
        
        if ( empty( $user_ids_filter ) ) {
            return; // No users to query
        }
        
        // Base WHERE clause for completed submissions
        $base_where = "WHERE session_category = 'course' 
                       AND (session_status = 1 OR session_status = 2) 
                       AND status = 1";
        if( $this->role == "student" ) {
            $base_where .= " AND user_id = {$this->user_id}";
        } else {
            $base_where .= " AND user_id IN ({$user_ids_filter})";
        }

        
        // Calculate IELTS LMS analytics
        if ( $enable_ielts_lms == 1 ) {
            // Listening
            $this->quizzes_analytics->ielts_listenings = (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$this->submissions_table} 
                {$base_where} AND quiz_category = 'ielts-listening'"
            );
            
            // Reading
            $this->quizzes_analytics->ielts_readings = (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$this->submissions_table} 
                {$base_where} AND quiz_category = 'ielts-reading'"
            );
            
            // Writing
            $this->quizzes_analytics->ielts_writings = (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$this->submissions_table} 
                {$base_where} AND quiz_category = 'ielts-writing'"
            );
            
            // Writing - Unreviewed
            $this->quizzes_analytics->ielts_writings_unreviewed = (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$this->submissions_table} 
                {$base_where} AND quiz_category = 'ielts-writing' AND review = 0"
            );
            
            // Speaking
            $this->quizzes_analytics->ielts_speakings = (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$this->submissions_table} 
                {$base_where} AND quiz_category = 'ielts-speaking'"
            );
            
            // Speaking - Unreviewed
            $this->quizzes_analytics->ielts_speakings_unreviewed = (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$this->submissions_table} 
                {$base_where} AND quiz_category = 'ielts-speaking' AND review = 0"
            );
        }
        
        // Calculate Government/Competitive Exam analytics
        if ( $enable_gov_lms == 1 ) {
            // Non-sectional timing
            $this->quizzes_analytics->gov_non_sectional_timing = (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$this->submissions_table} 
                {$base_where} AND quiz_category = 'gov-non-sectional-timing'"
            );
            
            // Sectional timing
            $this->quizzes_analytics->gov_sectional_timing = (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$this->submissions_table} 
                {$base_where} AND quiz_category = 'gov-sectional-timing'"
            );
            
            // Total competitive exams
            $this->quizzes_analytics->competitive_exams = 
                $this->quizzes_analytics->gov_non_sectional_timing + 
                $this->quizzes_analytics->gov_sectional_timing;
        }
        
        // Calculate PDF Quiz analytics
        if ( $enable_proqyz_pdfquiz == 1 ) {
            $this->quizzes_analytics->proqyz_pdf_quiz = (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$this->submissions_table} 
                {$base_where} AND quiz_category = 'proqyz-pdf-quiz'"
            );
        }

        
    }
    
    /**
     * Initialize evaluation settings
     * 
     * Checks evaluation plans once in constructor for better performance
     * Stores results for use in score display logic
     * 
     * @return void
     */
    private function init_evaluation_settings() {
        global $ST_OPTION_st_proqyz_IELTS_LMS_enable_evaluation,
            $ST_OPTION_st_proqyz_IELTS_LMS_writing_task1_evaluation_enable,
            $ST_OPTION_st_proqyz_IELTS_LMS_writing_task2_evaluation_enable,
            $ST_OPTION_st_proqyz_IELTS_LMS_writing_task1and2_evaluation_enable,
            $ST_OPTION_st_proqyz_IELTS_LMS_writing_task1_evaluation_plan_id,
            $ST_OPTION_st_proqyz_IELTS_LMS_writing_task2_evaluation_plan_id,
            $ST_OPTION_st_proqyz_IELTS_LMS_writing_task1and2_evaluation_plan_id,
            $ST_OPTION_st_proqyz_IELTS_LMS_speaking_evaluation_enable,
            $ST_OPTION_st_proqyz_IELTS_LMS_speaking_evaluation_plan_id;
        
        // Initialize evaluation settings object
        $this->evaluation_settings = (object) array(
            'enabled'               => false,
            'woocommerce_active'    => function_exists( 'wc_get_product' ),
            'writing_task1_plan'    => false,
            'writing_task2_plan'    => false,
            'writing_task1and2_plan'=> false,
            'speaking_plan'         => false,
        );
        
        // Check if evaluation is enabled
        $enable_evaluation = get_option( $ST_OPTION_st_proqyz_IELTS_LMS_enable_evaluation, false );
        
        if ( ! $enable_evaluation || ! $this->evaluation_settings->woocommerce_active ) {
            // Evaluation not enabled or WooCommerce not active
            return;
        }
        
        $this->evaluation_settings->enabled = true;
        
        // Check Writing Task 1 Plan
        $task1_enable = get_option( $ST_OPTION_st_proqyz_IELTS_LMS_writing_task1_evaluation_enable, false );
        if ( $task1_enable == 1 ) {
            $product_id = get_option( $ST_OPTION_st_proqyz_IELTS_LMS_writing_task1_evaluation_plan_id, false );
            if ( $product_id ) {
                $product = wc_get_product( $product_id );
                if ( $product && $product->get_price() > 0 ) {
                    $this->evaluation_settings->writing_task1_plan = true;
                }
            }
        }
        
        // Check Writing Task 2 Plan
        $task2_enable = get_option( $ST_OPTION_st_proqyz_IELTS_LMS_writing_task2_evaluation_enable, false );
        if ( $task2_enable == 1 ) {
            $product_id = get_option( $ST_OPTION_st_proqyz_IELTS_LMS_writing_task2_evaluation_plan_id, false );
            if ( $product_id ) {
                $product = wc_get_product( $product_id );
                if ( $product && $product->get_price() > 0 ) {
                    $this->evaluation_settings->writing_task2_plan = true;
                }
            }
        }
        
        // Check Writing Task 1+2 Combined Plan
        $task1and2_enable = get_option( $ST_OPTION_st_proqyz_IELTS_LMS_writing_task1and2_evaluation_enable, false );
        if ( $task1and2_enable == 1 ) {
            $product_id = get_option( $ST_OPTION_st_proqyz_IELTS_LMS_writing_task1and2_evaluation_plan_id, false );
            if ( $product_id ) {
                $product = wc_get_product( $product_id );
                if ( $product && $product->get_price() > 0 ) {
                    $this->evaluation_settings->writing_task1and2_plan = true;
                }
            }
        }
        
        // Check Speaking Plan
        $speaking_enable = get_option( $ST_OPTION_st_proqyz_IELTS_LMS_speaking_evaluation_enable, false );
        if ( $speaking_enable == 1 ) {
            $product_id = get_option( $ST_OPTION_st_proqyz_IELTS_LMS_speaking_evaluation_plan_id, false );
            if ( $product_id ) {
                $product = wc_get_product( $product_id );
                if ( $product && $product->get_price() > 0 ) {
                    $this->evaluation_settings->speaking_plan = true;
                }
            }
        }
    }
    
    /**
     * Re-initialize evaluation settings
     * 
     * Public method to refresh evaluation settings on demand (useful for AJAX)
     * 
     * @return void
     */
    public function refresh_evaluation_settings() {
        $this->init_evaluation_settings();
    }
    
    /**
     * Get evaluation settings
     * 
     * Returns the pre-computed evaluation settings object
     * 
     * @return object Evaluation settings
     */
    public function get_evaluation_settings() {
        return $this->evaluation_settings;
    }
    
    /**
     * Set cached data
     * 
     * Manually set user, courses, and quiz analytics data from cache (for AJAX lightweight mode)
     * Avoids recalculation when data is already available from frontend
     * 
     * @param object $cached_user Cached user data
     * @param array $cached_courses Cached courses data
     * @param object $cached_quizzes Cached quiz analytics data
     * @return void
     */
    public function set_cached_data( $cached_user, $cached_courses, $cached_quizzes = null ) {
        if ( $cached_user ) {
            // Merge cached user data with existing current_user object
            foreach ( $cached_user as $key => $value ) {
                $this->current_user->{$key} = $value;
            }
        }
        
        if ( $cached_courses && is_array( $cached_courses ) ) {
            // Convert cached courses array to objects if needed
            $this->courses = array();
            foreach ( $cached_courses as $course ) {
                $this->courses[] = is_object( $course ) ? $course : (object) $course;
            }
        }
        
        if ( $cached_quizzes ) {
            // Set quiz analytics from cache
            $this->quizzes_analytics = is_object( $cached_quizzes ) ? $cached_quizzes : (object) $cached_quizzes;
        }
    }
    
    /**
     * Get user IDs filter for analytics queries
     * 
     * Returns comma-separated sanitized user IDs based on role:
     * - Admin/Teacher: Current user + all students
     * - Student: Current user only
     * 
     * @return string Comma-separated user IDs
     */
    private function get_user_ids_filter_for_analytics() {
        $user_ids = array( $this->user_id );
        
        // Admin and Teacher: Include their students
        if ( $this->role === 'admin' || $this->role === 'teacher' ) {
            if ( isset( $this->current_user->student_ids ) && ! empty( $this->current_user->student_ids ) ) {
                $user_ids = array_merge( $user_ids, $this->current_user->student_ids );
            }
        }
        
        // Sanitize and convert to comma-separated string
        $user_ids = array_map( 'absint', $user_ids );
        $user_ids = array_unique( $user_ids );
        
        return implode( ',', $user_ids );
    }
    
    /**
     * Get quiz analytics
     * 
     * @return object Quiz analytics data
     */
    public function get_quizzes_analytics() {
        return $this->quizzes_analytics;
    }
    
    /**
     * Get memory usage
     * 
     * Returns current memory usage statistics
     * 
     * @param bool $formatted Return formatted string or raw bytes
     * @return mixed Memory usage (string or array based on $formatted)
     */
    public function get_memory_usage( $formatted = true ) {
        $current_memory = memory_get_usage( true );
        $peak_memory = memory_get_peak_usage( true );
        $memory_limit = ini_get( 'memory_limit' );
        
        if ( $formatted ) {
            return (object) array(
                'current'       => $this->format_bytes( $current_memory ),
                'peak'          => $this->format_bytes( $peak_memory ),
                'limit'         => $memory_limit,
                'current_bytes' => $current_memory,
                'peak_bytes'    => $peak_memory,
                'percentage'    => $this->calculate_memory_percentage( $current_memory, $memory_limit ),
            );
        }
        
        return array(
            'current' => $current_memory,
            'peak'    => $peak_memory,
            'limit'   => $memory_limit,
        );
    }
    
    /**
     * Format bytes to human readable format
     * 
     * @param int $bytes Number of bytes
     * @param int $precision Decimal precision
     * @return string Formatted size (e.g., "2.5 MB")
     */
    private function format_bytes( $bytes, $precision = 2 ) {
        $units = array( 'B', 'KB', 'MB', 'GB', 'TB' );
        
        $bytes = max( $bytes, 0 );
        $pow = floor( ( $bytes ? log( $bytes ) : 0 ) / log( 1024 ) );
        $pow = min( $pow, count( $units ) - 1 );
        
        $bytes /= pow( 1024, $pow );
        
        return round( $bytes, $precision ) . ' ' . $units[ $pow ];
    }
    
    /**
     * Calculate memory usage percentage
     * 
     * @param int $current_bytes Current memory in bytes
     * @param string $limit_string Memory limit string (e.g., "128M")
     * @return string Percentage with % symbol
     */
    private function calculate_memory_percentage( $current_bytes, $limit_string ) {
        // Convert memory limit to bytes
        $limit_bytes = $this->convert_to_bytes( $limit_string );
        
        if ( $limit_bytes <= 0 ) {
            return 'N/A';
        }
        
        $percentage = ( $current_bytes / $limit_bytes ) * 100;
        return round( $percentage, 2 ) . '%';
    }
    
    /**
     * Convert memory limit string to bytes
     * 
     * Handles formats like: 128M, 256M, 1G, etc.
     * 
     * @param string $value Memory limit string
     * @return int Bytes
     */
    private function convert_to_bytes( $value ) {
        $value = trim( $value );
        $last = strtolower( $value[ strlen( $value ) - 1 ] );
        $value = (int) $value;
        
        switch ( $last ) {
            case 'g':
                $value *= 1024;
                // Fall through
            case 'm':
                $value *= 1024;
                // Fall through
            case 'k':
                $value *= 1024;
        }
        
        return $value;
    }
    
    /**
     * Get dashboard statistics summary
     * 
     * Returns a comprehensive summary of all dashboard data and performance
     * 
     * @return object Statistics object
     */
    public function get_dashboard_stats() {
        return (object) array(
            'user'           => $this->current_user,
            'courses_count'  => $this->get_courses_count(),
            'quiz_analytics' => $this->quizzes_analytics,
            'memory_usage'   => $this->get_memory_usage( true ),
        );
    }
    
    /**
     * Get dashboard widgets by role
     * 
     * Returns array of widget objects based on user role and enabled LMS modules
     * 
     * @return array Array of widget objects
     */
    public function get_widgets_by_role() {
        global $ST_OPTION_st_proqyz__IELTS_LMS, $ST_OPTION_st_proqyz__GOV_LMS, $ST_OPTION_st_proqyz__PDF_QUIZ_LMS;
        
        // Get enabled LMS modules
        $enable_ielts_lms = get_option( $ST_OPTION_st_proqyz__IELTS_LMS, 0 );
        $enable_gov_lms = get_option( $ST_OPTION_st_proqyz__GOV_LMS, 0 );
        $enable_proqyz_pdfquiz = get_option( $ST_OPTION_st_proqyz__PDF_QUIZ_LMS, 0 );
        
        $widgets = array();
        
        // Calculate total tests taken
        $total_tests_taken = 0;
        
        if ( $enable_ielts_lms == 1 ) {
            $total_tests_taken += $this->quizzes_analytics->ielts_listenings;
            $total_tests_taken += $this->quizzes_analytics->ielts_readings;
            $total_tests_taken += $this->quizzes_analytics->ielts_writings;
            $total_tests_taken += $this->quizzes_analytics->ielts_speakings;
        }
        
        if ( $enable_gov_lms == 1 ) {
            $total_tests_taken += $this->quizzes_analytics->competitive_exams;
        }
        
        if ( $enable_proqyz_pdfquiz == 1 ) {
            $total_tests_taken += $this->quizzes_analytics->proqyz_pdf_quiz;
        }
        
        // Widget: Total Tests Taken (for all roles)
        $widgets[] = (object) array(
            'id'    => 'total-tests',
            'icon'  => 'ioticon-document',
            'name'  => 'Total Tests Taken',
            'value' => $total_tests_taken,
            'type'  => 'number',
        );
        
        // Role-specific widgets
        if ( $this->role === 'admin' || $this->role === 'teacher' ) {
            $this->add_admin_teacher_widgets( $widgets, $enable_ielts_lms, $enable_gov_lms );
        } elseif ( $this->role === 'student' ) {
            $this->add_student_widgets( $widgets );
        }
        
        return $widgets;
    }
    
    /**
     * Add widgets for admin and teacher roles
     * 
     * @param array $widgets Reference to widgets array
     * @param int $enable_ielts_lms IELTS LMS enabled flag
     * @param int $enable_gov_lms Gov LMS enabled flag
     * @return void
     */
    private function add_admin_teacher_widgets( &$widgets, $enable_ielts_lms, $enable_gov_lms ) {
        // Widget: Courses
        $widgets[] = (object) array(
            'id'    => 'courses',
            'icon'  => 'ioticon-book-open',
            'name'  => 'Courses',
            'value' => $this->get_courses_count(),
            'type'  => 'number',
        );
        
        // IELTS-specific widgets
        if ( $enable_ielts_lms == 1 ) {
            // Widget: Writings Under Review
            $widgets[] = (object) array(
                'id'    => 'writings-review',
                'icon'  => 'ioticon-edit-3',
                'name'  => 'Writings Under Review',
                'value' => $this->quizzes_analytics->ielts_writings_unreviewed,
                'type'  => 'number',
                'alert' => $this->quizzes_analytics->ielts_writings_unreviewed > 0,
            );
            
            // Widget: Speakings Under Review
            $widgets[] = (object) array(
                'id'    => 'speakings-review',
                'icon'  => 'ioticon-announcement-speaker',
                'name'  => 'Speakings Under Review',
                'value' => $this->quizzes_analytics->ielts_speakings_unreviewed,
                'type'  => 'number',
                'alert' => $this->quizzes_analytics->ielts_speakings_unreviewed > 0,
            );
        }
        
        // Widget: Total Students
        $total_students = isset( $this->current_user->students_count ) ? $this->current_user->students_count : 0;
        $widgets[] = (object) array(
            'id'    => 'total-students',
            'icon'  => 'ioticon-student',
            'name'  => 'Total Students',
            'value' => $total_students,
            'type'  => 'number',
        );
    }
    
    /**
     * Add widgets for student role
     * 
     * @param array $widgets Reference to widgets array
     * @return void
     */
    private function add_student_widgets( &$widgets ) {
        // Widget: Courses
        $widgets[] = (object) array(
            'id'    => 'courses',
            'icon'  => 'ioticon-book-open',
            'name'  => 'Courses',
            'value' => $this->get_courses_count(),
            'type'  => 'number',
        );
    }
    
    /**
     * Render widgets HTML
     * 
     * Converts widget objects to HTML markup
     * 
     * @param array $widgets Array of widget objects
     * @return string HTML markup
     */
    public function render_widgets( $widgets = null ) {
        if ( $widgets === null ) {
            $widgets = $this->get_widgets_by_role();
        }
        
        if ( empty( $widgets ) ) {
            return '';
        }
        
        $html = '';
        
        foreach ( $widgets as $widget ) {
            $alert_class = isset( $widget->alert ) && $widget->alert ? ' performance-board__item--alert' : '';
            
            ob_start(); ?>
            <div class="performance-board__item<?php echo esc_attr( $alert_class ); ?>" data-widget-id="<?php echo esc_attr( $widget->id ); ?>">
                <span class="performance-board__item-icon <?php echo esc_attr( $widget->icon ); ?>"></span>
                <div class="performance-board__item-name"><?php echo esc_html( $widget->name ); ?></div>
                <div class="performance-board__item-value"><?php echo esc_html( $widget->value ); ?></div>
            </div>
            <?php $html .= ob_get_clean();
        }
        
        return $html;
    }
    
    /**
     * Get progress analytics chart for student role
     * Shows performance charts for listening, reading, writing, speaking
     * 
     * @return string HTML for charts section or empty if not student or no IELTS LMS
     */
    public function get_progress_analytics_chart() {
        global $wpdb, $ST_OPTION_st_proqyz__IELTS_LMS;
        
        // Only show for students
        if ( $this->role !== 'student' ) {
            return '';
        }
        
        // Check if IELTS LMS is enabled
        $enable_ielts_lms = get_option( $ST_OPTION_st_proqyz__IELTS_LMS, 0 );
        if ( $enable_ielts_lms != 1 || ! function_exists( 'ProQyz_Ielts_scoreToBand' ) ) {
            return '';
        }
        
        $user_id = $this->user_id;
        
        # need to get score from score table
        $listening_results = $wpdb->get_results( $wpdb->prepare(
            "SELECT 
                ss.submission_id AS submission_id,
                ss.score_data AS score,
                s.date_created AS created_at
             FROM {$this->score_table} ss
             INNER JOIN {$this->submissions_table} s 
                ON ss.submission_id = s.ID
             WHERE s.quiz_category = 'ielts-listening'
               AND s.status = 1
               AND s.session_status != 3
               AND ss.user_id = %d
             ORDER BY s.date_created DESC
             LIMIT 10",
            $user_id
        ) );

        # need to get score from score table
        $reading_results = $wpdb->get_results( $wpdb->prepare(
            "SELECT 
                ss.submission_id AS submission_id,
                ss.score_data AS score,
                s.date_created AS created_at
             FROM {$this->score_table} ss
             INNER JOIN {$this->submissions_table} s ON ss.submission_id = s.ID
             WHERE s.quiz_category = 'ielts-reading' 
             AND s.status = 1 
             AND s.session_status != 3
             AND ss.user_id = %d 
             ORDER BY s.date_created DESC 
             LIMIT 10",
            $user_id
        ) );

        # need to get score from score table
        $writing_results = $wpdb->get_results( $wpdb->prepare(
            "SELECT ss.score_data as score, s.date_created as created_at 
             FROM {$this->score_table} ss
             INNER JOIN {$this->submissions_table} s ON ss.submission_id = s.ID
             WHERE s.quiz_category = 'ielts-writing' 
             AND s.status = 1 
             AND s.session_status != 3
             AND ss.user_id = %d 
             ORDER BY s.date_created DESC 
             LIMIT 10",
            $user_id
        ) );

        # need to get score from score table
        $speaking_results = $wpdb->get_results( $wpdb->prepare(
            "SELECT ss.score_data as score, s.date_created as created_at 
             FROM {$this->score_table} ss
             INNER JOIN {$this->submissions_table} s ON ss.submission_id = s.ID
             WHERE s.quiz_category = 'ielts-speaking' 
             AND s.status = 1 
             AND s.session_status != 3
             AND ss.user_id = %d 
             ORDER BY s.date_created DESC 
             LIMIT 10",
            $user_id
        ) );
        
        // Process listening results
        $listening_labels = [];
        $listening_scores = [];
        $listening_bands  = [];
        $listening_txt = '';
        
        if ( count( $listening_results ) > 0 ) {
            foreach ( $listening_results as $result ) {
                $score_obj = json_decode( $result->score );
                if ( $score_obj ) {
                    $total_questions = (int) $score_obj->total;
                    $total_correct   = (int) $score_obj->correct;
                    $total_wrong     = (int) $score_obj->wrong;
                    $total_unattempt = (int) $score_obj->unattempt;

                    $course_subcategory = $wpdb->get_var( $wpdb->prepare(
                        "SELECT meta_value FROM {$this->meta_table} 
                        WHERE submission_id = %d AND meta_key = 'course_subcategory' LIMIT 1",
                        $result->submission_id
                    ) );
                    $course_subcategory = $course_subcategory ? $course_subcategory : 'academic';

                    $overall_band    = ProQyz_Ielts_scoreToBand( $total_correct, $course_subcategory );
                    $percentage      = $total_questions > 0 ? ( $total_correct * 100 ) / $total_questions : 0;
                    $percentage      = number_format( $percentage, 2 );
                    
                    $listening_scores[] = [ $overall_band, $total_correct, $total_wrong, $total_unattempt ];
                    $listening_bands[]  = $percentage;
                    $listening_labels[] = date( 'm/d/Y', $result->created_at );
                    
                    ob_start(); ?>
                    <div class="test-performance__eval-row">
                        <div class="test-performance__eval-skill"><?php echo date( 'm/d/Y', $result->created_at ); ?></div>
                        <div class="test-performance__eval-value"><?php echo $percentage . '%'; ?></div>
                    </div>
                    <?php $listening_txt .= ob_get_clean();
                }
            }
        }
        
        // Process reading results
        $reading_labels = [];
        $reading_scores = [];
        $reading_bands  = [];
        $reading_txt = '';
        
        if ( count( $reading_results ) > 0 ) {
            foreach ( $reading_results as $result ) {
                $score_obj = json_decode( $result->score );
                if ( $score_obj ) {
                    $total_questions = (int) $score_obj->total;
                    $total_correct   = (int) $score_obj->correct;
                    $total_wrong     = (int) $score_obj->wrong;
                    $total_unattempt = (int) $score_obj->unattempt;

                    $course_subcategory = $wpdb->get_var( $wpdb->prepare(
                        "SELECT meta_value FROM {$this->meta_table} 
                        WHERE submission_id = %d AND meta_key = 'course_subcategory' LIMIT 1",
                        $result->submission_id
                    ) );
                    $course_subcategory = $course_subcategory ? $course_subcategory : 'academic';
                    $overall_band    = ProQyz_Ielts_scoreToBand( $total_correct, $course_subcategory );
                    
                    $percentage      = $total_questions > 0 ? ( $total_correct * 100 ) / $total_questions : 0;
                    $percentage      = number_format( $percentage, 2 );
                    
                    $reading_scores[] = [ $overall_band, $total_correct, $total_wrong, $total_unattempt ];
                    $reading_bands[]  = $percentage;
                    $reading_labels[] = date( 'm/d/Y', $result->created_at );
                    
                    ob_start(); ?>
                    <div class="test-performance__eval-row">
                        <div class="test-performance__eval-skill"><?php echo date( 'm/d/Y', $result->created_at ); ?></div>
                        <div class="test-performance__eval-value"><?php echo $percentage . '%'; ?></div>
                    </div>
                    <?php $reading_txt .= ob_get_clean();
                }
            }
        }
        
        // Process writing results
        $writing_labels = [];
        $writing_scores = [];
        $writing_bands  = [];
        $writing_txt = '';
        
        if ( count( $writing_results ) > 0 ) {
            foreach ( $writing_results as $result ) {
                $score_obj = maybe_unserialize( $result->score );
                if ( is_array( $score_obj ) && count( $score_obj ) > 0 ) {
                    $task1_scores = isset( $score_obj['task-1'] ) ? (array) $score_obj['task-1'] : [ 0, 0, 0, 0 ];
                    $task2_scores = isset( $score_obj['task-2'] ) ? (array) $score_obj['task-2'] : [ 0, 0, 0, 0 ];
                    
                    $total_score1 = array_sum( $task1_scores ) / 4;
                    $total_score1 = round( $total_score1 * 2 ) / 2;
                    
                    $total_score2 = array_sum( $task2_scores ) / 4;
                    $total_score2 = round( $total_score2 * 2 ) / 2;
                    
                    $band = ( $total_score1 + ( $total_score2 * 2 ) ) / 3;
                    $overall_band = round( $band * 2 ) / 2;
                    
                    $writing_scores[] = [ $overall_band, $total_score1, $total_score2 ];
                    $writing_bands[]  = $overall_band;
                    $writing_labels[] = date( 'm/d/Y', $result->created_at );
                    
                    ob_start(); ?>
                    <div class="test-performance__eval-row">
                        <div class="test-performance__eval-skill"><?php echo date( 'm/d/Y', $result->created_at ); ?></div>
                        <div class="test-performance__eval-value"><?php echo $overall_band; ?></div>
                    </div>
                    <?php $writing_txt .= ob_get_clean();
                }
            }
        }
        
        // Process speaking results
        $speaking_labels = [];
        $speaking_scores = [];
        $speaking_bands  = [];
        $speaking_txt = '';
        
        if ( count( $speaking_results ) > 0 ) {
            foreach ( $speaking_results as $result ) {
                $score_obj = maybe_unserialize( $result->score );
                if ( is_array( $score_obj ) && count( $score_obj ) > 0 ) {
                    $tasks_scores = isset( $score_obj['tasks'] ) ? (array) $score_obj['tasks'] : [ 0, 0, 0, 0 ];
                    $total_scores = array_sum( $tasks_scores ) / 4;
                    $total_scores = round( $total_scores * 2 ) / 2;
                    
                    $speaking_scores[] = [ $total_scores ];
                    $speaking_bands[]  = $total_scores;
                    $speaking_labels[] = date( 'm/d/Y', $result->created_at );
                    
                    ob_start(); ?>
                    <div class="test-performance__eval-row">
                        <div class="test-performance__eval-skill"><?php echo date( 'm/d/Y', $result->created_at ); ?></div>
                        <div class="test-performance__eval-value"><?php echo $total_scores; ?></div>
                    </div>
                    <?php $speaking_txt .= ob_get_clean();
                }
            }
        }
        
        // Render the chart HTML
        ob_start(); ?>
        <section class="test-performance">
            <div class="test-performance__box">
                <div role="tabpanel">
                    <ul class="test-performance__nav clearfix hidden-xs" role="tablist" id="lesson-tab">
                        <li role="presentation" class="test-performance__nav-item -listening active"> 
                            <a data-tab-index="0" class="test-performance__nav-btn" href="#listening-performance" aria-controls="listening-performance" role="tab" data-toggle="tab" aria-expanded="true">
                                <span class="ioticon-live-support-agent-headset"></span>Listening
                            </a>
                        </li>
                        <li role="presentation" class="test-performance__nav-item -reading"> 
                            <a data-tab-index="1" class="test-performance__nav-btn" href="#reading-performance" aria-controls="reading-performance" role="tab" data-toggle="tab" aria-expanded="false">
                                <span class="ioticon-book-open"></span>Reading
                            </a>
                        </li>
                        <li role="presentation" class="test-performance__nav-item -writing"> 
                            <a data-tab-index="2" class="test-performance__nav-btn" href="#writing-performance" aria-controls="writing-performance" role="tab" data-toggle="tab" aria-expanded="false">
                                <span class="ioticon-edit-3"></span>Writing
                            </a>
                        </li>
                        <li role="presentation" class="test-performance__nav-item -speaking"> 
                            <a data-tab-index="3" class="test-performance__nav-btn" href="#speaking-performance" aria-controls="speaking-performance" role="tab" data-toggle="tab" aria-expanded="false">
                                <span class="ioticon-announcement-speaker"></span>Speaking
                            </a>
                        </li>
                    </ul>
                    <div class="dropdown bootstrap-select visible-xs iot-opselect select-lesson">
                        <select name="selectLesson" id="select-lesson" class="v-select dropdown bootstrap-select visible-xs iot-opselect select-lesson selectpicker" tabindex="-98">
                            <option value="0" selected="selected" data-content="<span class='ioticon-live-support-agent-headset'></span>Listening"></option>
                            <option value="1" data-content="<span class='ioticon-book-open'></span>Reading"></option>
                            <option value="2" data-content="<span class='ioticon-edit-3'></span>Writing"></option>
                            <option value="3" data-content="<span class='ioticon-announcement-speaker'></span>Speaking"></option>
                        </select>
                    </div>
                    <div class="test-performance__contents tab-content">
                        
                        <!-- Listening Tab -->
                        <div role="tabpanel" class="tab-pane fade -listening clearfix active in" id="listening-performance">
                            <div class="test-performance__chart">
                                <div style="width:100%;max-width: 480px">
                                    <canvas id="listening_evaluation" class="chart-container" height="396" width="475"></canvas>
                                    <script id="listening-chatjs-json" type="application/json">
                                        <?php echo json_encode( (object) [
                                            'listening' => (object) [
                                                'labels' => $listening_labels,
                                                'scores' => $listening_scores,
                                                'bands'  => $listening_bands
                                            ]
                                        ] ); ?>
                                    </script>
                                </div>
                            </div>
                            <div class="test-performance__eval-board">
                                <div class="test-performance__eval-head">
                                    <div class="test-performance__eval-title">Date (m/d/y)</div>
                                    <div class="test-performance__eval-title">Band</div>
                                </div>
                                <?php echo $listening_txt; ?>
                            </div>
                        </div>
                        
                        <!-- Reading Tab -->
                        <div role="tabpanel" class="tab-pane fade -reading clearfix" id="reading-performance">
                            <div class="test-performance__chart">
                                <div style="width:100%; max-width: 475px">
                                    <canvas id="reading_evaluation" class="chart-container" height="396" width="475"></canvas>
                                    <script id="reading-chatjs-json" type="application/json">
                                        <?php echo json_encode( (object) [
                                            'reading' => (object) [
                                                'labels' => $reading_labels,
                                                'scores' => $reading_scores,
                                                'bands'  => $reading_bands
                                            ]
                                        ] ); ?>
                                    </script>
                                </div>
                            </div>
                            <div class="test-performance__eval-board">
                                <div class="test-performance__eval-head">
                                    <div class="test-performance__eval-title">Date (m/d/y)</div>
                                    <div class="test-performance__eval-title">Band</div>
                                </div>
                                <?php echo $reading_txt; ?>
                            </div>
                        </div>
                        
                        <!-- Writing Tab -->
                        <div role="tabpanel" class="tab-pane fade -writing clearfix" id="writing-performance">
                            <div class="test-performance__chart">
                                <div style="width:100%; max-width: 475px">
                                    <canvas id="writing_evaluation" class="chart-container" height="396" width="475"></canvas>
                                    <script id="writing-chatjs-json" type="application/json">
                                        <?php echo json_encode( (object) [
                                            'writing' => (object) [
                                                'labels' => $writing_labels,
                                                'scores' => $writing_scores,
                                                'bands'  => $writing_bands
                                            ]
                                        ] ); ?>
                                    </script>
                                </div>
                            </div>
                            <div class="test-performance__eval-board">
                                <div class="test-performance__eval-head">
                                    <div class="test-performance__eval-title">Date (m/d/y)</div>
                                    <div class="test-performance__eval-title">Band</div>
                                </div>
                                <?php echo $writing_txt; ?>
                            </div>
                        </div>
                        
                        <!-- Speaking Tab -->
                        <div role="tabpanel" class="tab-pane fade -speaking clearfix" id="speaking-performance">
                            <div class="test-performance__chart">
                                <div style="width:100%; max-width: 475px">
                                    <canvas id="speaking_evaluation" class="chart-container" height="396" width="475"></canvas>
                                    <script id="speaking-chatjs-json" type="application/json">
                                        <?php echo json_encode( (object) [
                                            'speaking' => (object) [
                                                'labels' => $speaking_labels,
                                                'scores' => $speaking_scores,
                                                'bands'  => $speaking_bands
                                            ]
                                        ] ); ?>
                                    </script>
                                </div>
                            </div>
                            <div class="test-performance__eval-board">
                                <div class="test-performance__eval-head">
                                    <div class="test-performance__eval-title">Date (m/d/y)</div>
                                    <div class="test-performance__eval-title">Band</div>
                                </div>
                                <?php echo $speaking_txt; ?>
                            </div>
                        </div>
                        
                    </div>
                </div>
            </div>
        </section>
        <br />
        <?php
        return ob_get_clean();
    }
    
    /**
     * Get dashboard overall tab content with pagination and filters
     * 
     * @param array $args Arguments for pagination and filters
     * @param string $widgets_html Optional pre-rendered widgets HTML (for AJAX with cache)
     * @return array HTML content, pagination, and filters
     */
    public function get_dashboard_overall( $args = array(), $widgets_html = null ) {
        // Use provided widgets HTML or render from instance data
        if ( $widgets_html === null ) {
            $widgets_html = $this->render_widgets();
        }
        
        // Get tests with pagination
        $result = $this->get_recent_tests_history( $args );
        $tests = $result['tests'];
        $pagination = $result['pagination'];
        
        ob_start(); ?>
        
        <h1 class="section-title">Overall Performance</h1>
        
        <!--begin::widget list-->
        <section class="performance-board">
            <div class="performance-board__item-wrap">
                <?php echo $widgets_html; ?>
            </div>
        </section>
        <!--end::widget list-->
        <br />
        
        <?php 
        // Get progress analytics chart for students
        $progress_chart = $this->get_progress_analytics_chart();
        if ( ! empty( $progress_chart ) ) {
            echo $progress_chart;
        }
        ?>
        
        <h1 class="section-title">Recent Test History</h1>

        <?php 
        $widgets_html = ob_get_clean();
        
        // Transform args to match filter rendering expectations
        $filter_args = array(
            'category'     => isset( $args['category'] ) ? $args['category'] : 'all',
            'course'       => isset( $args['course_id'] ) ? $args['course_id'] : 'all',
            'session_type' => isset( $args['session_type'] ) ? $args['session_type'] : 'all',
            'user'         => isset( $args['user_id'] ) ? $args['user_id'] : 'all',
        );
        
        // Wrap recent tests in test-history section
        $table_html = $this->render_recent_tests_table( $tests );
        $pagination_html = $this->render_pagination( $pagination );
        $filters_html = $this->render_overview_filters( $filter_args );
        
        $recent_tests_section = $this->render_test_history_section( $filters_html, $table_html, $pagination_html, "overview-tests" );
        
        // Combine widgets and recent tests sections
        $complete_html = $widgets_html . $recent_tests_section;
        
        // Return HTML
        return array(
            'html'       => $complete_html,
            'pagination' => '',
            'filters'    => '',
        );
    }
    
    /**
     * Render overview filters
     * 
     * @param array $current_filters Current filter values to preserve
     * @return string HTML filters
     */
    public function render_overview_filters( $current_filters = array() ) {
        $courses = $this->get_courses();
        
        // Get all quiz categories for filter
        $quiz_categories = array(
            'ielts-listening' => 'IELTS Listening',
            'ielts-reading'   => 'IELTS Reading',
            'ielts-writing'   => 'IELTS Writing',
            'ielts-speaking'  => 'IELTS Speaking',
            'gov-exam'       => 'Gov Exams',
            'proqyz-pdf-quiz' => 'PDF Quiz',
        );
        
        // Parse current filter values
        $selected_category = isset( $current_filters['category'] ) ? $current_filters['category'] : 'all';
        $selected_course = isset( $current_filters['course'] ) ? $current_filters['course'] : 'all';
        $selected_session_type = isset( $current_filters['session_type'] ) ? $current_filters['session_type'] : 'all';
        $selected_user = isset( $current_filters['user'] ) ? $current_filters['user'] : 'all';
      
      	// 2.2 fast fetch
        $student_ids = ! empty( $this->current_user->student_ids )
        ? array_map( 'intval', (array) $this->current_user->student_ids )
        : array();

        $students = array();

        if ( ! empty( $student_ids ) ) {
            // Fetch only what we need, in a single query
            $students = get_users( array(
                'include' => $student_ids,
                'fields'  => array( 'ID', 'display_name', 'user_email' ),
                // Optional: sort by display name in dropdown
                'orderby' => 'display_name',
                'order'   => 'ASC',
                'number'  => -1,
            ) );
        }
        
        ob_start(); ?>
        <div class="test-history__filter">
            <!-- Hidden field to store current tab (overview) -->
            <input type="hidden" id="quiz_category" value="dashboard" />
            
            <!-- Test Category Filter -->
            <select class="v-select  filter-select selectpicker dropdown bootstrap-select iot-opselect -rounded" name="category" id="filter-category" 
                    data-style="btn-default" data-width="auto" data-size="10">
                <option value="all" <?php selected( $selected_category, 'all' ); ?>>All Test Types</option>
                <?php foreach ( $quiz_categories as $cat_slug => $cat_name ) : ?>
                    <option value="<?php echo esc_attr( $cat_slug ); ?>" <?php selected( $selected_category, $cat_slug ); ?>>
                        <?php echo esc_html( $cat_name ); ?>
                    </option>
                <?php endforeach; ?>
            </select>
            
            <!-- Course Filter -->
            <select class="v-select filter-select selectpicker dropdown bootstrap-select iot-opselect -rounded" name="course" id="filter-course" 
                    data-style="btn-default" data-width="auto" data-size="10" data-live-search="true">
                <option value="all" <?php selected( $selected_course, 'all' ); ?>>All Courses</option>
                <?php foreach ( $courses as $course ) : ?>
                    <option value="<?php echo esc_attr( $course->id ); ?>" <?php selected( $selected_course, $course->id ); ?>>
                        <?php echo esc_html( $course->course_title ); ?>
                    </option>
                <?php endforeach; ?>
            </select>
            
            <!-- Attempt Type Filter (session_type: fresh/retake) -->
            <select class="v-select filter-select selectpicker dropdown bootstrap-select iot-opselect -rounded" name="session_type" id="filter-session-type" 
                    data-style="btn-default" data-width="auto">
                <option value="all" <?php selected( $selected_session_type, 'all' ); ?>>All Attempts</option>
                <option value="fresh" <?php selected( $selected_session_type, 'fresh' ); ?>>Fresh (First Attempt)</option>
                <option value="retake" <?php selected( $selected_session_type, 'retake' ); ?>>Retake</option>
            </select>
            
            <!-- Student Filter (admin/teacher only) -->
            <?php if ( $this->role === 'admin' || $this->role === 'teacher' ) : ?>
            <select class="v-select filter-select selectpicker dropdown bootstrap-select iot-opselect -rounded" name="user" id="filter-students" 
                    data-style="btn-default" data-width="auto" data-size="10" data-live-search="true">
                <option value="all" <?php selected( $selected_user, 'all' ); ?>>All Students</option>
              	
                <?php 
                // Use optimized query to fetch student data
                if ( ! empty( $students ) ) :
                    foreach ( $students as $student ) : ?>
                        <option value="<?php echo esc_attr( $student->ID ); ?>" <?php selected( $selected_user, $student->ID ); ?>>
                            <?php echo "(#".$student->ID.") ". esc_html( $student->display_name ) . " [" . esc_html( $student->user_email ) . "]"; ?>
                        </option>
                    <?php 
                    endforeach;
                endif; ?>
              	
            </select>
            <?php endif; ?>
            
            <button class="test-history__btn-filter test-history__btn iot-bt filter_btns" id="apply-filters">Apply</button>
            <button class="test-history__btn-reset test-history__btn iot-bt filter_btns">
                <span class="ioticon-refresh-double"></span>
            </button>
        </div>
        <?php
        return ob_get_clean();
    }
    
    /**
     * Get recent tests history with pagination and filters
     * 
     * @param array $args Arguments for pagination and filters
     * @return array Array with 'tests' and 'pagination'
     */
    public function get_recent_tests_history( $args = array() ) {
        global $wpdb;
        
        // Parse arguments
        $defaults = array(
            'per_page'     => 10,
            'page'         => 1,
            'course_id'    => 'all',
            'session_type' => 'all',
            'user_id'      => 'all',
            'category'     => 'all',
        );
        $args = wp_parse_args( $args, $defaults );
        
        // Build user filter based on role
        $user_ids_filter = $this->get_user_ids_filter_for_analytics();
        
        if ( empty( $user_ids_filter ) ) {
            return array(
                'tests'      => array(),
                'pagination' => array(
                    'current_page'  => 1,
                    'per_page'      => $args['per_page'],
                    'total_pages'   => 0,
                    'total_records' => 0,
                ),
            );
        }
        
        // Build WHERE conditions
        $where_conditions = array();
        $where_conditions[] = "s.user_id IN ({$user_ids_filter})";
        $where_conditions[] = "s.status = 1";
        $where_conditions[] = "s.session_status != 3";
        
        // Apply filters
        if ( $args['course_id'] !== 'all' ) {
            $where_conditions[] = $wpdb->prepare( "s.course_id = %s", $args['course_id'] );
        }
        
        // Session type filter (fresh vs retake)
        if ( $args['session_type'] !== 'all' ) {
            $where_conditions[] = $wpdb->prepare( "s.session_type = %s", $args['session_type'] );
        }
        
        if ( $args['user_id'] !== 'all' && ( $this->role === 'admin' || $this->role === 'teacher' ) ) {
            $where_conditions[] = $wpdb->prepare( "s.user_id = %d", $args['user_id'] );
        }
        
        if ( $args['category'] !== 'all' ) { 
            if($args['category'] == 'gov-exam') {
                $where_conditions[] = "(s.quiz_category = 'gov-sectional-timing' OR s.quiz_category = 'gov-non-sectional-timing')";
            } else {
                $where_conditions[] = $wpdb->prepare( "s.quiz_category = %s", $args['category'] );
            }
           //  $where_conditions[] = $wpdb->prepare( "s.quiz_category = %s", $args['category'] );
        }
        
        $where_clause = 'WHERE ' . implode( ' AND ', $where_conditions );
        
        // Get total count
        $total_records = $wpdb->get_var( "SELECT COUNT(*) FROM {$this->submissions_table} s {$where_clause}" );
        
        // Calculate pagination
        $total_pages = ceil( $total_records / $args['per_page'] );
        $offset = ( $args['page'] - 1 ) * $args['per_page'];
        
        // Fetch tests
        $recent_tests = $wpdb->get_results(
            "SELECT 
                s.ID,
                s.user_id,
                s.quiz_category,
                s.session_type,
                s.session_category,
                s.session_status,
                s.course_id,
                s.date_created,
                s.review,
                s.api_id
            FROM {$this->submissions_table} s
            {$where_clause}
            ORDER BY s.date_created DESC
            LIMIT {$args['per_page']} OFFSET {$offset}"
        );
        
        return array(
            'tests'      => $recent_tests,
            'pagination' => array(
                'current_page'  => (int) $args['page'],
                'per_page'      => (int) $args['per_page'],
                'total_pages'   => (int) $total_pages,
                'total_records' => (int) $total_records,
            ),
        );
    }
    
    /**
     * Render recent tests history table
     * 
     * @param array $tests Tests array
     * @return string HTML table
     */
    public function render_recent_tests_table( $tests ) {
        global $wpdb;
        
        if ( empty( $tests ) ) {
            ob_start(); ?>
            <div class="test-history__empty-box">
                <?php if ( $this->role === 'student' ) : ?>
                    <h5 class="test-history__empty-title">You haven't taken any test yet.</h5>
                    <p class="test-history__empty-caption">How about give it a try?</p>
                <?php else : ?>
                    <h5 class="test-history__empty-title">No test records found for your students.</h5>
                    <p class="test-history__empty-caption">Your students haven't taken any tests yet.</p>
                <?php endif; ?>
            </div>
            <?php
            return ob_get_clean();
        }
        
        // Build HTML table
        ob_start(); ?>
        <table class="table table-hover history-table iot-responsive-table">
            <thead>
                <?php if ( $this->role === 'student' ) : ?>
                <tr>
                    <th class="th__date">Date</th>
                    <th class="th__testname">Test name</th>
                    <th class="th__score">Score</th>
                    <th class="th__course">Course</th>
                    <th class="th__actions"></th>
                </tr>
                <?php else : ?>
                <tr>
                    <th class="th__date">Date</th>
                    <th class="th__testname">Test name</th>
                    <th class="th__score">Score</th>
                    <th class="th__course">Course</th>
                    <th class="th__username">Username</th>
                    <th class="th__actions"></th>
                </tr>
                <?php endif; ?>
            </thead>
            <tbody>
                <?php foreach ( $tests as $test ) : 
                    $quiz_type = $this->format_quiz_type( $test->quiz_category );
                    $date = date( 'd/m/y h:i A', $test->date_created );

                    
                    // get quiz category 
                    $quiz_category = $test->quiz_category;
                    // Get quiz title from meta
                    $quiz_title = $wpdb->get_var( $wpdb->prepare(
                        "SELECT meta_value FROM {$this->meta_table} 
                        WHERE submission_id = %d AND meta_key = 'quiz_title' LIMIT 1",
                        $test->ID
                    ) );
                    $test_name = $quiz_title ? $quiz_title : $quiz_type;
                    
                    // Get course title from meta
                    $course_title = $wpdb->get_var( $wpdb->prepare(
                        "SELECT meta_value FROM {$this->meta_table} 
                        WHERE submission_id = %d AND meta_key = 'course_title' LIMIT 1",
                        $test->ID
                    ) );
                    $course_title = $course_title ? $course_title : '--';

                    // Get course subcategory from meta table
                    $course_subcategory = $wpdb->get_var( $wpdb->prepare(
                        "SELECT meta_value FROM {$this->meta_table} 
                        WHERE submission_id = %d AND meta_key = 'course_subcategory' LIMIT 1",
                        $test->ID
                    ) );
                    $course_subcategory = $course_subcategory ? $course_subcategory : 'academic';
                    
                    // Get student name if admin/teacher
                    $student_name = 'Unknown';
                    if ( $this->role === 'admin' || $this->role === 'teacher' ) {
                        $users = get_users( array(
                            'include' => array( $test->user_id ),
                            'fields'  => array( 'ID', 'display_name' ),
                        ) );
                        if ( ! empty( $users ) ) {
                            $student_name = $users[0]->display_name ?: 'Unknown';
                        }
                    }
                    
                    // Get quiz_slug from meta table
                    $quiz_slug = $wpdb->get_var( $wpdb->prepare(
                        "SELECT meta_value FROM {$this->meta_table} 
                        WHERE submission_id = %d AND meta_key = 'quiz_slug' LIMIT 1",
                        $test->ID
                    ) );
                    
                    // api_id is already in the submissions table
                    $api_id = $test->api_id;
                    
                    // Generate review/result URL
                    $result_url = $this->get_test_url( $test->quiz_category, $quiz_slug, $api_id, $test->ID );
                    
                    // Score display
                    $score = '--';
                    $session_category = $test->session_category;

                    $lesson_title = '';
                    // if its fullmock-test then need to fetch lesson_title from submission_meta table 
                    if( $session_category == 'fullmock-test') {
                        $lesson_title = $wpdb->get_var( $wpdb->prepare(
                            "SELECT meta_value FROM {$this->meta_table} 
                            WHERE submission_id = %d AND meta_key = 'lesson_title' LIMIT 1",
                            $test->ID
                        ) );
                        $lesson_title = $lesson_title ? $lesson_title : '';
                    }

                    // need to fetch course from meta table as meta_key session_detail, meta_value is serialized object
                    $evaluation_object = null;
                    if($quiz_category == 'ielts-speaking' || $quiz_category == 'ielts-writing'){
                        $session_detail = $wpdb->get_var( $wpdb->prepare(
                            "SELECT session_data FROM {$this->session_table} 
                            WHERE submission_id = %d LIMIT 1",
                            $test->ID
                        ) );
                        
                        if( $session_detail) {
                            $session_detail = maybe_unserialize( $session_detail );
                            $session_detail = ! empty( $session_detail ) ? (object) $session_detail : null;
                            $course = isset( $session_detail->course ) ? (object)$session_detail->course : null;
                            $evaluation_object = isset( $course->_evaluation ) ? (object) $course->_evaluation : null;
                        }
                    }

                    // Score display
                    $score = $this->get_score_display( $test->ID, $test->quiz_category, $test->review, $evaluation_object, $course_subcategory );

                ?>
                <tr>
                    <td class="history-table__date"><?php echo esc_html( $date ); ?></td>
                    <td class="history-table__test-name">
                        <?php if($test->session_category == 'fullmock-test') { ?>
                            <div style="display: flex; flex-direction: column; align-items: flex-start; gap: 0px;">
                                <span class="test_title"><?php echo esc_html( $test_name ); ?></span>
                                <span class="test_type" style="color:#7c002a;">Fullmock Test</span>
                            </div>
                        <?php } else { ?>
                            <?php echo esc_html( $test_name ); ?>
                        <?php } ?>
                    </td>
                    <td class="history-table__score" data-label="Score"><?php echo $score; ?></td>
                    <td class="history-table__course" data-label="Course">
                        <?php if($session_category == 'fullmock-test') { ?>
                            <div class="lg--align-left md--align-right">
                                <span class="test_title"><?php echo esc_html( $course_title ); ?></span>
                                <span class="test_type" style="color:green;"><?php echo esc_html( $lesson_title ); ?></span>
                            </div>
                        <?php } else { ?>
                            <?php echo esc_html( $course_title ); ?>
                        <?php } ?>
                        
                    </td>
                    <?php if ( $this->role === 'admin' || $this->role === 'teacher' ) : ?>
                    <td class="history-table__username" data-label="Username"><?php echo esc_html( $student_name ); ?></td>
                    <?php endif; ?>
                    <td class="history-table__action">
                        <?php if($session_category == 'fullmock-test') { ?>
                            <div class="history-table__btn-group">
                                <a href="<?php echo esc_url( $result_url ); ?>" class="history-table__btn-view view-result" target="_blank">Review</a>
                                <div class="history-table__other-btn">
                                    <span class="ioticon-chevron-down"></span>
                                    <span class="history-table__hidden-group">
                                        <?php if($this->role === 'admin' || $this->role === 'teacher') { ?>
                                            <a href="<?php echo esc_url(st_proqyz_get_mock_test_url($test->course_id, $test->lesson_id, 'result/?child_id=' . $test->user_id)); ?>" target="_blank" class="history-table__btn view-result">
                                                Full Review
                                            </a>
                                        <?php } else { ?>
                                            <a href="<?php echo esc_url(st_proqyz_get_mock_test_url($test->course_id, $test->lesson_id, 'result')); ?>" target="_blank" class="history-table__btn view-result">
                                                Full Review
                                            </a>
                                        <?php } ?>
                                    </span>
                                </div>
                            </div>
                        <?php } else { ?>
                            <div class="history-table__btn-group">
                                <a href="<?php echo esc_url( $result_url ); ?>" class="history-table__btn-view view-result" target="_blank">Review</a>
                                <div class="history-table__other-btn">
                                    <span class="ioticon-chevron-down"></span>
                                    <span class="history-table__hidden-group">
                                        <a href="javascript:;" 
                                        data-proqyz-delete-modal="true"
                                        data-test-id="<?php echo esc_attr( $test->ID ); ?>"
                                        data-test-category="<?php echo esc_attr( $test->quiz_category ); ?>"
                                        class="history-table__btn -delete">
                                            <span class="ioticon-trash-3"></span>Delete
                                        </a>
                                    </span>
                                </div>
                            </div>
                        <?php } ?>
                    </td>
                </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
        <?php return ob_get_clean();
    }
    
    /**
     * Format quiz type for display
     * 
     * @param string $quiz_category Quiz category slug
     * @return string Formatted quiz type name
     */
    private function format_quiz_type( $quiz_category ) {
        $types = array(
            'ielts-listening'           => 'IELTS Listening',
            'ielts-reading'             => 'IELTS Reading',
            'ielts-writing'             => 'IELTS Writing',
            'ielts-speaking'            => 'IELTS Speaking',
            'gov-sectional-timing'      => 'Sectional Timing',
            'gov-non-sectional-timing'  => 'Non-Sectional Timing',
            'proqyz-pdf-quiz'           => 'PDF Quiz',
        );
        
        return isset( $types[ $quiz_category ] ) ? $types[ $quiz_category ] : ucwords( str_replace( '-', ' ', $quiz_category ) );
    }
    
    /**
     * Calculate and format score display based on quiz category
     * 
     * @param int $submission_id Submission ID
     * @param string $quiz_category Quiz category
     * @param int $review Review status (0 = not reviewed, 1 = reviewed)
     * @return string Formatted score display
     */
    private function get_score_display( $submission_id, $quiz_category, $review = 0, $evaluation_object = null, $course_subcategory = 'academic' ) {
        global $wpdb;
        $writing_evaluation_enabled = false;
        $speaking_evaluation_enabled = false;
        if($evaluation_object) {
            $evaluation_object = isset($evaluation_object)? (object) $evaluation_object : null;
            if( $evaluation_object->status == 'true') {
                
                if( isset($evaluation_object->writing) && ($evaluation_object->writing == 1 || $evaluation_object->writing == 'true' || $evaluation_object->writing == true)) {
                    $writing_evaluation_enabled = true;
                }
                if( isset($evaluation_object->speaking) && ($evaluation_object->speaking == 1 || $evaluation_object->speaking == 'true' || $evaluation_object->speaking == true)) {
                    $speaking_evaluation_enabled = true;
                }
            }

        }
        
        if($quiz_category != 'ielts-writing' && $quiz_category != 'ielts-speaking') {
            // Get score from meta table
            $score_data = $wpdb->get_var( $wpdb->prepare(
                "SELECT score_data FROM {$this->score_table} 
                WHERE submission_id = %d LIMIT 1",
                $submission_id
            ) );
            // for all normal quizzes, score is in the score field
            if( $quiz_category === 'ielts-reading' || $quiz_category === 'ielts-listening') {
                if($score_data) {
                    $score = (object) json_decode( $score_data, true );
                    $total_correct = isset( $score->correct ) ? (int) $score->correct : 0;
                    // return $score->correct;
                    return ProQyz_Ielts_scoreToBand( $total_correct, $course_subcategory ) . ' Band';
                } else {
                    return '--';
                }
            } else if($quiz_category == 'gov-sectional-timing' || $quiz_category == 'gov-non-sectional-timing' || $quiz_category == 'gov-exam'){
                if($score_data) {
                    $score = (object) json_decode( $score_data, true );
                    $total_marks = isset( $score->total_test_marks ) ? (int) $score->total_test_marks : 0;
                    $gained_marks = isset( $score->total_user_marks ) ? (int) $score->total_user_marks : 0;
                    // return $score->correct;
                    return "{$gained_marks}/{$total_marks}";
                } else {
                    return '--';
                }
            } else if( $quiz_category == "proqyz-pdf-quiz"){
                if($score_data) {
                    $score = (object) json_decode( $score_data, true );
                    $score_report = isset( $score->report ) ? (object) $score->report : null;
                    if( $score_report ) {
                        $total_questions = isset( $score_report->total_questions ) ? (int) $score_report->total_questions : 0;
                        $total_correct = isset( $score_report->total_correct ) ? (int) $score_report->total_correct : 0;
                        if( $total_questions > 0 ) {
                            $percentage = ($total_correct / $total_questions) * 100;
                            $percentage = round( $percentage / 5 ) * 5;
                            return "{$total_correct}/{$total_questions}";
                        } else {
                            return '--';
                        }
                    } else {
                        return '--';
                    }
                } else {
                    return '--';
                }
            } else {
                // for rest of the quizzes, score is not available
                return $quiz_category;
            }
        } else {
            $this_role = 'student';
            $user_id = $wpdb->get_var( $wpdb->prepare(
                "SELECT user_id FROM {$this->submissions_table} 
                WHERE ID = %d LIMIT 1",
                $submission_id
            ) );

            // Fetch only capabilities meta to derive roles (lighter than get_userdata)
            $caps_meta_key = $wpdb->prefix . 'capabilities';

            $caps_meta = $wpdb->get_var( $wpdb->prepare(
                "SELECT meta_value 
                 FROM {$wpdb->usermeta}
                 WHERE user_id = %d AND meta_key = %s
                 LIMIT 1",
                $user_id,
                $caps_meta_key
            ) );

            $user_roles = array();

            if ( $caps_meta ) {
                $caps = maybe_unserialize( $caps_meta );
                if ( is_array( $caps ) ) {
                    // keep only capabilities set to true
                    $user_roles = array_keys( array_filter( $caps ) );
                }
            }

            if ( empty( $user_roles ) ) {
                return 'Invalid user ID';
            }

            // same as before, but now from our lightweight roles array
            $this_role = $this->normalize_user_role( $user_roles );



            // for writing and speaking, score is in the sections field
            // first get sections for writing if quiz is writing 
            $sections = array();
            if($quiz_category === 'ielts-writing') {
                $sections = $wpdb->get_var( $wpdb->prepare(
                    "SELECT meta_value FROM {$this->meta_table} 
                    WHERE submission_id = %d AND meta_key = 'sections' LIMIT 1",
                    $submission_id
                ) );
                $sections = @unserialize( $sections );
                $sections = ! empty( $sections ) ? (array) $sections : array();
                // checking for task 1 and task 2 
                $has_task_1 = false;
              	$task_1_id = null;
                $has_task_2 = false;
                $task_2_id = null;
                // writing tasks related logic here
                if( count( $sections ) > 0 ) {
                    foreach( $sections as $section ) {
                        $section = (object) $section;
                        if( isset( $section->order ) ) {
                            if( $section->order == 1 ) {
                                $has_task_1 = true;
                                $task_1_id = $section->_id;
                            } else if( $section->order == 2 ) {
                                $has_task_2 = true;
                                $task_2_id = $section->_id;
                            }
                        }
                    }
                }
                
                // if tasks are review = 1 already, then get score from meta table
                if($review == 1) {
                    // now get score for task 1 and task 2
                    $task_1_score = 0;
                    $task_2_score = 0;
                    $overall_score = 0;
                    $has_scores = true;
                    # get score from review-scores meta from review meta table using (result_id & section_id )
                    $task1_scores = $this->get_score_from_review_and_review_meta( $submission_id, $task_1_id, $user_id );
                    $task2_scores = $this->get_score_from_review_and_review_meta( $submission_id, $task_2_id, $user_id );
                    if( $task1_scores ) {
                        # if task 1 score is not null when means its returning array of scores example: [0,0,0,0]
                        $task_1_score_arr = $task1_scores;
                        $task_1_score = array_sum( $task_1_score_arr ) / 4;
                        $task_1_score = round( $task_1_score * 2 ) / 2;
                    } else {
                        $has_scores = false;
                    }

                    if( $task2_scores ) {
                        # if task 2 score is not null when means its returning array of scores example: [0,0,0,0]
                        $task_2_score_arr = $task2_scores;
                        $task_2_score = array_sum( $task_2_score_arr ) / 4;
                        $task_2_score = round( $task_2_score * 2 ) / 2;
                    } else {
                        $has_scores = false;
                    }

                    // if has score then need to show task vise score - only for writing 
                    if( $has_scores ) {
                        $overall_score = ($task_1_score + $task_2_score) / 2;
                        $overall_score = round( $overall_score * 2 ) / 2;

                        ob_start(); ?>
                            <pre data-has-scores="true" data-task-1-id="<?php echo $task_1_id; ?>" style="display:none;"><?php echo print_r($task1_scores, true); ?></pre>
                            <pre data-has-scores="true" data-task-2-id="<?php echo $task_2_id; ?>" style="display:none;"><?php echo print_r($task2_scores, true); ?></pre>
                            <?php if( $has_task_1 ) : ?>
                                <div class="history-table__score-type">
                                    Task 1: <span class="history-table__score-num">
                                        <?php echo $task_1_score; ?>
                                    </span>
                                </div>
                            <?php endif; ?>
                            <?php if( $has_task_2 ) : ?>
                                <div class="history-table__score-type">Task 2: <span class="history-table__score-num"><?php echo $task_2_score; ?></span></div>
                            <?php endif; ?>
                            <?php if( $has_task_1 && $has_task_2 ) : ?>
                                <div class="history-table__score-type">
                                    Overall: <span class="history-table__score-num">
                                        <?php echo $overall_score; ?>
                                    </span>
                                </div>
                            <?php endif; ?>
                            
                        <?php return ob_get_clean();
                    } else {
                        // just error handling if review is 1 but score is not set

                        ob_start(); ?>
                            <pre data-has-scores="false" data-task-1-id="<?php echo $task_1_id; ?>" style="display:none;"><?php echo print_r($task1_scores, true); ?></pre>
                            <pre data-has-scores="false" data-task-2-id="<?php echo $task_2_id; ?>" style="display:none;"><?php echo print_r($task2_scores, true); ?></pre>
                            <?php if( $has_task_1 ) : ?>
                                <div class="history-table__score-type">
                                    Task 1: 
                                    <span class="history-table__score-num">
                                        <?php if($task_1_score > 0) {
                                            echo $task_1_score;
                                        } else {
                                            echo '--';
                                        } ?>
                                    </span>
                                </div>
                            <?php endif; ?>
                            <?php if( $has_task_2 ) : ?>
                                <div class="history-table__score-type">Task 2: <span class="history-table__score-num">
                                    <?php if($task_2_score > 0) {
                                        echo $task_2_score;
                                    } else {
                                        echo '--';
                                    } ?>
                                </span></div>
                            <?php endif; ?>
                        <?php return ob_get_clean();
                    }


                } else {
                    // if review is not 1, then show evaluation status, based on evaluation settings
                    if ( $this->evaluation_settings->enabled && $this->evaluation_settings->woocommerce_active  && $writing_evaluation_enabled ) {
                        // Evaluation is enabled and WooCommerce is active
                        // checking for task 1 and task 2
                        // Check enrollment status
                        $enrolled_for = array();
                        $check_payment = $this->get_submission_evaluation_meta( $submission_id, "enrolled_for", $user_id, true );
                        if ( $check_payment ) {
                            $enrolled_for = (array) json_decode( $check_payment, true );
                        }

                        ob_start();
                            // Task 1 Display
                            if ( $has_task_1 ) : ?>
								<pre style="display:none;"><?php echo print_r($evaluation_object, true); ?></pre>
                                <div class="history-table__score-type">
                                    Task 1: <span class="history-table__score-num">
                                        <?php 
                                        // Show "Get Evaluation" if:
                                        // - User hasn't enrolled AND (task1_plan exists OR task1and2_plan exists)
                                        if ( ! $this->is_task_enrolled((array) $enrolled_for, $task_1_id) && ( $this->evaluation_settings->writing_task1_plan || $this->evaluation_settings->writing_task1and2_plan ) ) {
                                            if($this->role == "student") {
                                                echo 'Get Evaluation';
                                            } else {
                                                echo 'Not enrolled';
                                            }                                             
                                        } else {
                                          	
                                          	if(isset($enrolled_for[$task_1_id])){
                                              $task_obj = $enrolled_for[$task_1_id];
                                              $payment_for = isset($task_obj['payment_for'])? $task_obj['payment_for'] : 'instructor';
                                              
                                              if($payment_for == "instructor") {
                                                echo '<i style="color:green;">Under evaluation</i>';
                                              } else if($payment_for == "ai") {
                                                echo '<i style="color:green;">Under AI evaluation</i>';
                                              } else {
                                                echo '<i style="color:green;">Under evaluation</i>';
                                              }
                                              
                                            } else { // default text
                                              if($this->role == "student") {
                                                  echo '<i style="color:green;">Under evaluation</i>';
                                              } else {
                                                  echo '<i style="color:green;">Under evaluation</i>';
                                              }
                                            }
                                        } ?>
                                    </span>
                                </div>
                            <?php endif;
                            
                            // Task 2 Display
                            if ( $has_task_2 ) : ?>
                                <div class="history-table__score-type">
                                    Task 2: <span class="history-table__score-num">
                                        <?php 
                                        // Show "Get Evaluation" if:
                                        // - User hasn't enrolled AND (task2_plan exists OR task1and2_plan exists)
                                        if ( ! $this->is_task_enrolled((array) $enrolled_for, $task_2_id) && 
                                            ( $this->evaluation_settings->writing_task2_plan || $this->evaluation_settings->writing_task1and2_plan ) ) {
                                                
                                                if($this->role == "student") {
                                                    echo 'Get Evaluation';
                                                } else {
                                                    echo 'Not enrolled';
                                                }
                                                
                                        } else {
                                            if(isset($enrolled_for[$task_2_id])){
                                                $task_obj = $enrolled_for[$task_2_id];
                                                $payment_for = isset($task_obj['payment_for'])? $task_obj['payment_for'] : 'instructor';
                                                if($payment_for == "instructor") {
                                                    echo '<i style="color:green;">Under evaluation</i>';
                                                } else if($payment_for == "ai") {
                                                    echo '<i style="color:green;">Under AI evaluation</i>';
                                                } else {
                                                    echo '<i style="color:green;">Under evaluation</i>';
                                                }
                                                
                                            } else { // default text
                                                if($this->role == "student") {
                                                    echo '<i style="color:green;">Under evaluation</i>';
                                                } else {
                                                    echo '<i style="color:green;">Under evaluation</i>';
                                                }
                                            }
                                        }
                                        ?>
                                    </span>
                                </div>
                            <?php endif;
                        return ob_get_clean();

                    } else {
                        ob_start();
                        if ( $has_task_1 ) : ?>
                            <div class="history-table__score-type">
                                Task 1: <span class="history-table__score-num">Under Evaluation</span>
                            </div>
                        <?php endif;
                        
                        if ( $has_task_2 ) : ?>
                            <div class="history-table__score-type">
                                Task 2: <span class="history-table__score-num">Under Evaluation</span>
                            </div>
                        <?php endif;
                        return ob_get_clean();
                    }
                }

            } else if($quiz_category === 'ielts-speaking') {
                // speaking dont required any sections
                if( $review == 1) {
                    // if review is 1, then get score from meta table
                    $overall_score = '--';
                    # get score from review-scores meta from review meta table using (result_id & section_id )
                    $speaking_scores = $this->get_speaking_review_score_from_review_and_review_meta( $submission_id, $user_id );
                    if( $speaking_scores ) {
                        $task_score_arr = $speaking_scores;
                        $task_score = array_sum( $task_score_arr ) / 4;
                        $task_score = round( $task_score * 2 );
                        $overall_score = $task_score/2;
                    } else {
                        $overall_score = '--';
                    }

                    # stop giving suggestion AI
                    // show all tasks scores 
                    ob_start(); ?>
                    <div class="history-table__score-type">
                        Tasks: <span class="history-table__score-num">
                            <?php echo $overall_score; ?>
                        </span>
                    </div>
                    <?php return ob_get_clean();
                    

                } else {
                    // if review is not 1, then show evaluation status, based on evaluation settings
                    if ( $this->evaluation_settings->enabled && $this->evaluation_settings->woocommerce_active  && $speaking_evaluation_enabled ) { 
                        // get the evaluation status by user id 
                        $enrolled_for = array();
                        $check_payment = $this->get_submission_evaluation_meta( $submission_id, "enrolled_for", $user_id, true );
                        if ( $check_payment ) {
                            $enrolled_for = (array) json_decode( $check_payment, true );
                        }

                        ob_start(); ?>
                        <div class="history-table__score-type">
                            Tasks: <span class="history-table__score-num">
                                <?php 

                                if( array_key_exists('speaking-tasks', (array) $enrolled_for) ) {
                                    $task_obj = $enrolled_for['speaking-tasks'];
                                    echo '<i style="color:green;">Under evaluation</i>';
                                    
                                } else if( array_key_exists('speaking-ai', (array) $enrolled_for) ) {
                                    $task_obj = $enrolled_for['speaking-ai'];
                                    echo '<i style="color:green;">Under AI evaluation</i>';
                                    
                                } else {
                                    if($this->role == "student") {
                                        echo 'Get Evaluation';
                                    } else {
                                        echo 'Not enrolled';
                                    }
                                }
                                ?>
                            </span>
                        </div>
                        <?php return ob_get_clean();
                    } else {
                        // if evaluation is not enabled, then show evaluation status
                        ob_start(); ?>
                        <div class="history-table__score-type">
                            Tasks: <span class="history-table__score-num">Under Evaluation</span>
                        </div>
                        <?php return ob_get_clean();
                    }
                }
            }

        }
        // For other quiz types, return placeholder for now
        return '--';
    }

    /**
     * get score from review and review meta table based on given susbmission_id, section_id
     */
    public function get_score_from_review_and_review_meta( $submission_id, $section_id, $user_id ) {
        global $wpdb;
        $review_id = $wpdb->get_var( $wpdb->prepare(
            "SELECT `ID` FROM {$this->review_table} 
            WHERE `result_id` = %d AND `section_id` = %s AND `user_id` = %d AND `status` = 1 LIMIT 1",
            $submission_id,
            $section_id,
            $user_id
        ) );

        if( $review_id ) {
            $review_scores = $wpdb->get_var( $wpdb->prepare(
                "SELECT meta_value FROM {$this->review_meta_table} 
                WHERE `review_id` = %d AND `meta_key` = 'review-scores' LIMIT 1",
                $review_id
            ) );
            if( $review_scores ) {
                $review_scores_json = json_decode( $review_scores, true );
                return $review_scores_json;
            }
        }
        return null;
    }

    /**
     * get speaking review score from review and review meta table based on given result id, user_id, but not section_id
     * 
     */
    public function get_speaking_review_score_from_review_and_review_meta( $result_id, $user_id ) {
        global $wpdb;
        $review_id = $wpdb->get_var( $wpdb->prepare(
            "SELECT `ID` FROM {$this->review_table} 
            WHERE `result_id` = %d AND `user_id` = %d AND `status` = 1 LIMIT 1",
            $result_id,
            $user_id
        ) );
        if( $review_id ) {
            $review_scores = $wpdb->get_var( $wpdb->prepare(
                "SELECT meta_value FROM {$this->review_meta_table} 
                WHERE `review_id` = %d AND `meta_key` = 'review-scores' LIMIT 1",
                $review_id
            ) );
            if( $review_scores ) {
                $review_scores_json = json_decode( $review_scores, true );
                return $review_scores_json;
            }
        }

        return null;
    }
    
    /**
     * Get tests by category with filters and pagination
     * 
     * @param string $category Quiz category
     * @param array $args Query arguments
     * @return array Array with tests and pagination data
     */
    public function get_tests_by_category( $category, $args = array() ) {
        global $wpdb;
        
        // Default arguments
        $defaults = array(
            'per_page'     => 10,
            'page'         => 1,
            'review'       => null,
            'course_id'    => null,
            'session_type' => null,
            'user_id'      => null
        );
        
        $args = wp_parse_args( $args, $defaults );
        
        // Build WHERE clauses
        $where_clauses = array( 'status = 1', 'session_status != 3' );

        
        // User filter based on role
        $user_ids_filter = $this->get_user_ids_filter_for_analytics();
        $where_clauses[] = "user_id IN ({$user_ids_filter})";
        
        // Category filter
        if ( $category == 'gov-exam' ) {
            $where_clauses[] = "(quiz_category = 'gov-sectional-timing' OR quiz_category = 'gov-non-sectional-timing')";
        } else {
            $where_clauses[] = $wpdb->prepare( "quiz_category = %s", $category );
        }
        
        // Session category (course or fullmock-test)
        $where_clauses[] = "(session_category = 'course' OR session_category = 'fullmock-test')";
        
        // Session status (completed or in progress)
        $where_clauses[] = "(session_status = 1 OR session_status = 2)";
        
        // Review filter (for writing/speaking)
        if ( $args['review'] !== null ) {
            $where_clauses[] = $wpdb->prepare( "review = %d", $args['review'] );
        }
        
        // Course filter
        if ( $args['course_id'] ) {
            $where_clauses[] = $wpdb->prepare( "course_id = %s", $args['course_id'] );
        }
        
        // Session type filter (fresh vs retake)
        if ( $args['session_type'] ) {
            $where_clauses[] = $wpdb->prepare( "session_type = %s", $args['session_type'] );
        }
        
        // Specific user filter (for admin/teacher)
        if ( $args['user_id'] ) {
            $where_clauses[] = $wpdb->prepare( "user_id = %d", $args['user_id'] );
        }
        
        $where_sql = implode( ' AND ', $where_clauses );
        
        // Get total count
        $total_query = "SELECT COUNT(*) FROM {$this->submissions_table} WHERE {$where_sql}";
        $total_records = (int) $wpdb->get_var( $total_query );
        
        // Calculate pagination
        $total_pages = $total_records > 0 ? ceil( $total_records / $args['per_page'] ) : 1;
        $current_page = min( $args['page'], $total_pages );
        $offset = ( $current_page - 1 ) * $args['per_page'];
        $remaining_records = max( 0, $total_records - ( $offset + $args['per_page'] ) );
        
        // Fetch records
        $query = "SELECT * FROM {$this->submissions_table} 
                  WHERE {$where_sql} 
                  ORDER BY date_created DESC 
                  LIMIT {$offset}, {$args['per_page']}";
        
        $tests = $wpdb->get_results( $query, ARRAY_A );
        
        return array(
            'tests' => $tests,
            'pagination' => array(
                'current_page' => $current_page,
                'total_pages' => $total_pages,
                'per_page' => $args['per_page'],
                'total_records' => $total_records,
                'remaining_records' => $remaining_records
            )
        );
    }
    
    /**
     * Render tests table HTML
     * 
     * @param array $tests Array of test records
     * @param string $category Quiz category
     * @param int $review_status Review status filter
     * @return string HTML table
     */
    public function render_tests_table( $tests, $category, $review_status = null ) {
        // Get category title
        $category_titles = array(
            'ielts-listening' => 'Listening Tests History',
            'ielts-reading'   => 'Reading Tests History',
            'ielts-writing'   => 'Writing Tests History',
            'ielts-speaking'  => 'Speaking Tests History',
            'gov-exam'       => 'Gov Exams History',
            'proqyz-pdf-quiz' => 'PDF Quiz History',
        );
        
        $page_title = isset( $category_titles[ $category ] ) ? $category_titles[ $category ] : 'Practice Test History';
        
        ob_start(); ?>
        <h1 class="section-tilte"><?php echo esc_html( $page_title ); ?></h1>

        <?php if ( empty( $tests ) ) : ?>
            <div class="test-history__empty-box">
                <?php if ( $this->role === 'student' ) : ?>
                    <h5 class="test-history__empty-title">You haven't taken any test yet.</h5>
                    <p class="test-history__empty-caption">How about give it a try?</p>
                <?php else : ?>
                    <h5 class="test-history__empty-title">No test records found for your students.</h5>
                    <p class="test-history__empty-caption">Your students haven't taken any tests in this category yet.</p>
                <?php endif; ?>
            </div>
        <?php
            return ob_get_clean();
        endif; ?>
        
        <table class="table table-hover history-table iot-responsive-table">
            <thead>
                <?php if ( $this->role === 'student' ) : ?>
                <tr>
                    <th class="th__date">Date</th>
                    <th class="th__testname">Test name</th>
                    <th class="th__score">Score</th>
                    <th class="th__course">Course</th>
                    <th class="th__actions"></th>
                </tr>
                <?php else : ?>
                <tr>
                    <th class="th__date">Date</th>
                    <th class="th__testname">Test name</th>
                    <th class="th__score">Score</th>
                    <th class="th__course">Course</th>
                    <th class="th__username">Username</th>
                    <th class="th__actions"></th>
                </tr>
                <?php endif; ?>
            </thead>
            <tbody>
                <?php foreach ( $tests as $test ) : 
                    echo $this->render_test_row( $test, $category );
                endforeach; ?>
            </tbody>
        </table>
        <?php
        return ob_get_clean();
    }
    
    /**
     * Render single test row
     * 
     * @param array $test Test data
     * @param string $category Quiz category
     * @return string HTML table row
     */
    private function render_test_row( $test, $category ) {
        global $wpdb;
        
        // Get test title from meta
        $test_title = $wpdb->get_var( $wpdb->prepare(
            "SELECT meta_value FROM {$this->meta_table} 
            WHERE submission_id = %d AND meta_key = 'quiz_title' LIMIT 1",
            $test['ID']
        ) );
        
        $test_title = $test_title ? $test_title : 'Test #' . $test['ID'];
        $date = date( 'd/m/y h:i A', $test['date_created'] );

        // test actual category 
        $test_category = $test['quiz_category'];
        
        // Get student name if admin/teacher
        $student_name = '';
        if ( $this->role === 'admin' || $this->role === 'teacher' ) {
            $user = get_userdata( $test['user_id'] );
            $student_name = $user ? $user->display_name : 'Unknown';
        }
        
        // Get course title
        $course_title = $wpdb->get_var( $wpdb->prepare(
            "SELECT meta_value FROM {$this->meta_table} 
            WHERE submission_id = %d AND meta_key = 'course_title' LIMIT 1",
            $test['ID']
        ) );
        $course_title = $course_title ? $course_title : '--';

        // Get course subcategory from meta table
        $course_subcategory = $wpdb->get_var( $wpdb->prepare(
            "SELECT meta_value FROM {$this->meta_table} 
            WHERE submission_id = %d AND meta_key = 'course_subcategory' LIMIT 1",
            $test['ID']
        ) );
        $course_subcategory = $course_subcategory ? $course_subcategory : 'academic';
        
        // Get quiz_slug from meta table
        $quiz_slug = $wpdb->get_var( $wpdb->prepare(
            "SELECT meta_value FROM {$this->meta_table} 
            WHERE submission_id = %d AND meta_key = 'quiz_slug' LIMIT 1",
            $test['ID']
        ) );
        
        // api_id is already in the submissions table
        $api_id = $test['api_id'];
        
        // Generate review/result URL
        $result_url = $this->get_test_url( $test['quiz_category'], $quiz_slug, $api_id, $test['ID'] );
        
        
        
        $session_category = $test['session_category'];
        $lesson_title = '';
        if( $session_category == 'fullmock-test') {
            $lesson_title = $wpdb->get_var( $wpdb->prepare(
                "SELECT meta_value FROM {$this->meta_table} 
                WHERE submission_id = %d AND meta_key = 'lesson_title' LIMIT 1",
                $test['ID']
            ) );
            $lesson_title = $lesson_title ? $lesson_title : '';
        }

        // need to fetch course from meta table as meta_key session_detail, meta_value is serialized object
        $evaluation_object = null;
        if($test_category == 'ielts-speaking' || $test_category == 'ielts-writing'){
            $session_detail = $wpdb->get_var( $wpdb->prepare(
                "SELECT session_data FROM {$this->session_table} 
                WHERE submission_id = %d LIMIT 1",
                $test['ID']
            ) );
            
            if( $session_detail) {
                $session_detail = maybe_unserialize( $session_detail );
                $session_detail = ! empty( $session_detail ) ? (object) $session_detail : null;
                $course = isset( $session_detail->course ) ? (object)$session_detail->course : null;
                $evaluation_object = isset( $course->_evaluation ) ? (object) $course->_evaluation : null;
            }
        }

        // Get score display based on category
        $score_display = $this->get_score_display( $test['ID'], $category, $test['review'], $evaluation_object, $course_subcategory );
        
        ob_start(); ?>
        <tr>
            <td class="history-table__date"><?php echo esc_html( $date ); ?></td>
            <td class="history-table__test-name">
                <?php if($test['session_category'] == 'fullmock-test') { ?>
                    <div style="display: flex; flex-direction: column; align-items: flex-start; gap: 0px;">
                        <span class="test_title"><?php echo esc_html( $test_title ); ?></span>
                        <span class="test_type" style="color:#7c002a;">Fullmock Test</span>
                    </div>
                <?php } else { ?>
                    <?php echo esc_html( $test_title ); ?>
                <?php } ?>
            </td>
            <td class="history-table__score" data-label="Score">
                <?php echo $score_display; ?>
            </td>
            <td class="history-table__course" data-label="Course">
                <?php if($session_category == 'fullmock-test') { ?>
                    <div class="md--align-right lg--align-left">
                        <span class="test_title"><?php echo esc_html( $course_title ); ?></span>
                        <span class="test_type" style="color:green;"><?php echo esc_html( $lesson_title ); ?></span>
                    </div>
                <?php } else { ?>
                    <?php echo esc_html( $course_title ); ?>
                <?php } ?>
            </td>
            <?php if ( $this->role === 'admin' || $this->role === 'teacher' ) : ?>
            <td class="history-table__username" data-label="Username"><?php echo esc_html( $student_name ); ?></td>
            <?php endif; ?>
            <td class="history-table__action">
                <?php if($session_category == 'fullmock-test') { ?>
                    <div class="history-table__btn-group">
                        <a href="<?php echo esc_url( $result_url ); ?>" class="history-table__btn-view" target="_blank">Review</a>
                        <div class="history-table__other-btn">
                            <span class="ioticon-chevron-down"></span>
                            <span class="history-table__hidden-group">
                                <a href="<?php echo esc_url(st_proqyz_get_mock_test_url($test['course_id'], $test['lesson_id'], 'result')); ?>" target="_blank" class="history-table__btn view-result">
                                    Full Review
                                </a>
                            </span>
                        </div>
                    </div>
                <?php } else { ?>
                    <div class="history-table__btn-group">
                        <a href="<?php echo esc_url( $result_url ); ?>" class="history-table__btn-view" target="_blank">Review</a>
                        <div class="history-table__other-btn">
                            <span class="ioticon-chevron-down"></span>
                            <span class="history-table__hidden-group">
                                <a href="javascript:;" 
                                    data-proqyz-delete-modal="true"
                                    data-test-id="<?php echo esc_attr( $test['ID'] ); ?>"
                                    data-test-category="<?php echo esc_attr( $test_category ); ?>"
                                    class="history-table__btn -delete">
                                    <span class="ioticon-trash-3"></span>Delete
                                </a>
                            </span>
                        </div>
                    </div>
                <?php } ?>
            </td>
        </tr>
        <?php
        return ob_get_clean();
    }
    
    /**
     * Get test URL based on role and quiz category
     * 
     * @param string $quiz_category Quiz category
     * @param string $quiz_slug Quiz slug
     * @param string $api_id API ID
     * @param int $result_id Result ID
     * @return string Test URL
     */
    private function get_test_url( $quiz_category, $quiz_slug, $api_id, $result_id ) {
        // Default fallback
        $result_url = 'javascript:;';
        
        // Only generate URL if quiz_slug exists
        if ( ! $quiz_slug ) {
            return $result_url;
        }
        
        // Check if URL helper functions exist
        if ( ! function_exists( 'st_proqyz_get_review_url' ) || ! function_exists( 'st_proqyz_get_result_url' ) ) {
            return $result_url;
        }
        
        // Admin and Teacher roles
        if ( $this->role === 'admin' || $this->role === 'teacher' ) {
            // For writing/speaking, use review URL
            if ( $quiz_category === 'ielts-writing' || $quiz_category === 'ielts-speaking' ) {
                $result_url = st_proqyz_get_review_url( $quiz_category, $quiz_slug, $api_id, $result_id );
            } else {
                // For other quiz types, use result URL
                $result_url = st_proqyz_get_result_url( $quiz_category, $quiz_slug, $api_id, $result_id );
            }
        } else {
            // Students always see the result page
            $result_url = st_proqyz_get_result_url( $quiz_category, $quiz_slug, $api_id, $result_id );
        }
        
        return $result_url;
    }
    
    /**
     * Render pagination HTML
     * 
     * @param array $pagination Pagination data
     * @return string HTML pagination
     */
    public function render_pagination( $pagination ) {
        if ( $pagination['total_pages'] <= 0 ) {
            return '';
        }
        
        $current_page = $pagination['current_page'];
        $total_pages = $pagination['total_pages'];
        $per_page = $pagination['per_page'];
        $total_records = $pagination['total_records'];
        
        ob_start(); ?>
        <div class="test-history__bottom"
             data-current-page="<?php echo $current_page; ?>" 
             data-total-pages="<?php echo $total_pages; ?>"
             data-per-page="<?php echo $per_page; ?>"
             data-total-records="<?php echo $total_records; ?>">
            
            <!-- Per Page Selector (Left) -->
            <div class="test-history__per-page">
                <label for="per-page-select">Show:</label>
                <select id="per-page-select" class="per-page-select">
                    <option value="10" <?php selected( $per_page, 10 ); ?>>10</option>
                    <option value="30" <?php selected( $per_page, 30 ); ?>>30</option>
                    <option value="50" <?php selected( $per_page, 50 ); ?>>50</option>
                    <option value="100" <?php selected( $per_page, 100 ); ?>>100</option>
                </select>
            </div>
            
            <!-- Pagination Navigation (Right) -->
            <nav class="pager clearfix">
                <ul class="pager__items js-pager__items">
                    <?php
                    // Calculate offset for data attributes
                    $current_offset = ( $current_page - 1 ) * $per_page;
                    
                    // First button (only show if not on first page)
                    if ( $current_page > 1 ) : ?>
                        <li class="pager__item pager__item_first">
                            <a href="javascript:;" 
                                data-offset="0" 
                                data-total="<?php echo $total_records; ?>" 
                                data-page="1"
                                class="test-history__view-more pagination-btn" 
                                rel="« First">« First</a>
                        </li>
                    <?php endif; ?>
                    
                    <?php
                    // Previous button
                    if ( $current_page > 1 ) : 
                        $prev_offset = ( $current_page - 2 ) * $per_page;
                    ?>
                        <li class="pager__item pager__item_previous">
                            <a href="javascript:;" 
                                data-offset="<?php echo $prev_offset; ?>" 
                                data-total="<?php echo $total_records; ?>" 
                                data-page="<?php echo $current_page - 1; ?>"
                                class="test-history__view-more pagination-btn" 
                                rel="‹ Prev">‹ Prev</a>
                        </li>
                    <?php endif; ?>
                    
                    <?php
                    // Show max 5 page numbers
                    $start_page = max( 1, $current_page - 2 );
                    $end_page = min( $total_pages, $current_page + 2 );
                    
                    // Adjust if we're at the beginning or end
                    if ( $current_page <= 3 ) {
                        $end_page = min( 5, $total_pages );
                    }
                    if ( $current_page >= $total_pages - 2 ) {
                        $start_page = max( 1, $total_pages - 4 );
                    }
                    
                    // Page numbers
                    for ( $i = $start_page; $i <= $end_page; $i++ ) : 
                        $offset = ( $i - 1 ) * $per_page;
                        $is_active = $i === $current_page ? 'is-active' : '';
                    ?>
                        <li class="pager__item <?php echo $is_active; ?>">
                            <a href="javascript:;" 
                               data-offset="<?php echo $offset; ?>" 
                               data-total="<?php echo $total_records; ?>" 
                               data-page="<?php echo $i; ?>"
                               class="test-history__view-more pagination-btn" 
                               rel="<?php echo $i; ?>"><?php echo $i; ?></a>
                        </li>
                    <?php endfor; ?>
                    
                    <?php if ( $current_page < $total_pages ) : 
                        $next_offset = $current_page * $per_page;
                    ?>
                        <li class="pager__item pager__item_next_update">
                            <a href="javascript:;" 
                               data-offset="<?php echo $next_offset; ?>" 
                               data-total="<?php echo $total_records; ?>" 
                               data-page="<?php echo $current_page + 1; ?>"
                               class="test-history__view-more pagination-btn" 
                               rel="Next ›">Next ›</a>
                        </li>
                    <?php endif; ?>
                    
                    <?php if ( $current_page < $total_pages ) : 
                        $last_offset = ( $total_pages - 1 ) * $per_page;
                    ?>
                        <li class="pager__item pager__item_last">
                            <a href="javascript:;" 
                               data-offset="<?php echo $last_offset; ?>" 
                               data-total="<?php echo $total_records; ?>" 
                               data-page="<?php echo $total_pages; ?>"
                               class="test-history__view-more pagination-btn" 
                               rel="Last »">Last »</a>
                        </li>
                    <?php endif; ?>
                </ul>
            </nav>
        </div>
        <?php
        return ob_get_clean();
    }
    
    /**
     * Render complete test history section wrapper
     * 
     * @param string $filters_html Filters HTML
     * @param string $table_html Table HTML
     * @param string $pagination_html Pagination HTML
     * @return string Complete wrapped HTML
     */
    public function render_test_history_section( $filters_html, $table_html, $pagination_html, $show = "" ) {
        ob_start(); ?>
        <section class="test-history">  
            <!-- Modile filters button -->
            <?php if ( $show ) : ?>
            <button class="test-history__btn-filter-mobile visible-xs <?php echo $show; ?>" id="js-btn-filter"> 
                <span class="ioticon-filter"></span>Apply 
            </button>   
            <?php endif; ?>
            <?php echo $filters_html; ?>
            <?php echo $table_html; ?>
            <?php echo $pagination_html; ?>
        </section>
        <?php
        return ob_get_clean();
    }
    
    /**
     * Render filters HTML
     * 
     * @param string $category Quiz category
     * @param int $review_status Current review status
     * @param array $current_filters Current filter values to preserve
     * @return string HTML filters
     */
    public function render_filters( $category, $review_status = null, $current_filters = array() ) {
        $courses = $this->get_courses();
        
        // Parse current filter values
        $selected_course = isset( $current_filters['course'] ) ? $current_filters['course'] : 'all';
        $selected_session_type = isset( $current_filters['session_type'] ) ? $current_filters['session_type'] : 'all';
        $selected_user = isset( $current_filters['user'] ) ? $current_filters['user'] : 'all';
        
        ob_start(); ?>
        <div class="test-history__filter">
            <!-- Hidden field to store current category for pagination -->
            <input type="hidden" id="quiz_category" value="<?php echo esc_attr( $category ); ?>" />
            
            <!-- Course Filter -->
            <select class="v-select filter-select selectpicker dropdown bootstrap-select iot-opselect -rounded" name="course" id="filter-course" 
                    data-style="btn-default" data-width="auto" data-size="10" data-live-search="true">
                <option value="all" <?php selected( $selected_course, 'all' ); ?>>All Courses</option>
                <?php foreach ( $courses as $course ) : ?>
                    <option value="<?php echo esc_attr( $course->id ); ?>" <?php selected( $selected_course, $course->id ); ?>>
                        <?php echo esc_html( $course->course_title ); ?>
                    </option>
                <?php endforeach; ?>
            </select>
            
            <!-- Attempt Type Filter (session_type: fresh/retake) -->
            <select class="v-select filter-select selectpicker dropdown bootstrap-select iot-opselect -rounded" name="session_type" id="filter-session-type" 
                    data-style="btn-default" data-width="auto">
                <option value="all" <?php selected( $selected_session_type, 'all' ); ?>>All Attempts</option>
                <option value="fresh" <?php selected( $selected_session_type, 'fresh' ); ?>>Fresh (First Attempt)</option>
                <option value="retake" <?php selected( $selected_session_type, 'retake' ); ?>>Retake</option>
            </select>
            
            <!-- Review Filter (for writing/speaking only) -->
            <?php if ( $category === 'ielts-writing' || $category === 'ielts-speaking' ) : ?>
            <select class="v-select filter-select selectpicker dropdown bootstrap-select iot-opselect -rounded" name="review" id="filter-review" 
                    data-style="btn-default" data-width="auto">
                <option value="0" <?php selected( $review_status, 0 ); ?>>Unreviewed</option>
                <option value="1" <?php selected( $review_status, 1 ); ?>>Reviewed</option>
            </select>
            <?php endif; ?>
            
            <!-- Student Filter (admin/teacher only) -->
            <?php if ( $this->role === 'admin' || $this->role === 'teacher' ) : ?>
            <select class="v-select filter-select selectpicker dropdown bootstrap-select iot-opselect -rounded" name="user" id="filter-students" 
                    data-style="btn-default" data-width="auto" data-size="10" data-live-search="true">
                <option value="all" <?php selected( $selected_user, 'all' ); ?>>All Students</option>
                <?php
                if ( ! empty( $this->current_user->student_ids ) ) :
                    // Normalize IDs
                    $student_ids = array_map( 'intval', (array) $this->current_user->student_ids );

                    // Fast fetch: single query, only needed fields
                    $students = get_users( array(
                        'include' => $student_ids,
                        'fields'  => array( 'ID', 'display_name', 'user_email' ),
                        'orderby' => 'display_name', // nice alphabetical dropdown
                        'order'   => 'ASC',
                        'number'  => -1,
                    ) );

                    if ( ! empty( $students ) ) :
                        foreach ( $students as $student ) : ?>
                            <option value="<?php echo esc_attr( $student->ID ); ?>"
                                <?php selected( (string) $selected_user, (string) $student->ID ); ?>>
                                <?php
                                    echo '(#' . esc_html( $student->ID ) . ') '
                                       . esc_html( $student->display_name )
                                       . ' [' . esc_html( $student->user_email ) . ']';
                                ?>
                            </option>
                        <?php
                        endforeach;
                    endif;
                endif;
                ?>
            </select>
            <?php endif; ?>
            
            <button class="test-history__btn-filter test-history__btn iot-bt filter_btns" id="apply-filters">Apply</button>
            <button class="test-history__btn-reset test-history__btn iot-bt filter_btns">
                <span class="ioticon-refresh-double"></span>
            </button>
        </div>
        <?php
        return ob_get_clean();
    }
    
    /**
     * Get abandoned tests (admin only)
     * Tests from users that no longer exist or are trashed
     * 
     * @param array $args Query arguments
     * @return array Array with tests and pagination data
     */
    public function get_abandoned_tests( $args = array() ) {
        global $wpdb;
        
        // Only allow admin access
        if ( $this->role !== 'admin' ) {
            return array(
                'tests' => array(),
                'pagination' => array(
                    'current_page'  => 1,
                    'per_page'      => 10,
                    'total_pages'   => 0,
                    'total_records' => 0,
                ),
            );
        }
        
        // Default arguments
        $defaults = array(
            'per_page'     => 10,
            'page'         => 1,
            'course_id'    => null,
            'session_type' => null,
            'category'     => null,
        );
        
        $args = wp_parse_args( $args, $defaults );
        
        // Build WHERE clauses
        $where_clauses = array( 's.status = 1', 's.session_status != 3' );
        
        // Find submissions where user_id doesn't exist in wp_users OR user is deleted (trash)
        // We'll use a LEFT JOIN and check for NULL or deleted user
        $where_clauses[] = "(u.ID IS NULL OR u.user_status != 0)";
        
        // Optional filters
        if ( $args['course_id'] ) {
            $where_clauses[] = $wpdb->prepare( "s.course_id = %s", $args['course_id'] );
        }
        
        if ( $args['session_type'] ) {
            $where_clauses[] = $wpdb->prepare( "s.session_type = %s", $args['session_type'] );
        }
        
        if ( $args['category'] ) {
            $where_clauses[] = $wpdb->prepare( "s.quiz_category = %s", $args['category'] );
        }
        
        $where_sql = implode( ' AND ', $where_clauses );
        
        // Get total count
        $total_query = "SELECT COUNT(*) 
                       FROM {$this->submissions_table} s
                       LEFT JOIN {$this->users_table} u ON s.user_id = u.ID
                       WHERE {$where_sql}";
        $total_records = (int) $wpdb->get_var( $total_query );
        
        // Calculate pagination
        $total_pages = $total_records > 0 ? ceil( $total_records / $args['per_page'] ) : 1;
        $current_page = min( $args['page'], $total_pages );
        $offset = ( $current_page - 1 ) * $args['per_page'];
        
        // Fetch records
        $query = "SELECT s.*, u.user_login, u.user_status
                 FROM {$this->submissions_table} s
                 LEFT JOIN {$this->users_table} u ON s.user_id = u.ID
                 WHERE {$where_sql} 
                 ORDER BY s.date_created DESC 
                 LIMIT {$offset}, {$args['per_page']}";
        
        $tests = $wpdb->get_results( $query, ARRAY_A );
        
        return array(
            'tests' => $tests,
            'pagination' => array(
                'current_page'  => (int) $current_page,
                'per_page'      => (int) $args['per_page'],
                'total_pages'   => (int) $total_pages,
                'total_records' => (int) $total_records,
            ),
        );
    }
    
    /**
     * Render abandoned tests table (admin only)
     * 
     * @param array $tests Tests array
     * @return string HTML table
     */
    public function render_abandoned_tests_table( $tests ) {
        global $wpdb;

        $abandoned_counts = $this->get_abandoned_counts();
        $ielts_reading_count = $abandoned_counts['counts']['ielts-reading'];
        $ielts_listening_count = $abandoned_counts['counts']['ielts-listening'];
        $ielts_writing_count = $abandoned_counts['counts']['ielts-writing'];
        $ielts_speaking_count = $abandoned_counts['counts']['ielts-speaking'];
        ob_start(); ?>
        <style>
            .delete-abandoned-tests-by-category {
                border: 1px solid;
                padding: 4px 15px;
                border-radius: 20px;
                width: 100%;
                text-align: center;
                background: #294563 !important;
                color: white !important;
                display: flex;
                flex-direction: row;
                align-items: center;
                gap: 6px;
                justify-content: center;
            }
            .delete-abandoned-tests-by-category.disabled {
                cursor: no-drop !important;
                opacity: 0.5 !important;
            }
            @media(max-width: 600px) {
                .sm-flex-col {
                    flex-direction: column !important;
                }
            }
            
        </style>

        <h1 class="section-tilte">Abandoned Tests</h1>
        <div class="sm-flex-col" style="display:flex; flex-direction: row; align-items:center; gap:10px; justify-content: space-between; margin-bottom: 20px;">
            <a href="javascript:;" class="btn btn-primary delete-abandoned-tests-by-category" data-category="ielts-reading" data-label="Readings">
                <span class="ioticon-trash-3"></span> Readings (<span class="abandoned-remaining" data-category="ielts-reading"><?php echo $ielts_reading_count; ?></span>)
            </a>
            <a href="javascript:;" class="btn btn-primary delete-abandoned-tests-by-category" data-category="ielts-listening" data-label="Listenings">
                <span class="ioticon-trash-3"></span> Listenings (<span class="abandoned-remaining" data-category="ielts-listening"><?php echo $ielts_listening_count; ?></span>)
            </a>
        </div>
        <div class="sm-flex-col" style="display:flex; flex-direction: row; align-items:center; gap:10px; justify-content: space-between; margin-bottom: 20px;">
            <a href="javascript:;" class="btn btn-primary delete-abandoned-tests-by-category" data-category="ielts-writing" data-label="Writings">
                <span class="ioticon-trash-3"></span> Writings (<span class="abandoned-remaining" data-category="ielts-writing"><?php echo $ielts_writing_count; ?></span>)
            </a>
            <a href="javascript:;" class="btn btn-primary delete-abandoned-tests-by-category" data-category="ielts-speaking" data-label="Speakings">
                <span class="ioticon-trash-3"></span> Speakings (<span class="abandoned-remaining" data-category="ielts-speaking"><?php echo $ielts_speaking_count; ?></span>)
            </a>
        </div>
        <div class="notice--area"></div>
        <?php if ( empty( $tests ) ) : ?>
            <div class="test-history__empty-box">
                <h5 class="test-history__empty-title">No abandoned tests found.</h5>
                <p class="test-history__empty-caption">All test records belong to active users.</p>
            </div>
        <?php
            return ob_get_clean();
        endif;
        ?>
        <table class="table table-hover history-table iot-responsive-table">
            <thead>
                <tr>
                    <th class="th__date">Date</th>
                    <th class="th__testname">Test name</th>
                    <th class="th__score">Score</th>
                    <th class="th__course">Course</th>
                    <th class="th__username">User ID (Abandoned)</th>
                    <th class="th__actions"></th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ( $tests as $test ) : 
                    $quiz_type = $this->format_quiz_type( $test['quiz_category'] );
                    $date = date( 'M j, Y', $test['date_created'] );
                    
                    // Get quiz title from meta
                    $test_title = $wpdb->get_var( $wpdb->prepare(
                        "SELECT meta_value FROM {$this->meta_table} 
                        WHERE submission_id = %d AND meta_key = 'quiz_title' LIMIT 1",
                        $test['ID']
                    ) );
                    $test_name = $test_title ? $test_title : $quiz_type;
                    
                    // Get course title
                    $course_title = '--';
                    $course_subcategory = 'academic';
                    if ( ! empty( $test['course_id'] ) ) {
                        // First check cached courses
                        foreach ( $this->courses as $course ) {
                            if ( $course->id === $test['course_id'] ) {
                                $course_title = $course->course_title;
                                break;
                            }
                        }
                        
                        // If not found in cache, query meta table
                        if ( $course_title === '--' ) {
                            $course_title_from_meta = $wpdb->get_var( $wpdb->prepare(
                                "SELECT meta_value FROM {$this->meta_table} 
                                WHERE submission_id = %d 
                                AND meta_key = 'course_title' 
                                LIMIT 1",
                                $test['ID']
                            ) );
                            
                            if ( ! empty( $course_title_from_meta ) ) {
                                $course_title = $course_title_from_meta;
                            }
                        }

                        $course_subcategory = $wpdb->get_var( $wpdb->prepare(
                            "SELECT meta_value FROM {$this->meta_table} 
                            WHERE submission_id = %d AND meta_key = 'course_subcategory' LIMIT 1",
                            $test['ID']
                        ) );
                        $course_subcategory = $course_subcategory ? $course_subcategory : 'academic';
                    }
                    
                    // Score display
                    $score_display = $this->get_score_display( $test['ID'], $test['quiz_category'], $test['review'], $test['user_id'], $course_subcategory );
                ?>
                <tr>
                    <td class="history-table__date"><?php echo esc_html( $date ); ?></td>
                    <td class="history-table__test-name"><?php echo esc_html( $test_name ); ?></td>
                    <td class="history-table__score" data-label="Score"><?php echo $score_display; ?></td>
                    <td class="history-table__course" data-label="Course"><?php echo esc_html( $course_title ); ?></td>
                    <td class="history-table__username" data-label="Username">
                        <span class="badge badge-danger">User #<?php echo esc_html( $test['user_id'] ); ?></span>
                    </td>
                    <td class="history-table__action">
                        <div class="history-table__btn-group">
                            <a href="javascript:;" 
                               data-proqyz-delete-modal="true"
                               data-test-id="<?php echo esc_attr( $test['ID'] ); ?>"
                               data-test-category="<?php echo esc_attr( $test['quiz_category'] ); ?>"
                               class="history-table__btn -delete">
                                <span class="ioticon-trash-3"></span>Delete
                            </a>
                        </div>
                    </td>
                </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
        <?php return ob_get_clean();
    }

    /**
     * util for abandoned tests table
     */
    public function get_abandoned_count( $category ) {
        global $wpdb;
    
        $deleted_user_ids = $this->get_missing_user_ids( $category );
        if ( empty( $deleted_user_ids ) ) {
            return array(
                'count'            => 0,
                'deleted_user_ids' => $deleted_user_ids,
            );
        }
    
        $placeholders      = implode( ',', array_fill( 0, count( $deleted_user_ids ), '%d' ) );
    
        $count = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$this->submissions_table} WHERE quiz_category = %s AND user_id IN ($placeholders)",
                array_merge( array( $category ), $deleted_user_ids )
            )
        );
    
        return array(
            'count'            => $count,
            'deleted_user_ids' => $deleted_user_ids,
        );
    }
    
    public function get_abandoned_counts() {
        // Only privileged roles can view/delete abandoned data
        $current_user = wp_get_current_user();
        $is_admin_or_teacher = in_array( 'administrator', $current_user->roles ) ||
            in_array( 'teacher', $current_user->roles ) ||
            in_array( 'instructor', $current_user->roles ) ||
            in_array( 'trainer', $current_user->roles );
    
        if ( ! $is_admin_or_teacher ) {
            wp_send_json_error(
                array(
                    'message' => 'Permission denied',
                    'code'    => 403,
                )
            );
        }
    
        $categories = array(
            'ielts-reading',
            'ielts-listening',
            'ielts-writing',
            'ielts-speaking',
        );
    
        $counts = array();
        foreach ( $categories as $category ) {
            $counts[ $category ] = proqyz_dashboard_get_abandoned_count( $category )['count'];
        }
    
        
        return array(
            'counts' => $counts
        );
        
    }

    public function get_missing_user_ids( $category ) {
        global $wpdb;
    
        $user_ids          = $wpdb->get_col(
            $wpdb->prepare(
                "SELECT DISTINCT user_id FROM {$this->submissions_table} WHERE quiz_category = %s",
                $category
            )
        );
    
        $deleted_user_ids = array();
        foreach ( $user_ids as $user_id ) {
            $user = $wpdb->get_row(
                $wpdb->prepare(
                    "SELECT ID FROM {$wpdb->prefix}users WHERE ID = %d",
                    $user_id
                )
            );
            if ( ! $user ) {
                $deleted_user_ids[] = $user_id;
            }
        }
    
        return $deleted_user_ids;
    }
    
    /**
     * Render filters for abandoned tests
     * 
     * @param array $current_filters Current filter values to preserve
     * @return string HTML filters
     */
    public function render_abandoned_tests_filters( $current_filters = array() ) {
        $courses = $this->get_courses();
        
        // Get all quiz categories for filter
        $quiz_categories = array(
            'ielts-listening' => 'IELTS Listening',
            'ielts-reading'   => 'IELTS Reading',
            'ielts-writing'   => 'IELTS Writing',
            'ielts-speaking'  => 'IELTS Speaking',
            'gov-exam'       => 'Gov Exams',
            'proqyz-pdf-quiz' => 'PDF Quiz',
        );
        
        // Parse current filter values
        $selected_category = isset( $current_filters['category'] ) ? $current_filters['category'] : 'all';
        $selected_course = isset( $current_filters['course'] ) ? $current_filters['course'] : 'all';
        $selected_session_type = isset( $current_filters['session_type'] ) ? $current_filters['session_type'] : 'all';
        
        ob_start(); ?>
        <div class="test-history__filter">
            <!-- Hidden field to store current tab -->
            <input type="hidden" id="quiz_category" value="abandoned" />
            
            <!-- Test Category Filter -->
            <select class="v-select filter-select selectpicker dropdown bootstrap-select iot-opselect -rounded" 
                    name="category" id="filter-category" 
                    data-style="btn-default" data-width="auto" data-size="10">
                <option value="all" <?php selected( $selected_category, 'all' ); ?>>All Test Types</option>
                <?php foreach ( $quiz_categories as $cat_slug => $cat_name ) : ?>
                    <option value="<?php echo esc_attr( $cat_slug ); ?>" <?php selected( $selected_category, $cat_slug ); ?>>
                        <?php echo esc_html( $cat_name ); ?>
                    </option>
                <?php endforeach; ?>
            </select>
            
            <!-- Course Filter -->
            <select class="v-select filter-select selectpicker dropdown bootstrap-select iot-opselect -rounded" 
                    name="course" id="filter-course" 
                    data-style="btn-default" data-width="auto" data-size="10" data-live-search="true">
                <option value="all" <?php selected( $selected_course, 'all' ); ?>>All Courses</option>
                <?php foreach ( $courses as $course ) : ?>
                    <option value="<?php echo esc_attr( $course->id ); ?>" <?php selected( $selected_course, $course->id ); ?>>
                        <?php echo esc_html( $course->course_title ); ?>
                    </option>
                <?php endforeach; ?>
            </select>
            
            <!-- Session Type Filter -->
            <select class="v-select filter-select selectpicker dropdown bootstrap-select iot-opselect -rounded" 
                    name="session_type" id="filter-session-type" 
                    data-style="btn-default" data-width="auto">
                <option value="all" <?php selected( $selected_session_type, 'all' ); ?>>All Attempts</option>
                <option value="fresh" <?php selected( $selected_session_type, 'fresh' ); ?>>Fresh (First Attempt)</option>
                <option value="retake" <?php selected( $selected_session_type, 'retake' ); ?>>Retake</option>
            </select>
            
            <button class="test-history__btn-filter test-history__btn iot-bt filter_btns" id="apply-filters">Apply</button>
            <button class="test-history__btn-reset test-history__btn iot-bt filter_btns">
                <span class="ioticon-refresh-double"></span>
            </button>
        </div>
        <?php
        return ob_get_clean();
    }

  	// helper function
    private function is_task_enrolled($enrolled_for, $task_id) {
        if (empty($enrolled_for) || !is_array($enrolled_for)) {
            return false;
        }

        
        if(array_key_exists($task_id, $enrolled_for)){
            return true;
        }

        return false;
    }

    /**
     * Get evaluation metadata for a submission
     * 
     * Similar to WordPress get_user_meta(), but for the v3 evaluation metadata table.
     * Retrieves metadata value(s) for the given submission_id, user_id, and meta_key.
     * Returns raw meta_value as stored in database (no unserialization or json_decode).
     * 
     * @param int|string $submission_id The submission/session ID
     * @param string $meta_key The metadata key (optional, if empty returns all meta for submission+user)
     * @param int $user_id The user ID (defaults to class user_id if not provided)
     * @param bool $single Whether to return a single value (true) or array of values (false). Default true.
     * @return mixed Single raw meta value if $single is true, array of raw values if false, empty string/array if not found
     * 
     * @since 2.1.0
     */
    private function get_submission_evaluation_meta( $submission_id, $meta_key = '', $user_id = null, $single = true ) {
        global $wpdb;
        
        // Use class user_id if not provided
        if ( $user_id === null ) {
            $user_id = $this->user_id;
        }
        
        // Validate inputs
        if ( empty( $submission_id ) || empty( $user_id ) ) {
            return $single ? '' : array();
        }
        
        // Convert submission_id to string (session_id is varchar)
        $session_id = (string) $submission_id;
        $user_id = absint( $user_id );
        
        if ( ! empty( $meta_key ) ) {
            // Get specific meta key
            $meta_key = sanitize_text_field( $meta_key );
            
            $results = $wpdb->get_results( $wpdb->prepare(
                "SELECT meta_value FROM {$this->evaluation_meta_table} 
                 WHERE session_id = %s AND user_id = %d AND meta_key = %s 
                 ORDER BY meta_id ASC",
                $session_id,
                $user_id,
                $meta_key
            ) );
            
            if ( empty( $results ) ) {
                return $single ? '' : array();
            }
            
            $values = array();
            foreach ( $results as $row ) {
                $values[] = $row->meta_value; // Return raw value without unserialization
            }
            
            if ( $single ) {
                return $values[0];
            } else {
                return $values;
            }
        } else {
            // Get all meta keys for this submission+user
            $results = $wpdb->get_results( $wpdb->prepare(
                "SELECT meta_key, meta_value FROM {$this->evaluation_meta_table} 
                 WHERE session_id = %s AND user_id = %d 
                 ORDER BY meta_key ASC, meta_id ASC",
                $session_id,
                $user_id
            ) );
            
            if ( empty( $results ) ) {
                return array();
            }
            
            $meta = array();
            foreach ( $results as $row ) {
                $key = $row->meta_key;
                $value = $row->meta_value; // Return raw value without unserialization
                
                if ( $single ) {
                    // For single mode, return first value for each key
                    if ( ! isset( $meta[ $key ] ) ) {
                        $meta[ $key ] = $value;
                    }
                } else {
                    // For multiple mode, return array of values for each key
                    if ( ! isset( $meta[ $key ] ) ) {
                        $meta[ $key ] = array();
                    }
                    $meta[ $key ][] = $value;
                }
            }
            
            return $meta;
        }
    }

  	// helper function 2
    public function get_enrolled_task_object($enrolled_for, $task_id) {
        if (empty($enrolled_for) || !is_array($enrolled_for)) {
            return null;
        }

        if(array_key_exists($task_id, (array) $enrolled_for)){
            return (object) $enrolled_for[$task_id];
        }

        return null; // no match found
    }


}

