<?php

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

if ( ! class_exists( 'WP_List_Table' ) ) {
	require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}

/**
 * Handle Speaking Test Results Admin Page using WP_List_Table.
 */
class WPVoice_TestResults {

	private static $instance;

	private function __construct() {
		add_action( 'admin_menu', [ $this, 'add_results_menu' ], 1001 );
	}

	public static function get_instance() {
		if ( ! isset( self::$instance ) && ! ( self::$instance instanceof WPVoice_TestResults ) ) {
			self::$instance = new WPVoice_TestResults;
		}

		return self::$instance;
	}

    public function handle_bulk_actions() {
        if ( ! isset( $_POST['page'] ) || $_POST['page'] !== 'vmwpmdp-speaking-test-results' ) {
            return;
        }

        if ( ! isset( $_POST['bulk_nonce'] ) || ! wp_verify_nonce( $_POST['bulk_nonce'], 'vmwpmdp_bulk_delete' ) ) {
            return;
        }

        $action = isset( $_POST['action'] ) ? $_POST['action'] : '';
        if ( $action === '-1' ) {
            $action = isset( $_POST['action2'] ) ? $_POST['action2'] : '';
        }

        if ( $action === 'bulk-delete' && isset( $_POST['bulk-delete'] ) ) {
            $ids = (array) $_POST['bulk-delete'];
            foreach ( $ids as $id ) {
                $session_id = get_post_meta( $id, 'vmwpmdp_exam_session_id', true );
                if ( $session_id ) {
                    // Delete all records in this session
                    $args = [
                        'post_type'  => 'qcvoicemsg_record',
                        'meta_query' => [
                            [
                                'key'   => 'vmwpmdp_exam_session_id',
                                'value' => $session_id,
                            ]
                        ],
                        'fields'     => 'ids',
                        'posts_per_page' => -1,
                    ];
                    $session_posts = get_posts( $args );
                    foreach ( $session_posts as $p_id ) {
                        wp_delete_post( $p_id, true );
                    }
                } else {
                    // Legacy record, just delete this one
                    wp_delete_post( $id, true );
                }
            }
            
            wp_safe_redirect( admin_url( 'edit.php?post_type=wp_voicemsg_record&page=vmwpmdp-speaking-test-results&deleted=1' ) );
            exit;
        }

        if ( isset( $_GET['deleted'] ) ) {
            add_action( 'admin_notices', function() {
                echo '<div class="updated notice is-dismissible"><p>' . esc_html__( 'Selected exams deleted.', 'voice-widgets' ) . '</p></div>';
            });
        }
    }

	public function add_results_menu() {
		add_submenu_page(
			'edit.php?post_type=wp_voicemsg_record',
			esc_html__( 'Speaking Test Result', 'voice-widgets' ),
			esc_html__( 'Speaking Test Result', 'voice-widgets' ),
			'manage_options',
			'vmwpmdp-speaking-test-results',
			[ $this, 'render_results_page' ]
		);
	}

