<?php
/**
 * Points log admin page
 */
if ( ! defined( 'ABSPATH' ) ) exit;

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

class SPAR_Points_Log_Table extends WP_List_Table {
    public function __construct() {
        parent::__construct( [
            'singular' => 'log',
            'plural'   => 'logs',
            'ajax'     => false
        ] );
    }

    public function get_columns() {
        return [
            'cb'     => '<input type="checkbox" />',
            'user'   => esc_html__( 'User', 'simple-points-and-rewards' ),
            'action' => esc_html__( 'Action', 'simple-points-and-rewards' ),
            'type'   => esc_html__( 'Type', 'simple-points-and-rewards' ),
            'points' => esc_html__( 'Points', 'simple-points-and-rewards' ),
            'date'   => esc_html__( 'Date', 'simple-points-and-rewards' )
        ];
    }

    public function get_sortable_columns() {
        return [
            'user'   => [ 'user', false ],
            'type'   => [ 'type', false ],
            'points' => [ 'points', false ],
            'date'   => [ 'date', true ]
        ];
    }

    public function get_bulk_actions() {
        return [
            'undo_update' => esc_html__( 'Undo + Update Log', 'simple-points-and-rewards' ),
            'undo_delete' => esc_html__( 'Undo + Delete', 'simple-points-and-rewards' ),
            'delete'      => esc_html__( 'Delete', 'simple-points-and-rewards' ),
        ];
    }

    public function column_cb( $item ) {
        // Check if this is an undo log
        $is_undo_log = ( isset( $item['action_id'] ) && 'admin_undo' === $item['action_id'] ) || ( strpos( $item['action'], 'Undo:' ) === 0 );
        $is_undone   = ( isset( $item['action_id'] ) && 'undone' === $item['action_id'] );
        
        $class = ( $is_undo_log || $is_undone ) ? 'spar-undone-cb' : '';

        return sprintf(
            '<input type="checkbox" name="log_ids[]" value="%s" class="%s" />',
            esc_attr( $item['id'] ),
            esc_attr( $class )
        );
    }

    public function process_bulk_action() {
        if ( $this->current_action() ) {
            check_admin_referer( 'bulk-' . $this->_args['plural'] );
            
            if ( ! current_user_can( 'manage_woocommerce' ) ) {
                return;
            }

            $log_ids = isset( $_POST['log_ids'] ) ? array_map( 'absint', (array) $_POST['log_ids'] ) : [];
            if ( empty( $log_ids ) ) {
                return;
            }

            global $wpdb;
            $table = $wpdb->prefix . 'spar_points_logs';
            
            foreach ( $log_ids as $log_id ) {
                $log = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM %i WHERE id = %d', $table, $log_id ), ARRAY_A );
                if ( ! $log ) {
                    continue;
                }

                $user_id = (int) $log['user_id'];
                $points  = absint( $log['points'] );
                $type    = $log['type'];
                $action  = $log['action'];
                $is_undone = ( isset( $log['action_id'] ) && 'undone' === $log['action_id'] );
                $is_undo_log = ( isset( $log['action_id'] ) && 'admin_undo' === $log['action_id'] ) || ( strpos( $log['action'], 'Undo:' ) === 0 );

                switch ( $this->current_action() ) {
                    case 'undo_update':
                        if ( $is_undone || $is_undo_log ) {
                            continue 2;
                        }
                        // Skip undo for guest entries — no user account to revert points for.
                        if ( 0 === $user_id ) {
                            continue 2;
                        }
                        // Revert points and log it
                        $reverse_action = ( 'add' === $type ) ? 'remove' : 'add';
                        $note = sprintf( __( 'Undo: %s', 'simple-points-and-rewards' ), $action );
                        spar_update_user_points( $user_id, $points, $reverse_action, $note, 'admin_undo' );
                        
                        // Mark original log as undone
                        $wpdb->update( 
                            $table, 
                            [ 'action_id' => 'undone' ], 
                            [ 'id' => $log_id ], 
                            [ '%s' ], 
                            [ '%d' ] 
                        );
                        break;

                    case 'undo_delete':
                        // Skip point-revert for guest entries — no user account to adjust.
                        if ( 0 === $user_id ) {
                            $wpdb->delete( $table, [ 'id' => $log_id ], [ '%d' ] );
                            break;
                        }
                        if ( ! $is_undone && ! $is_undo_log ) {
                            // Revert points manually without logging
                            $current_points = spar_get_user_points( $user_id );
                            if ( 'add' === $type ) {
                                // Original was add, so we remove
                                $new_points = max( 0, $current_points - $points );
                                // Also decrement total earned
                                $total_earned = (int) get_user_meta( $user_id, '_spar_total_earned_points', true );
                                update_user_meta( $user_id, '_spar_total_earned_points', max( 0, $total_earned - $points ) );
                            } else {
                                // Original was remove, so we add
                                $new_points = $current_points + $points;
                            }
                            update_user_meta( $user_id, '_spar_points', $new_points );
                        }
                        
                        // Delete the log
                        $wpdb->delete( $table, [ 'id' => $log_id ], [ '%d' ] );
                        break;

                    case 'delete':
                        // Just delete the log
                        $wpdb->delete( $table, [ 'id' => $log_id ], [ '%d' ] );
                        break;
                }
            }
        }
    }