	public function render_results_page() {
        if ( isset( $_GET['record_id'] ) ) {
            $this->render_detail_view( intval( $_GET['record_id'] ) );
            return;
        }

        $this->handle_bulk_actions();

		$results_list_table = new WPVoice_Speaking_Test_Results_List();
		$results_list_table->prepare_items();
		?>
		<div class="wrap">
			<h1 class="wp-heading-inline"><?php esc_html_e( 'Speaking Test Results', 'voice-widgets' ); ?></h1>
            <p><?php esc_html_e( 'You can show speaking test each student result front view by shortcode: [qcld_stt_learning_mode_results]', 'voice-widgets' ); ?> </p>
			<hr class="wp-header-end">
			
			<div id="vmwpmdp-speaking-test-results-container">
                <div class="vmwpmdp-filter-bar" style="background: #fff; padding: 15px; border: 1px solid #ccd0d4; margin-bottom: 20px;">
                    <form method="get" style="display: flex; flex-wrap: wrap; gap: 15px; align-items: flex-end;">
                        <input type="hidden" name="post_type" value="qcvoicemsg_record" />
                        <input type="hidden" name="page" value="vmwpmdp-speaking-test-results" />
                        
                        <div>
                            <label style="display:block; font-weight:bold;"><?php esc_html_e( 'Search', 'voice-widgets' ); ?></label>
                            <input type="text" name="s" value="<?php echo isset($_REQUEST['s']) ? esc_attr($_REQUEST['s']) : ''; ?>" placeholder="<?php esc_attr_e( 'Username, Email...', 'voice-widgets' ); ?>" style="width: 200px;">
                        </div>

                        <div>
                            <label style="display:block; font-weight:bold;"><?php esc_html_e( 'Test Name', 'voice-widgets' ); ?></label>
                            <select name="filter_test_id" style="width: 200px;">
                                <option value=""><?php esc_html_e( 'All Tests', 'voice-widgets' ); ?></option>
                                <?php 
                                $tests = get_posts([
                                    'post_type' => ['voicemssg_form_qcwp', 'voicemssg_test_qcwp'],
                                    'posts_per_page' => -1,
                                    'post_status' => 'publish',
                                    'orderby' => 'title',
                                    'order' => 'ASC'
                                ]);
                                foreach ($tests as $test) {
                                    printf('<option value="%d" %s>%s</option>', 
                                        $test->ID, 
                                        selected(isset($_REQUEST['filter_test_id']) ? $_REQUEST['filter_test_id'] : '', $test->ID, false),
                                        get_the_title($test->ID)
                                    );
                                }
                                ?>
                            </select>
                        </div>

                        <div>
                            <label style="display:block; font-weight:bold;"><?php esc_html_e( 'From Date', 'voice-widgets' ); ?></label>
                            <input type="date" name="filter_date_from" value="<?php echo isset($_REQUEST['filter_date_from']) ? esc_attr($_REQUEST['filter_date_from']) : ''; ?>">
                        </div>

                        <div>
                            <label style="display:block; font-weight:bold;"><?php esc_html_e( 'To Date', 'voice-widgets' ); ?></label>
                            <input type="date" name="filter_date_to" value="<?php echo isset($_REQUEST['filter_date_to']) ? esc_attr($_REQUEST['filter_date_to']) : ''; ?>">
                        </div>

                        <div>
                            <label style="display:block; font-weight:bold;"><?php esc_html_e( 'Score Range', 'voice-widgets' ); ?></label>
                            <input type="number" name="filter_score_min" value="<?php echo isset($_REQUEST['filter_score_min']) ? esc_attr($_REQUEST['filter_score_min']) : ''; ?>" placeholder="Min" style="width: 60px;">
                            <input type="number" name="filter_score_max" value="<?php echo isset($_REQUEST['filter_score_max']) ? esc_attr($_REQUEST['filter_score_max']) : ''; ?>" placeholder="Max" style="width: 60px;">
                        </div>

                        <div>
                            <button type="submit" class="button button-primary"><?php esc_html_e( 'Apply Filters', 'voice-widgets' ); ?></button>
                            <a href="<?php echo admin_url('edit.php?post_type=wp_voicemsg_record&page=vmwpmdp-speaking-test-results'); ?>" class="button"><?php esc_html_e( 'Reset', 'voice-widgets' ); ?></a>
                        </div>
                    </form>
                </div>

                <form method="post">
                    <input type="hidden" name="page" value="vmwpmdp-speaking-test-results" />
                    <?php wp_nonce_field('vmwpmdp_bulk_delete', 'bulk_nonce'); ?>
                    
                    <?php 
                    $results_list_table->display(); 
                    ?>
                </form>
			</div>
		</div>
		<?php
	}

    public function render_detail_view( $record_id ) {
        $post = get_post( $record_id );
        if ( ! $post || $post->post_type !== 'qcvoicemsg_record' ) {
            wp_die( esc_html__( 'Invalid record ID.', 'voice-widgets' ) );
        }

        $test_id = get_post_meta( $record_id, 'vmwpmdp_cform_id', true );
        $session_id = get_post_meta( $record_id, 'vmwpmdp_exam_session_id', true );
        $student_meta = get_post_meta( $record_id, 'vmwpmdp_additional_fields', true );
        $author_id = $post->post_author;

        // Grouping logic: find all records for this session
        $args = [
            'post_type'      => 'qcvoicemsg_record',
            'posts_per_page' => -1,
            'orderby'        => 'ID',
            'order'          => 'ASC',
        ];

        if ( $session_id ) {
            $args['meta_query'] = [
                [
                    'key'     => 'vmwpmdp_exam_session_id',
                    'value'   => $session_id,
                    'compare' => '=',
                ],
            ];
        } else {
            // Fallback to student + test if no session id (legacy)
            $args['meta_query'] = [
                [
                    'key'     => 'vmwpmdp_cform_id',
                    'value'   => $test_id,
                    'compare' => '=',
                ],
            ];
            if ( $author_id > 0 ) $args['author'] = $author_id;
        }

        $all_records = get_posts( $args );
        
        // Final filter for guest meta if no session ID
        if ( ! $session_id && $author_id == 0 ) {
            $current_meta = json_decode( $student_meta, true );
            $all_records = array_filter( $all_records, function( $r ) use ( $current_meta ) {
                $r_meta = json_decode( get_post_meta( $r->ID, 'vmwpmdp_additional_fields', true ), true );
                return $r_meta === $current_meta;
            } );
        }

        $total_score = 0;
        foreach ($all_records as $record) {
            $total_score += (int) get_post_meta($record->ID, 'vmwpmdp_test_score', true);
        }
        $max_possible = count($all_records) * 100;

        ?>
        <div class="wrap">
            <h1><?php esc_html_e( 'Speaking Test Exam Details', 'voice-widgets' ); ?></h1>
            <div style="display:flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
                <a href="<?php echo admin_url('admin.php?page=vmwpmdp-speaking-test-results'); ?>" class="button">&laquo; <?php esc_html_e( 'Back to Results', 'voice-widgets' ); ?></a>
                <div id="vmwpmdp-total-score-display" data-max="<?php echo $max_possible; ?>" style="background: #e7f3ff; padding: 10px 20px; border-radius: 5px; border: 1px solid #0073aa; font-weight: bold; color: #0073aa;">
                    <?php printf( esc_html__('Total Manual Score: %d / %d', 'voice-widgets'), $total_score, $max_possible ); ?>
                </div>
            </div>
            <hr>

            <div class="vmwpmdp-detail-header" style="background: #fff; padding: 20px; border: 1px solid #ccd0d4; margin-bottom: 20px; display: grid; grid-template-columns: 1fr 1fr; gap: 30px;">
                <div>
                    <h3 style="margin-top: 0;"><?php esc_html_e( 'Student Information', 'voice-widgets' ); ?></h3>
                    <?php echo (new WPVoice_Speaking_Test_Results_List())->format_student_info( $student_meta, $author_id ); ?>
                </div>
                <div>
                   <p><strong><?php esc_html_e( 'Test Name:', 'voice-widgets' ); ?></strong> <?php echo get_the_title( $test_id ); ?></p>
                    <?php if ($session_id): ?>
                        <p><strong><?php esc_html_e( 'Session ID:', 'voice-widgets' ); ?></strong> <code><?php echo esc_html($session_id); ?></code></p>
                    <?php endif; ?>
                </div>
            </div>

            <div class="vmwpmdp-session-results">
                <?php foreach ( $all_records as $record ) : 
                    $r_id = $record->ID;
                    $score = get_post_meta( $r_id, 'vmwpmdp_test_score', true );
                    $label = get_post_meta( $r_id, 'vmwpmdp_test_level_label', true );
                    $trans = get_post_meta( $r_id, 'vmwpmdp_transcription_txt', true );
                    $eval  = get_post_meta( $r_id, 'vmwpmdp_test_evaluation', true );
                    $audio_path = get_post_meta( $r_id, 'qcld_wpvm_vmwpmdp_voicemssg_audio', true );
                    $audio_url = '';
                    if ( $audio_path ) {
                        $audio_url = str_replace( wp_normalize_path(untrailingslashit(ABSPATH)), site_url(), wp_normalize_path($audio_path) );
                    }

                    $levels = get_post_meta( $test_id, 'vmwpmdp_test_levels', true );
                    $level_index = get_post_meta( $r_id, 'vmwpmdp_test_level_index', true );
                    $target = ( is_array( $levels ) && isset( $levels[ $level_index ] ) ) ? $levels[ $level_index ]['text'] : '';
                ?>
                <div class="vmwpmdp-record-item" style="background: #fff; border: 1px solid #ccd0d4; padding: 20px; margin-bottom: 30px;">
                    <div style="display: flex; justify-content: space-between; align-items: flex-start; border-bottom: 1px solid #eee; padding-bottom: 10px; margin-bottom: 15px;">
                        <h4 style="margin: 0;"><?php echo esc_html( $label ); ?></h4>
                        <div>
                            <span style="font-size: 0.9em; color: #666;"><?php echo get_date_from_gmt( $record->post_date, 'Y-m-d H:i:s' ); ?></span>
                        </div>
                    </div>

                    <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
                        <div>
                            <p><strong><?php esc_html_e( 'Target Sentence:', 'voice-widgets' ); ?></strong></p>
                            <p style="padding: 10px; background: #f0f6fb; border-left: 3px solid #0073aa;"><?php echo esc_html( $target ); ?></p>

                            <p><strong><?php esc_html_e( 'Audio Recording:', 'voice-widgets' ); ?></strong></p>
                            <?php if ( $audio_url ) : ?>
                                <audio controls style="width: 100%;"><source src="<?php echo esc_url( $audio_url ); ?>" type="audio/wav"></audio>
                            <?php else : ?>
                                <p><em><?php esc_html_e( 'No recording.', 'voice-widgets' ); ?></em></p>
                            <?php endif; ?>
                        </div>
                        <div>
                            <p><strong><?php esc_html_e( 'AI Transcription:', 'voice-widgets' ); ?></strong></p>
                            <p style="padding: 10px; border: 1px dashed #ccc; font-style: italic;"><?php echo esc_html( $trans ); ?></p>
                            <p><strong><?php esc_html_e( 'AI Evaluation:', 'voice-widgets' ); ?></strong> 
                                <span style="color: <?php echo ($eval === 'pass' ? 'green' : 'red'); ?>; font-weight: bold;"><?php echo strtoupper($eval); ?></span>
                            </p>
                        </div>
                    </div>

                    <div style="margin-top: 20px; padding: 15px; background: #f9f9f9; border-radius: 4px; display: flex; align-items: center;">
                        <label style="font-weight: bold; margin-right: 15px;"><?php esc_html_e( 'Manual Score:', 'voice-widgets' ); ?></label>
                        <input type="number" class="vmwpmdp-score-input" value="<?php echo esc_attr( $score ); ?>" min="0" max="100" style="width: 70px;">
                        <span style="margin: 0 10px;">/ 100</span>
                        <button type="button" class="button button-secondary vmwpmdp-save-single-score" data-record-id="<?php echo $r_id; ?>"><?php esc_html_e( 'Save Score', 'voice-widgets' ); ?></button>
                        <span class="vmwpmdp-save-msg" style="margin-left: 15px; font-weight: bold;"></span>
                    </div>
                </div>
                <?php endforeach; ?>
            </div>
        </div>

        <script type="text/javascript">
            jQuery(document).ready(function($) {
                $('.vmwpmdp-save-single-score').on('click', function() {
                    var $btn = $(this);
                    var recordId = $btn.data('record-id');
                    var score = $btn.siblings('.vmwpmdp-score-input').val();
                    var $msg = $btn.siblings('.vmwpmdp-save-msg');

                    $btn.prop('disabled', true);
                    $msg.text('...').css('color', '#666');

                    $.post(ajaxurl, {
                        action: 'vmwpmdp_manual_mark_test',
                        record_id: recordId,
                        score: score,
                        _ajax_nonce: '<?php echo wp_create_nonce( "qcld_stt_test_nonce" ); ?>'
                    }, function(response) {
                        $btn.prop('disabled', false);
                        if (response.success) {
                            $msg.text('Saved!').css('color', 'green').fadeOut(2000, function(){ $(this).text('').show(); });
                            
                            // Update total score display
                            if (response.data && typeof response.data.total_score !== 'undefined') {
                                var $totalDisp = $('#vmwpmdp-total-score-display');
                                var max = $totalDisp.data('max');
                                var langText = '<?php echo esc_js( __('Total Manual Score:', 'voice-widgets') ); ?>';
                                $totalDisp.text(langText + ' ' + response.data.total_score + ' / ' + max);
                            }
                        } else {
                            $msg.text('Error').css('color', 'red');
                        }
                    });
                });
            });
        </script>
        <?php
    }

}