    public function prepare_items() {
        global $wpdb;

        $per_page = 20;
        $current_page = $this->get_pagenum();
        $offset = ( $current_page - 1 ) * $per_page;

        // Get sort parameters without direct superglobals
        $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
        $order   = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
        $orderby = $orderby ? $orderby : 'date';
        $order   = $order ? $order : 'DESC';

        // Validate orderby
        $allowed_orderby = [ 'user', 'type', 'points', 'date' ];
        if ( ! in_array( $orderby, $allowed_orderby ) ) {
            $orderby = 'date';
        }

        // Validate order
        $order = strtoupper( $order ) === 'ASC' ? 'ASC' : 'DESC';

        $table = $wpdb->prefix . 'spar_points_logs';

        // Build dynamic WHERE conditions & parameters (avoid concatenated prepared fragments for scanner compliance)
        $conditions = array();
        $params     = array();
        $nonce      = filter_input( INPUT_GET, 'spar_log_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
        $nonce_valid = $nonce ? wp_verify_nonce( $nonce, 'spar_log_filters' ) : false;

        if ( $nonce_valid ) {
            // Date range filters
            $date_from = filter_input( INPUT_GET, 'date_from', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
            if ( $date_from && strtotime( $date_from ) ) {
                $conditions[] = ' AND l.date >= %s';
                $params[]     = $date_from . ' 00:00:00';
            }
            $date_to = filter_input( INPUT_GET, 'date_to', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
            if ( $date_to && strtotime( $date_to ) ) {
                $conditions[] = ' AND l.date <= %s';
                $params[]     = $date_to . ' 23:59:59';
            }

            // Username filter (LIKE against 3 columns)
            $username = filter_input( INPUT_GET, 'username', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
            if ( $username ) {
                $search_term  = '%' . $wpdb->esc_like( $username ) . '%';
                $conditions[] = ' AND (u.display_name LIKE %s OR u.user_login LIKE %s OR u.user_email LIKE %s)';
                $params[]     = $search_term; $params[] = $search_term; $params[] = $search_term;
            }

            // Action text filter
            $action_filter = filter_input( INPUT_GET, 'action_filter', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
            if ( $action_filter ) {
                $conditions[] = ' AND l.action LIKE %s';
                $params[]     = '%' . $wpdb->esc_like( $action_filter ) . '%';
            }

            // Points range
            $min_points = filter_input( INPUT_GET, 'min_points', FILTER_SANITIZE_NUMBER_INT );
            if ( '' !== $min_points && is_numeric( $min_points ) ) {
                $conditions[] = ' AND ABS(l.points) >= %d';
                $params[]     = (int) $min_points;
            }
            $max_points = filter_input( INPUT_GET, 'max_points', FILTER_SANITIZE_NUMBER_INT );
            if ( '' !== $max_points && is_numeric( $max_points ) ) {
                $conditions[] = ' AND ABS(l.points) <= %d';
                $params[]     = (int) $max_points;
            }

            // Type filter (strict whitelist)
            $type_filter = filter_input( INPUT_GET, 'type_filter', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
            if ( in_array( $type_filter, array( 'add', 'remove' ), true ) ) {
                $conditions[] = ' AND l.type = %s';
                $params[]     = $type_filter;
            }
        }

        $where_dynamic = implode( '', $conditions );

        // Build COUNT query with dynamic parameters
        $count_sql = ' SELECT COUNT(*) FROM %i l LEFT JOIN ' . $wpdb->users . ' u ON l.user_id = u.ID WHERE 1=1' . $where_dynamic;
        $count_args = array_merge( array( $count_sql, $table ), $params );
        $count_sql_prepared = call_user_func_array( array( $wpdb, 'prepare' ), $count_args );
        $cache_group = 'spar';
        $count_key   = 'spar_log_count_' . md5( $count_sql_prepared );
        $total_items = wp_cache_get( $count_key, $cache_group );
        if ( false === $total_items ) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $total_items = (int) $wpdb->get_var( $count_sql_prepared );
            wp_cache_set( $count_key, $total_items, $cache_group, 60 );
        }

        // Build ORDER BY clause
        $order_clause = '';
        if ( $orderby === 'user' ) {
            $order_clause = "ORDER BY u.display_name $order";
        } else {
            $order_clause = "ORDER BY l.$orderby $order";
        }

        // Get data rows (build dynamic prepared statement)
        $data_sql  = ' SELECT l.*, u.display_name as user_name FROM %i l LEFT JOIN ' . $wpdb->users . ' u ON l.user_id = u.ID WHERE 1=1' . $where_dynamic . ' ' . $order_clause . ' LIMIT %d OFFSET %d';
        $data_args = array_merge( array( $data_sql, $table ), $params, array( $per_page, $offset ) );
        $data_sql_prepared = call_user_func_array( array( $wpdb, 'prepare' ), $data_args );
        $results_key = 'spar_log_results_' . md5( $data_sql_prepared );
        $results     = wp_cache_get( $results_key, $cache_group );
        if ( false === $results ) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $results = $wpdb->get_results( $data_sql_prepared, ARRAY_A );
            wp_cache_set( $results_key, $results, $cache_group, 60 );
        }

        $this->items = $results;

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

        $this->_column_headers = [ $this->get_columns(), [], $this->get_sortable_columns() ];
    }

    public function column_default( $item, $column_name ) {
        switch ( $column_name ) {
            case 'user':
                if ( empty( $item['user_id'] ) || 0 === (int) $item['user_id'] ) {
                    // Guest entry — try to get the email from the linked order.
                    $guest_email = '';
                    $action_text = isset( $item['action'] ) ? $item['action'] : '';
                    if ( preg_match( '/#(\d+)/', $action_text, $m ) ) {
                        $log_order = wc_get_order( (int) $m[1] );
                        if ( $log_order ) {
                            $guest_email = $log_order->get_billing_email();
                        }
                    }
                    if ( $guest_email ) {
                        return esc_html__( 'Guest', 'simple-points-and-rewards' ) . ' (' . esc_html( $guest_email ) . ')';
                    }
                    return esc_html__( 'Guest', 'simple-points-and-rewards' );
                }
                return esc_html( $item['user_name'] ?: esc_html__( 'Unknown user', 'simple-points-and-rewards' ) );

            case 'action':
                $action = isset( $item['action'] ) ? $item['action'] : '';

                // Prepend "Prize Wheel:" prefix for spin wheel log entries
                if ( isset( $item['action_id'] ) && 'spin_wheel' === $item['action_id'] ) {
                    $action = esc_html__( 'Prize Wheel', 'simple-points-and-rewards' ) . ': ' . $action;
                }

                // If "Points Earned for Order" get the order ID after and link it
                // Handle both formats: "Points Earned for Order: #123" and "Points Earned for Order #123"
                if ( preg_match( '/Points Earned for Order[:\s]+#?(\d+)/', $action, $order_match ) ) {
                    $order_id_num = (int) $order_match[1];
                    $order = wc_get_order( $order_id_num );
                    if ( $order ) {
                        $order_edit_url = $order->get_edit_order_url();
                        $order_link = '<a href="' . esc_url( $order_edit_url ) . '">#' . esc_html( $order_id_num ) . '</a>';
                        $action = preg_replace( '/#?' . $order_id_num . '/', $order_link, $action, 1 );
                    }
                }

                // If "Claimed Voucher:" get the coupon after and link it
                if ( strpos( $action, 'Claimed Voucher:' ) !== false ) {
                    $parts = explode( 'Claimed Voucher:', $action );
                    if ( isset( $parts[1] ) ) {
                        $coupon_code = trim( $parts[1] );
                        $coupon_id = function_exists( 'wc_get_coupon_id_by_code' ) ? wc_get_coupon_id_by_code( $coupon_code ) : 0;
                        if ( $coupon_id ) {
                            $action = str_replace(
                                $coupon_code,
                                '<a href="' . esc_url( admin_url( 'post.php?post=' . absint( $coupon_id ) . '&action=edit' ) ) . '">' . esc_html( $coupon_code ) . '</a>',
                                $action
                            );
                        }
                    }
                }

                // If "Claimed Free Product Voucher:" get the product ID after and link it
                if ( strpos( $action, 'Claimed Free Product Voucher:' ) !== false ) {
                    $parts = explode( 'Claimed Free Product Voucher:', $action );
                    if ( isset( $parts[1] ) ) {
                        $product_id = trim( $parts[1] );
                        $product_id_trim = ltrim( $product_id, '#' );
                        $product = wc_get_product( $product_id_trim );
                        if ( $product ) {
                            $action = str_replace(
                                $product_id,
                                '<a href="' . esc_url( admin_url( 'post.php?post=' . $product->get_id() . '&action=edit' ) ) . '">' . esc_html( $product_id ) . '</a>',
                                $action
                            );
                        }
                    }
                }

                // If "Referral Bonus:" get the order ID and link it
                if ( strpos( $action, 'Referral Bonus:' ) !== false ) {
                    if ( preg_match( '/\\(Order #(\\d+)\\)/', $action, $matches ) ) {
                        $order_id = (int) $matches[1];
                        $order = wc_get_order( $order_id );
                        if ( $order ) {
                            $order_edit_url = $order->get_edit_order_url();
                            $action = str_replace(
                                '(Order #' . $order_id . ')',
                                '(<a href="' . esc_url( $order_edit_url ) . '">Order #' . $order_id . '</a>)',
                                $action
                            );

                            // Add referral stats context
                            $referrer_code = $order->get_meta( 'referrer_code' );
                            if ( $referrer_code ) {
                                $referrer_id = spar_get_user_by_referral_code( $referrer_code );
                                if ( $referrer_id ) {
                                    $referrer_stats = spar_get_user_referral_stats( $referrer_id );
                                    $clicks   = isset( $referrer_stats['total_clicks'] ) ? (int) $referrer_stats['total_clicks'] : 0;
                                    $refers   = isset( $referrer_stats['successful_referrals'] ) ? (int) $referrer_stats['successful_referrals'] : 0;
                                    $action  .= '<br><small>'
                                        . esc_html__( 'Referrer:', 'simple-points-and-rewards' ) . ' '
                                        . esc_html( $referrer_code ) . ' ('
                                        . esc_html__( 'Clicks:', 'simple-points-and-rewards' ) . ' ' . number_format_i18n( $clicks ) . ', '
                                        . esc_html__( 'Referrals:', 'simple-points-and-rewards' ) . ' ' . number_format_i18n( $refers )
                                        . ')</small>';
                                }
                            }
                        }
                    }
                }

                // If action contains referral coupon codes, link them
                if ( preg_match( '/ref-[A-Z0-9]+-\d+/', $action, $matches ) ) {
                    $coupon_code = $matches[0];
                    $coupon_id = function_exists( 'wc_get_coupon_id_by_code' ) ? wc_get_coupon_id_by_code( $coupon_code ) : 0;
                    if ( $coupon_id ) {
                        $action = str_replace(
                            $coupon_code,
                            '<a href="' . esc_url( admin_url( 'post.php?post=' . absint( $coupon_id ) . '&action=edit' ) ) . '">' . esc_html( $coupon_code ) . '</a>',
                            $action
                        );
                    }
                }

                return wp_kses_post( $action );

            case 'type':
                return ucfirst( esc_html( $item['type'] ) );

            case 'points':
                $points = (int) $item['points'];
                if ( $item['type'] === 'add' ) {
                    $points = '+' . $points;
                    $class = 'spar-positive';
                } else {
                    $points = '-' . absint( $points );
                    $class = 'spar-negative';
                }
                return '<span class="' . esc_attr( $class ) . '">' . esc_html( $points ) . '</span>';

            case 'date':
                // Use site formats and WordPress time i18n
                $ts = strtotime( $item['date'] );
                return $ts ? date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $ts ) : '';

            default:
                return '';
        }
    }

    public function no_items() {
        esc_html_e( 'No points log entries found.', 'simple-points-and-rewards' );
    }
}

function spar_points_log_page() {
    $log_table = new SPAR_Points_Log_Table();
    $log_table->process_bulk_action();
    $log_table->prepare_items();    ?>
    <div class="wrap">
    <?php spar_render_admin_header( esc_html__( 'Activity Log', 'simple-points-and-rewards' ) ); ?>

        <p><?php esc_html_e( 'This page shows the history of points earned and redeemed by users.', 'simple-points-and-rewards' ); ?></p>

        <!-- Filter Form -->
        <div class="spar-log-filters" style="background: #fff; border: 1px solid #ccd0d4; padding: 15px; margin: 20px 0; border-radius: 4px;">
            <h3 style="margin-top: 0;"><?php esc_html_e( 'Filter Logs', 'simple-points-and-rewards' ); ?></h3>
            <form method="get" id="spar-log-filter-form">
                <?php
                // Collect sanitized inputs using filter_input to avoid direct superglobals and gate by nonce
                $spar_nonce           = filter_input( INPUT_GET, 'spar_log_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
                $spar_nonce_valid     = $spar_nonce ? wp_verify_nonce( $spar_nonce, 'spar_log_filters' ) : false;
                $spar_page_param      = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
                $spar_date_from       = $spar_nonce_valid ? filter_input( INPUT_GET, 'date_from', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) : '';
                $spar_date_to         = $spar_nonce_valid ? filter_input( INPUT_GET, 'date_to', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) : '';
                $spar_username        = $spar_nonce_valid ? filter_input( INPUT_GET, 'username', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) : '';
                $spar_action_filter   = $spar_nonce_valid ? filter_input( INPUT_GET, 'action_filter', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) : '';
                $spar_min_points      = $spar_nonce_valid ? filter_input( INPUT_GET, 'min_points', FILTER_SANITIZE_NUMBER_INT ) : '';
                $spar_max_points      = $spar_nonce_valid ? filter_input( INPUT_GET, 'max_points', FILTER_SANITIZE_NUMBER_INT ) : '';
                $spar_type_filter_val = $spar_nonce_valid ? filter_input( INPUT_GET, 'type_filter', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) : '';
                ?>
                <input type="hidden" name="page" value="<?php echo esc_attr( $spar_page_param ); ?>" />
                <?php wp_nonce_field( 'spar_log_filters', 'spar_log_nonce' ); ?>

                <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-bottom: 15px;">
                    <!-- Date Range -->
                    <div>
                        <label for="date_from"><?php esc_html_e( 'Date From:', 'simple-points-and-rewards' ); ?></label>
                        <input type="date" id="date_from" name="date_from" value="<?php echo esc_attr( $spar_date_from ); ?>" style="width: 100%;" />
                    </div>

                    <div>
                        <label for="date_to"><?php esc_html_e( 'Date To:', 'simple-points-and-rewards' ); ?></label>
                        <input type="date" id="date_to" name="date_to" value="<?php echo esc_attr( $spar_date_to ); ?>" style="width: 100%;" />
                    </div>

                    <!-- Username -->
                    <div>
                        <label for="username"><?php esc_html_e( 'Username/Email:', 'simple-points-and-rewards' ); ?></label>
                        <input type="text" id="username" name="username" value="<?php echo esc_attr( $spar_username ); ?>" placeholder="<?php esc_attr_e( 'Search by name or email', 'simple-points-and-rewards' ); ?>" style="width: 100%;" />
                    </div>

                    <!-- Action -->
                    <div>
                        <label for="action_filter"><?php esc_html_e( 'Action Contains:', 'simple-points-and-rewards' ); ?></label>
                        <input type="text" id="action_filter" name="action_filter" value="<?php echo esc_attr( $spar_action_filter ); ?>" placeholder="<?php esc_attr_e( 'e.g. Order, Voucher, Signup', 'simple-points-and-rewards' ); ?>" style="width: 100%;" />
                    </div>

                    <!-- Points Range -->
                    <div>
                        <label for="min_points"><?php esc_html_e( 'Min Points:', 'simple-points-and-rewards' ); ?></label>
                        <input type="number" id="min_points" name="min_points" value="<?php echo esc_attr( $spar_min_points ); ?>" placeholder="0" min="0" style="width: 100%;" />
                    </div>

                    <div>
                        <label for="max_points"><?php esc_html_e( 'Max Points:', 'simple-points-and-rewards' ); ?></label>
                        <input type="number" id="max_points" name="max_points" value="<?php echo esc_attr( $spar_max_points ); ?>" placeholder="1000" min="0" style="width: 100%;" />
                    </div>

                    <!-- Type Filter -->
                    <div>
                        <label for="type_filter"><?php esc_html_e( 'Type:', 'simple-points-and-rewards' ); ?></label>
                        <select id="type_filter" name="type_filter" style="width: 100%;">
                            <option value=""><?php esc_html_e( 'All Types', 'simple-points-and-rewards' ); ?></option>
                            <option value="add" <?php selected( $spar_type_filter_val, 'add' ); ?>><?php esc_html_e( 'Points Added', 'simple-points-and-rewards' ); ?></option>
                            <option value="remove" <?php selected( $spar_type_filter_val, 'remove' ); ?>><?php esc_html_e( 'Points Removed', 'simple-points-and-rewards' ); ?></option>
                        </select>
                    </div>
                </div>

                <div style="display: flex; gap: 10px; align-items: center;">
                    <button type="submit" class="button button-primary"><?php esc_html_e( 'Apply Filters', 'simple-points-and-rewards' ); ?></button>
                    <a href="<?php echo esc_url( admin_url( 'admin.php?page=spar-log' ) ); ?>" class="button"><?php esc_html_e( 'Clear Filters', 'simple-points-and-rewards' ); ?></a>

                    <?php 
                    // Show active filter count
                    $active_filters  = 0;
                    $active_filters += ( '' !== $spar_date_from ) ? 1 : 0;
                    $active_filters += ( '' !== $spar_date_to ) ? 1 : 0;
                    $active_filters += ( '' !== $spar_username ) ? 1 : 0;
                    $active_filters += ( '' !== $spar_action_filter ) ? 1 : 0;
                    $active_filters += ( '' !== (string) $spar_min_points ) ? 1 : 0;
                    $active_filters += ( '' !== (string) $spar_max_points ) ? 1 : 0;
                    $active_filters += ( '' !== $spar_type_filter_val ) ? 1 : 0;
                    if ($active_filters > 0) {
                        /* translators: %d: number of active filters */
                        $filters_text = sprintf( esc_html__( '%d filter(s) active', 'simple-points-and-rewards' ), number_format_i18n( (int) $active_filters ) );
                        printf( '<span style="color: #135e96; font-weight: 600;">%s</span>', esc_html( $filters_text ) );
                    }
                    ?>
                </div>
            </form>
        </div>

        <form method="post">
            <?php 
            $spar_page_param2 = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
            $spar_nonce_val   = $spar_nonce ? $spar_nonce : wp_create_nonce( 'spar_log_filters' );
            ?>
            <input type="hidden" name="page" value="<?php echo esc_attr( $spar_page_param2 ); ?>" />
            <input type="hidden" name="spar_log_nonce" value="<?php echo esc_attr( $spar_nonce_val ); ?>" />

            <?php 
            // Pass through filter parameters to maintain them during table operations
            if ( '' !== $spar_date_from ) {
                echo '<input type="hidden" name="date_from" value="' . esc_attr( $spar_date_from ) . '" />';
            }
            if ( '' !== $spar_date_to ) {
                echo '<input type="hidden" name="date_to" value="' . esc_attr( $spar_date_to ) . '" />';
            }
            if ( '' !== $spar_username ) {
                echo '<input type="hidden" name="username" value="' . esc_attr( $spar_username ) . '" />';
            }
            if ( '' !== $spar_action_filter ) {
                echo '<input type="hidden" name="action_filter" value="' . esc_attr( $spar_action_filter ) . '" />';
            }
            if ( '' !== (string) $spar_min_points ) {
                echo '<input type="hidden" name="min_points" value="' . esc_attr( $spar_min_points ) . '" />';
            }
            if ( '' !== (string) $spar_max_points ) {
                echo '<input type="hidden" name="max_points" value="' . esc_attr( $spar_max_points ) . '" />';
            }
            if ( '' !== $spar_type_filter_val ) {
                echo '<input type="hidden" name="type_filter" value="' . esc_attr( $spar_type_filter_val ) . '" />';
            }
            ?>

            <?php $log_table->display(); ?>
        </form>
    </div>
    <script type="text/javascript">
    jQuery(document).ready(function($) {
        function toggleUndoneCheckboxes() {
            var actionTop = $('#bulk-action-selector-top').val();
            var actionBottom = $('#bulk-action-selector-bottom').val();
            var isDelete = (actionTop === 'delete' || actionBottom === 'delete');
            
            if (isDelete) {
                $('.spar-undone-cb').show();
            } else {
                $('.spar-undone-cb').hide().prop('checked', false);
            }
        }

        $('#bulk-action-selector-top, #bulk-action-selector-bottom').on('change', toggleUndoneCheckboxes);
        
        // Run on load
        toggleUndoneCheckboxes();
    });
    </script>
    <?php
}