/**
 * Custom List Table class for Speaking Test Results.
 */
class WPVoice_Speaking_Test_Results_List extends WP_List_Table {

	public function __construct() {
		parent::__construct( [
			'singular' => 'test_result',
			'plural'   => 'test_results',
			'ajax'     => false,
		] );
	}

	public function get_columns() {
		return [
			'cb'            => '<input type="checkbox" />',
			'date'          => esc_html__( 'Date', 'voice-widgets' ),
			'student_info'  => esc_html__( 'Student Detail', 'voice-widgets' ),
			'test_title'    => esc_html__( 'Test Name', 'voice-widgets' ),
            'total_score'   => esc_html__( 'Total Score', 'voice-widgets' ),
            'exam_summary'  => esc_html__( 'Exam Progress', 'voice-widgets' ),
			'actions'       => esc_html__( 'Actions', 'voice-widgets' ),
		];
	}

    public function get_sortable_columns() {
        return [ 
            'date' => [ 'post_date', true ],
            'total_score' => [ 'total_score', false ]
        ];
    }

    public function get_bulk_actions() {
        return [ 'bulk-delete' => esc_html__( 'Delete', 'voice-widgets' ) ];
    }

	public function prepare_items() {
		$per_page = 20;
		$columns  = $this->get_columns();
		$hidden   = [];
		$sortable = $this->get_sortable_columns();
		$this->_column_headers = [ $columns, $hidden, $sortable ];

		$current_page = $this->get_pagenum();
		
        // Fetch base posts
        $args = [
            'post_type'      => 'qcvoicemsg_record',
            'post_status'    => 'any',
            'posts_per_page' => -1, 
            'orderby'        => 'post_date',
            'order'          => 'DESC',
            'meta_query'     => [
                'relation' => 'AND',
                [ 'key' => 'vmwpmdp_cform_id', 'compare' => 'EXISTS' ]
            ],
        ];

        // Filter by Test ID
        if ( ! empty( $_REQUEST['filter_test_id'] ) ) {
            $args['meta_query'][] = [
                'key'   => 'vmwpmdp_cform_id',
                'value' => intval( $_REQUEST['filter_test_id'] ),
            ];
        }

        // Date Range Filtering (Initial fetch)
        if ( ! empty( $_REQUEST['filter_date_from'] ) || ! empty( $_REQUEST['filter_date_to'] ) ) {
            $date_query = [];
            if ( ! empty( $_REQUEST['filter_date_from'] ) ) {
                $date_query['after'] = $_REQUEST['filter_date_from'];
                $date_query['inclusive'] = true;
            }
            if ( ! empty( $_REQUEST['filter_date_to'] ) ) {
                $date_query['before'] = $_REQUEST['filter_date_to'];
                $date_query['inclusive'] = true;
            }
            $args['date_query'] = [ $date_query ];
        }

        $all_posts = get_posts( $args );
        $sessions = [];

        $search_query = ! empty( $_REQUEST['s'] ) ? strtolower( sanitize_text_field( $_REQUEST['s'] ) ) : '';

        foreach ( $all_posts as $post ) {
            $session_id = get_post_meta( $post->ID, 'vmwpmdp_exam_session_id', true );
            $test_id    = get_post_meta( $post->ID, 'vmwpmdp_cform_id', true );
            $student    = get_post_meta( $post->ID, 'vmwpmdp_additional_fields', true );
            $score      = get_post_meta( $post->ID, 'vmwpmdp_test_score', true );
            $author_id  = $post->post_author;

            // Search filter
            if ( $search_query ) {
                $match = false;
                if ( strpos( strtolower( $post->post_title ), $search_query ) !== false ) $match = true;
                if ( strpos( strtolower( $session_id ), $search_query ) !== false ) $match = true;
                if ( strpos( strtolower( $student ), $search_query ) !== false ) $match = true;
                
                if ( ! $match && $author_id > 0 ) {
                    $user = get_userdata( $author_id );
                    if ( $user ) {
                        $full_name = strtolower( trim( $user->user_firstname . ' ' . $user->user_lastname ) );
                        if ( strpos( strtolower( $user->display_name ), $search_query ) !== false || 
                             strpos( strtolower( $user->user_email ), $search_query ) !== false ||
                             ( ! empty( $full_name ) && strpos( $full_name, $search_query ) !== false )
                        ) {
                            $match = true;
                        }
                    }
                }

                if ( ! $match ) continue;
            }

            // Grouping key: Session ID or composite for legacy
            $key = $session_id ? $session_id : 'legacy_' . $test_id . '_' . $author_id . '_' . substr($student, 0, 50);

            if ( ! isset( $sessions[$key] ) ) {
                $sessions[$key] = [
                    'ID'            => $post->ID,
                    'date'          => $post->post_date,
                    'student_info'  => $this->format_student_info( $student, $author_id ),
                    'test_id'       => $test_id,
                    'test_title'    => $test_id ? get_the_title( $test_id ) : esc_html__( 'Unknown Test', 'voice-widgets' ),
                    'count'         => 0,
                    'total_levels'  => 0,
                    'total_score'   => 0,
                ];
                if ($test_id) {
                    $levels = get_post_meta($test_id, 'vmwpmdp_test_levels', true);
                    $sessions[$key]['total_levels'] = is_array($levels) ? count($levels) : 0;
                }
            }
            $sessions[$key]['count']++;
            $sessions[$key]['total_score'] += (int) $score;
        }

        // Score Range Filtering (Post-grouping)
        if ( isset( $_REQUEST['filter_score_min'] ) && $_REQUEST['filter_score_min'] !== '' ) {
            $min = intval( $_REQUEST['filter_score_min'] );
            $sessions = array_filter( $sessions, function( $s ) use ( $min ) {
                return $s['total_score'] >= $min;
            });
        }
        if ( isset( $_REQUEST['filter_score_max'] ) && $_REQUEST['filter_score_max'] !== '' ) {
            $max = intval( $_REQUEST['filter_score_max'] );
            $sessions = array_filter( $sessions, function( $s ) use ( $max ) {
                return $s['total_score'] <= $max;
            });
        }

        // Sort by total score if requested
        if ( isset( $_REQUEST['orderby'] ) && $_REQUEST['orderby'] === 'total_score' ) {
            $order = ( isset( $_REQUEST['order'] ) && $_REQUEST['order'] === 'asc' ) ? 1 : -1;
            uasort( $sessions, function( $a, $b ) use ( $order ) {
                if ( $a['total_score'] == $b['total_score'] ) return 0;
                return ( $a['total_score'] < $b['total_score'] ) ? -$order : $order;
            });
        }

        // Pagination
        $total_items = count($sessions);
        $sessions = array_slice($sessions, ($current_page - 1) * $per_page, $per_page);

		$this->items = $sessions;
		$this->set_pagination_args( [
			'total_items' => $total_items,
			'per_page'    => $per_page,
			'total_pages' => ceil( $total_items / $per_page ),
		] );
	}

    public function format_student_info( $meta_json, $author_id = 0 ) {
        if ( $author_id > 0 ) {
            $user = get_userdata( $author_id );
            if ( $user ) {
                $full_name = trim( $user->user_firstname . ' ' . $user->user_lastname );
                $display = ! empty( $full_name ) ? $full_name : $user->display_name;
                
                return sprintf( '<strong>%s:</strong> %s<br><strong>%s:</strong> %s',
                    esc_html__( 'User', 'voice-widgets' ), esc_html( $display ), 
                    esc_html__( 'Email', 'voice-widgets' ), esc_html( $user->user_email ) );
            }
        }
        if ( empty( $meta_json ) ) return esc_html__( 'Guest', 'voice-widgets' );
        $fields = json_decode( $meta_json, true );
        if ( ! is_array( $fields ) ) return esc_html__( 'Guest', 'voice-widgets' );
        $output = '';
        foreach ( $fields as $field ) {
            if ( isset( $field['label'] ) && isset( $field['value'] ) ) {
                $val = is_array( $field['value'] ) ? implode( ', ', $field['value'] ) : $field['value'];
                $output .= '<strong>' . esc_html( $field['label'] ) . ':</strong> ' . esc_html( $val ) . '<br>';
            }
        }
        return $output ? $output : esc_html__( 'Guest', 'voice-widgets' );
    }

	public function column_default( $item, $column_name ) {
		switch ( $column_name ) {
			case 'date': return get_date_from_gmt( $item['date'], 'Y-m-d H:i:s' );
			case 'student_info': return $item['student_info'];
			case 'test_title': 
                if ( ! empty( $item['test_id'] ) ) {
                    return sprintf( '<a href="%s" target="_blank">%s</a>', 
                        get_edit_post_link( $item['test_id'] ),
                        esc_html( $item['test_title'] )
                    );
                }
                return esc_html( $item['test_title'] );
            case 'total_score': 
                return sprintf( '<strong>%d</strong> / %d', $item['total_score'], $item['total_levels'] * 100 );
            case 'exam_summary': 
                $txt = sprintf( esc_html__( '%d sentence(s) recorded', 'voice-widgets' ), $item['count'] );
                if ( $item['total_levels'] > 0 ) {
                    $txt .= ' / ' . $item['total_levels'];
                }
                return $txt;
            case 'actions': return sprintf( '<a href="%s" class="button button-small">%s</a>',
                    admin_url( 'admin.php?page=vmwpmdp-speaking-test-results&record_id=' . $item['ID'] ),
                    esc_html__( 'View Full Exam', 'voice-widgets' ) );
			default: return '';
		}
	}

	public function column_cb( $item ) {
		return sprintf( '<input type="checkbox" name="bulk-delete[]" value="%s" />', $item['ID'] );
	}
}
