<?php

if ( !defined( 'ABSPATH' ) ) {
    exit;
}
// Exit if accessed directly
function wpsummarize_admin_menu() {
    // Main menu page
    add_menu_page(
        esc_html__( 'WPSummarize Dashboard', 'wpsummarize' ),
        // Page title
        esc_html__( 'WPSummarize', 'wpsummarize' ),
        // Menu title
        'manage_options',
        // Capability
        'wpsummarize',
        // Menu slug
        'wpsummarize_dashboard_page',
        // Function to display the dashboard page
        'data:image/svg+xml;base64,' . base64_encode( wpsummarize_sanitize_svg( '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#a7aaad"><path d="M4 4c0-1.1.9-2 2-2h12c1.1 0 2 .9 2 2v16c0 1.1-.9 2-2 2H6c-1.1 0-2-.9-2-2V4zm2 0v16h12V4H6zm2 3h8v2H8V7zm0 4h8v2H8v-2zm0 4h8v2H8v-2z"/></svg>' ) )
    );
    // Manually add the Dashboard submenu page that matches the main menu
    add_submenu_page(
        'wpsummarize',
        // Parent slug, matching the main menu slug
        esc_html__( 'WPSummarize Dashboard', 'wpsummarize' ),
        // Page title
        esc_html__( 'Dashboard', 'wpsummarize' ),
        // Menu title
        'manage_options',
        // Capability
        'wpsummarize',
        // Menu slug, same as main menu to actually link to the main menu item
        'wpsummarize_dashboard_page'
    );
    // Additional submenu page for settings
    add_submenu_page(
        'wpsummarize',
        // Parent slug, matching the main menu slug
        esc_html__( 'WPSummarize Settings', 'wpsummarize' ),
        // Page title
        esc_html__( 'Settings', 'wpsummarize' ),
        // Menu title
        'manage_options',
        // Capability
        'wpsummarize_settings',
        // Menu slug
        'wpsummarize_settings_page'
    );
}

function wpsummarize_display_user_message() {
    if ( wpsummarize_fs()->is_trial() ) {
        ?>
    	<div class="notice notice-info wpsummarize-trial-notice" style="border-left-color: #2271b1; padding: 20px; margin: 20px 0; background: #f0f6fc;">
    		<h3 style="margin-top: 0; color: #2271b1;">
    			<span class="dashicons dashicons-star-filled" style="font-size: 20px; vertical-align: middle;"></span>
    			<?php 
        esc_html_e( 'Exploring All Features? You\'re On the Right Track!', 'wpsummarize' );
        ?>
    		</h3>
    		
    		<p style="font-size: 14px; line-height: 1.6;">
    			<?php 
        printf( 
            /* translators: %s: "trial account" text */
            esc_html__( 'You\'re currently using a %s with full access to explore everything our plugin has to offer:', 'wpsummarize' ),
            '<strong>' . esc_html__( 'trial account', 'wpsummarize' ) . '</strong>'
         );
        ?>
    		</p>
    		
    		<ul style="font-size: 14px; line-height: 1.8; margin: 15px 0;">
    			<li>
    				<span class="dashicons dashicons-yes-alt" style="color: #00a32a;"></span>
    				<?php 
        esc_html_e( 'Batch processing for multiple posts at once', 'wpsummarize' );
        ?>
    			</li>
    			<li>
    				<span class="dashicons dashicons-yes-alt" style="color: #00a32a;"></span>
    				<?php 
        esc_html_e( 'All AI providers (OpenAI, Gemini, Anthropic)', 'wpsummarize' );
        ?>
    			</li>
    			<li>
    				<span class="dashicons dashicons-yes-alt" style="color: #00a32a;"></span>
    				<?php 
        esc_html_e( 'Custom settings per post', 'wpsummarize' );
        ?>
    			</li>
    			<li>
    				<span class="dashicons dashicons-yes-alt" style="color: #00a32a;"></span>
    				<?php 
        esc_html_e( 'Advanced configuration options', 'wpsummarize' );
        ?>
    			</li>
    		</ul>
    		
    		<p style="font-size: 14px; background: #fff; padding: 12px; border-left: 3px solid #2271b1; margin: 15px 0;">
    			<strong><?php 
        esc_html_e( 'Trial Limit:', 'wpsummarize' );
        ?></strong>
    			<?php 
        printf( 
            /* translators: %d: Number of summaries */
            esc_html__( '%d summaries', 'wpsummarize' ),
            250
         );
        ?>
    		</p>
    		
    		<p style="font-size: 14px; line-height: 1.6;">
    			<?php 
        esc_html_e( 'Once you\'ve reached your limit, you\'ll need to upgrade to continue generating summaries. Ready to unlock unlimited potential?', 'wpsummarize' );
        ?>
    		</p>
    		
    		<p style="margin-top: 20px;">
    			<a href="<?php 
        echo esc_url( wpsummarize_fs()->get_upgrade_url() );
        ?>" class="button button-primary button-hero" style="text-decoration: none;">
    				<span class="dashicons dashicons-unlock" style="vertical-align: middle;"></span>
    				<?php 
        esc_html_e( 'Upgrade Now', 'wpsummarize' );
        ?>
    			</a>
    		</p>
    	</div>
    	<?php 
    } elseif ( wpsummarize_fs()->is_free_plan() ) {
        // Premium features list.
        $features = array(
            array(
                'icon'        => 'dashicons-update',
                'title'       => __( 'Batch Processing', 'wpsummarize' ),
                'description' => __( 'Summarize multiple posts simultaneously', 'wpsummarize' ),
            ),
            array(
                'icon'        => 'dashicons-admin-settings',
                'title'       => __( 'Per-Post Settings', 'wpsummarize' ),
                'description' => __( 'Customize AI behavior for individual posts', 'wpsummarize' ),
            ),
            array(
                'icon'        => 'dashicons-superhero',
                'title'       => __( 'Premium AI Providers', 'wpsummarize' ),
                'description' => __( 'Access Gemini and Anthropic (Claude) models', 'wpsummarize' ),
            ),
            array(
                'icon'        => 'dashicons-chart-line',
                'title'       => __( 'Higher Limits', 'wpsummarize' ),
                'description' => __( 'Generate hundreds or thousands of summaries', 'wpsummarize' ),
            ),
            array(
                'icon'        => 'dashicons-sos',
                'title'       => __( 'Priority Support', 'wpsummarize' ),
                'description' => __( 'Get help when you need it', 'wpsummarize' ),
            ),
            array(
                'icon'        => 'dashicons-editor-code',
                'title'       => __( 'Advanced Templates', 'wpsummarize' ),
                'description' => __( 'More control over summary output', 'wpsummarize' ),
            )
        );
        // Allow filtering of features.
        $features = apply_filters( 'wpsummarize_premium_features', $features );
        ?>
    	<div class="notice notice-warning wpsummarize-free-notice" style="border-left-color: #dba617; padding: 20px; margin: 20px 0; background: #fcf9e8;">
    		<h3 style="margin-top: 0; color: #996800;">
    			<span class="dashicons dashicons-info" style="font-size: 20px; vertical-align: middle;"></span>
    			<?php 
        esc_html_e( 'You\'re Using the Free Plan', 'wpsummarize' );
        ?>
    		</h3>
    		
    		<p style="font-size: 14px; line-height: 1.6; background: #fff; padding: 12px; border-left: 3px solid #dba617; margin: 15px 0;">
    			<?php 
        printf( 
            /* translators: %s: Number of summaries per month */
            esc_html__( 'Your account includes %s to help you get started with AI-powered content summarization.', 'wpsummarize' ),
            '<strong>' . sprintf( 
                /* translators: %d: Number of summaries */
                esc_html__( '%d summaries per month', 'wpsummarize' ),
                50
             ) . '</strong>'
         );
        ?>
    		</p>
    		
    		<h4 style="color: #996800; margin: 20px 0 10px 0;">
    			<?php 
        esc_html_e( 'Want to do more? Upgrade to unlock premium features:', 'wpsummarize' );
        ?>
    		</h4>
    		
    		<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 15px; margin: 20px 0;">
    			<?php 
        foreach ( $features as $feature ) {
            ?>
    				<div style="background: #fff; padding: 15px; border-radius: 4px; border-left: 3px solid #2271b1;">
    					<strong style="color: #2271b1;">
    						<span class="dashicons <?php 
            echo esc_attr( $feature['icon'] );
            ?>" style="vertical-align: middle;"></span>
    						<?php 
            echo esc_html( $feature['title'] );
            ?>
    					</strong>
    					<p style="margin: 8px 0 0 0; font-size: 13px; color: #646970;">
    						<?php 
            echo esc_html( $feature['description'] );
            ?>
    					</p>
    				</div>
    			<?php 
        }
        ?>
    		</div>
    		
    		<p style="font-size: 14px; line-height: 1.6; margin-top: 20px;">
    			<?php 
        esc_html_e( 'Stop manually summarizing one post at a time. Upgrade and let AI handle your entire content library.', 'wpsummarize' );
        ?>
    		</p>
    		
    		<p style="margin-top: 20px;">
    			<a href="<?php 
        echo esc_url( wpsummarize_fs()->get_upgrade_url() );
        ?>" class="button button-primary button-hero" style="text-decoration: none;">
    				<span class="dashicons dashicons-cart" style="vertical-align: middle;"></span>
    				<?php 
        esc_html_e( 'See Plans &amp; Pricing', 'wpsummarize' );
        ?>
    			</a>
    		</p>
    	</div>
    	<?php 
    }
}

function wpsummarize_settings_page() {
    wpsummarize_display_user_message();
    ?>
    <div class="wrap wpsummarize_settings_form">
        <h2 class="wpsummarize_settings_title"><?php 
    echo esc_html__( 'WPSummarize Settings', 'wpsummarize' );
    ?></h2>
        
        <!-- Begin Form -->
        <form method="post" action="options.php">
            <?php 
    wpsummarize_check_and_notify_token_limit();
    settings_fields( 'wpsummarize_options' );
    // Unified option group
    do_settings_sections( 'wpsummarize_options' );
    // Display all sections
    submit_button( esc_html__( 'Save Changes', 'wpsummarize' ) );
    ?>
        </form>
    </div>
    <?php 
}

function wpsummarize_dashboard_page() {
    global $wpdb;
    wpsummarize_display_user_message();
    ?>
    <div class="wrap wpsummarize_settings_form">
        <h2 class="wpsummarize_settings_title"><?php 
    echo esc_html__( 'WPSummarize Dashboard', 'wpsummarize' );
    ?></h2>
        <?php 
    wpsummarize_check_and_notify_token_limit();
    $tokens_data = wpsummarize_api_check_tokens( 'dashboard' );
    $tokens_text = sprintf( 
        // translators: %1$d is the number of credits used, %2$d is the total number of credits available for the month
        esc_html__( 'Credits used this month: %1$s / %2$s', 'wpsummarize' ),
        esc_html( $tokens_data['tokens_used_month'] ),
        esc_html( $tokens_data['token_limit'] )
     );
    $allowed_html = array(
        'div'  => array(
            'class' => array(),
            'id'    => array(),
        ),
        'span' => array(
            'class' => array(),
        ),
    );
    echo wp_kses( '<div class="wpsummarize_dashboard_tokens">' . $tokens_text . '</div>', $allowed_html );
    echo '<table class="wp-list-table widefat fixed bookmarks" style="padding-left:0">
        <thead>
        <tr>
            <th><strong>' . esc_html__( 'Today', 'wpsummarize' ) . '</strong></th>
            <th><strong>' . esc_html__( 'Yesterday', 'wpsummarize' ) . '</strong></th>
            <th><strong>' . esc_html__( 'This Week', 'wpsummarize' ) . '</strong></th>
            <th><strong>' . esc_html__( 'This Month', 'wpsummarize' ) . '</strong></th>
            <th><strong>' . esc_html__( 'All Time', 'wpsummarize' ) . '</strong></th>        
        </tr>
    <thead>
     <tbody>
                        <tr>
                    <td>' . esc_html( $tokens_data['tokens_used_today'] ) . '</td>
                    <td>' . esc_html( $tokens_data['tokens_used_yesterday'] ) . '</td>
                    <td>' . esc_html( $tokens_data['tokens_used_week'] ) . '</td>
                    <td>' . esc_html( $tokens_data['tokens_used_month'] ) . '</td>
                    <td>' . esc_html( $tokens_data['tokens_used_all_time'] ) . '</td>        
                </tr>

            
    </tbody>
</table>';
    ?>

<h2 class="wpsummarize_settings_title subtitle"><?php 
    echo esc_html__( 'All summaries', 'wpsummarize' );
    ?></h2>
<p class="description" style="margin-bottom:10px;">
    <?php 
    echo esc_html__( 'Browse, search and manage every summary. Use the row actions to regenerate or revert a summary, or bulk actions to act on several at once.', 'wpsummarize' );
    ?>
</p>
<?php 
    // Active batch filter notice with a clear link.
    $active_batch = ( isset( $_REQUEST['wpsummarize_batch'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['wpsummarize_batch'] ) ) : '' );
    if ( '' !== $active_batch ) {
        $page_slug = ( isset( $_REQUEST['page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) : 'wpsummarize' );
        $clear_url = add_query_arg( array(
            'page' => $page_slug,
        ), admin_url( 'admin.php' ) );
        ?>
            <div class="notice notice-info inline" style="margin:10px 0;padding:8px 12px;">
                <?php 
        printf( 
            /* translators: %s: batch identifier */
            esc_html__( 'Showing summaries from batch %s.', 'wpsummarize' ),
            '<code>' . esc_html( $active_batch ) . '</code>'
         );
        ?>
                <a href="<?php 
        echo esc_url( $clear_url );
        ?>" style="margin-left:8px;"><?php 
        esc_html_e( 'Clear filter', 'wpsummarize' );
        ?></a>
            </div>
            <?php 
    }
    // Render the searchable, paginated summaries list table.
    $summaries_table = new WPSummarize_Summaries_List_Table();
    $summaries_table->prepare_items();
    ?>
        <form method="get" class="wpsummarize-summaries-form">
            <input type="hidden" name="page" value="<?php 
    echo esc_attr( ( isset( $_REQUEST['page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) : 'wpsummarize' ) );
    ?>" />
            <?php 
    if ( '' !== $active_batch ) {
        ?>
            <input type="hidden" name="wpsummarize_batch" value="<?php 
        echo esc_attr( $active_batch );
        ?>" />
            <?php 
    }
    ?>
            <?php 
    $summaries_table->search_box( esc_html__( 'Search summaries', 'wpsummarize' ), 'wpsummarize-summary-search' );
    $summaries_table->display();
    ?>
        </form>
        <?php 
    ?>
    </div>    
        
    <?php 
}

/**
 * Summaries list table.
 *
 * Powers the "All summaries" section on the dashboard: pagination, search,
 * sortable date column, source/status indicators, row actions (regenerate /
 * revert) and bulk actions (regenerate selected / delete summary).
 */
if ( !class_exists( 'WP_List_Table' ) ) {
    require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}
class WPSummarize_Summaries_List_Table extends WP_List_Table {
    public function __construct() {
        parent::__construct( array(
            'singular' => 'wpsummarize_summary',
            'plural'   => 'wpsummarize_summaries',
            'ajax'     => false,
        ) );
    }

    /**
     * Define columns. The cb column enables bulk-action checkboxes.
     */
    public function get_columns() {
        return array(
            'cb'      => '<input type="checkbox" />',
            'post'    => esc_html__( 'Post', 'wpsummarize' ),
            'summary' => esc_html__( 'Summary', 'wpsummarize' ),
            'source'  => esc_html__( 'Source', 'wpsummarize' ),
            'date'    => esc_html__( 'Generated', 'wpsummarize' ),
        );
    }

    /**
     * Only the date column is sortable (it maps to a real stored timestamp).
     */
    public function get_sortable_columns() {
        return array(
            'date' => array('date', true),
        );
    }

    public function get_bulk_actions() {
        return array(
            'regenerate'     => esc_html__( 'Regenerate summary', 'wpsummarize' ),
            'delete_summary' => esc_html__( 'Delete summary', 'wpsummarize' ),
        );
    }

    /**
     * Checkbox column.
     */
    public function column_cb( $item ) {
        return sprintf( '<input type="checkbox" name="summary_post[]" value="%d" />', absint( $item['post_id'] ) );
    }

    /**
     * Post column: title linking to the editor, with view link + status, and row actions.
     */
    public function column_post( $item ) {
        $post_id = absint( $item['post_id'] );
        $edit_link = get_edit_post_link( $post_id );
        $view_link = get_permalink( $post_id );
        $post_obj = get_post( $post_id );
        $title = ( $post_obj ? $post_obj->post_title : sprintf( esc_html__( '(Post #%d)', 'wpsummarize' ), $post_id ) );
        $status_obj = ( $post_obj ? get_post_status_object( $post_obj->post_status ) : null );
        $status_lbl = ( $status_obj ? $status_obj->label : '' );
        // Title links to the editor when available, otherwise to the front end.
        if ( $edit_link ) {
            $title_html = '<strong><a href="' . esc_url( $edit_link ) . '">' . esc_html( $title ) . '</a></strong>';
        } else {
            $title_html = '<strong>' . esc_html( $title ) . '</strong>';
        }
        if ( $status_lbl ) {
            $title_html .= ' <span class="wpsummarize-post-status">(' . esc_html( $status_lbl ) . ')</span>';
        }
        // Flag a stuck / in-flight generation so failed runs are visible.
        if ( !empty( $item['running'] ) ) {
            $title_html .= ' <span class="wpsummarize-status-running" title="' . esc_attr__( 'A generation is currently running or stuck for this post.', 'wpsummarize' ) . '">&#9203; ' . esc_html__( 'Running', 'wpsummarize' ) . '</span>';
        }
        // Row actions.
        $nonce = wp_create_nonce( 'wpsummarize_row_action_' . $post_id );
        $actions = array();
        if ( $edit_link ) {
            $actions['edit'] = '<a href="' . esc_url( $edit_link ) . '">' . esc_html__( 'Edit post', 'wpsummarize' ) . '</a>';
        }
        if ( $view_link ) {
            $actions['view'] = '<a href="' . esc_url( $view_link ) . '" target="_blank" rel="noopener">' . esc_html__( 'View', 'wpsummarize' ) . '</a>';
        }
        $actions['regenerate'] = sprintf(
            '<a href="#" class="wpsummarize-row-regenerate" data-post="%d" data-nonce="%s">%s</a>',
            $post_id,
            esc_attr( $nonce ),
            esc_html__( 'Regenerate', 'wpsummarize' )
        );
        // Revert is only offered when a previous revision exists.
        if ( !empty( $item['has_revision'] ) ) {
            $actions['revert'] = sprintf(
                '<a href="#" class="wpsummarize-row-revert" data-post="%d" data-nonce="%s">%s</a>',
                $post_id,
                esc_attr( $nonce ),
                esc_html__( 'Revert to previous', 'wpsummarize' )
            );
        }
        // Offer a manual escape hatch when a generation flag is currently set, so a
        // post can never be left permanently stuck on "Running".
        if ( !empty( $item['running'] ) ) {
            $actions['clear_stuck'] = sprintf(
                '<a href="#" class="wpsummarize-row-clear-stuck" data-post="%d" data-nonce="%s">%s</a>',
                $post_id,
                esc_attr( $nonce ),
                esc_html__( 'Clear stuck flag', 'wpsummarize' )
            );
        }
        return $title_html . $this->row_actions( $actions );
    }

    /**
     * Summary column: truncated preview with an expand toggle for the full text.
     */
    public function column_summary( $item ) {
        $full = (string) $item['summary'];
        $plain = wp_strip_all_tags( $full );
        $limit = 150;
        $needs_cut = mb_strlen( $plain ) > $limit;
        if ( !$needs_cut ) {
            return '<div class="wpsummarize-summary-cell">' . wp_kses_post( $full ) . '</div>';
        }
        $short = esc_html( mb_substr( $plain, 0, $limit ) ) . '&hellip;';
        $out = '<div class="wpsummarize-summary-cell">';
        $out .= '<span class="wpsummarize-summary-short">' . $short . ' <a href="#" class="wpsummarize-summary-toggle" data-state="short">' . esc_html__( 'Show full', 'wpsummarize' ) . '</a></span>';
        $out .= '<span class="wpsummarize-summary-full" style="display:none;">' . wp_kses_post( $full ) . ' <a href="#" class="wpsummarize-summary-toggle" data-state="full">' . esc_html__( 'Show less', 'wpsummarize' ) . '</a></span>';
        $out .= '</div>';
        return $out;
    }

    /**
     * Source column: auto / batch (with batch ID) / manual.
     */
    public function column_source( $item ) {
        if ( !empty( $item['manual'] ) ) {
            return '<span class="wpsummarize-source wpsummarize-source-manual">' . esc_html__( 'Manual edit', 'wpsummarize' ) . '</span>';
        }
        if ( !empty( $item['batch_id'] ) ) {
            $batch_id = $item['batch_id'];
            $page = ( isset( $_REQUEST['page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) : 'wpsummarize' );
            $filter_url = add_query_arg( array(
                'page'              => $page,
                'wpsummarize_batch' => rawurlencode( $batch_id ),
            ), admin_url( 'admin.php' ) );
            return '<span class="wpsummarize-source wpsummarize-source-batch">' . esc_html__( 'Batch', 'wpsummarize' ) . '</span><br />' . '<a href="' . esc_url( $filter_url ) . '" class="wpsummarize-batch-id" title="' . esc_attr__( 'Show only summaries from this batch', 'wpsummarize' ) . '">' . esc_html( $batch_id ) . '</a>';
        }
        return '<span class="wpsummarize-source wpsummarize-source-auto">' . esc_html__( 'Automatic', 'wpsummarize' ) . '</span>';
    }

    /**
     * Date column: formatted generation time, or a dash when unknown (legacy summaries).
     */
    public function column_date( $item ) {
        if ( empty( $item['generated_on'] ) ) {
            return '<span aria-hidden="true">&mdash;</span><span class="screen-reader-text">' . esc_html__( 'Unknown', 'wpsummarize' ) . '</span>';
        }
        $ts = absint( $item['generated_on'] );
        return esc_html( wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $ts ) );
    }

    /**
     * Fallback for any unforeseen column.
     */
    public function column_default( $item, $column_name ) {
        return ( isset( $item[$column_name] ) ? esc_html( $item[$column_name] ) : '' );
    }

    public function no_items() {
        esc_html_e( 'No summaries found.', 'wpsummarize' );
    }

    /**
     * Build the dataset: query summaries from postmeta with search, sort and pagination.
     */
    public function prepare_items() {
        global $wpdb;
        $per_page = 20;
        $current_page = $this->get_pagenum();
        $offset = ($current_page - 1) * $per_page;
        // Sort order (date column only).
        $order = ( isset( $_REQUEST['order'] ) && strtolower( sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ) ) === 'asc' ? 'ASC' : 'DESC' );
        // Search term (matches post title).
        $search = ( isset( $_REQUEST['s'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ) : '' );
        // Optional batch filter (set when a batch ID is clicked in the Source column).
        $batch = ( isset( $_REQUEST['wpsummarize_batch'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['wpsummarize_batch'] ) ) : '' );
        // We order by the stored generation timestamp when present, falling back to
        // meta_id so legacy summaries (no timestamp) still sort sensibly.
        $summary_key = '_wpsummarize_summary_set';
        $generated_key = '_wpsummarize_summary_generated';
        $batch_key = '_wpsummarize_summary_batch_id';
        // Base joins: summaries left-joined to their generation timestamp.
        // Optional search joins the posts table on title.
        $where_search = '';
        $search_join = '';
        if ( '' !== $search ) {
            $search_join = " INNER JOIN {$wpdb->posts} p ON p.ID = sm.post_id ";
            $where_search = $wpdb->prepare( ' AND p.post_title LIKE %s ', '%' . $wpdb->esc_like( $search ) . '%' );
        }
        // Optional batch join: restrict to posts stamped with the given batch ID.
        $batch_join = '';
        if ( '' !== $batch ) {
            $batch_join = $wpdb->prepare( " INNER JOIN {$wpdb->postmeta} bm ON bm.post_id = sm.post_id AND bm.meta_key = %s AND bm.meta_value = %s ", $batch_key, $batch );
        }
        // Total count for pagination.
        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- table names + prebuilt prepared fragments.
        $total_items = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->postmeta} sm {$search_join} {$batch_join} WHERE sm.meta_key = %s {$where_search}", $summary_key ) );
        // Main query. COALESCE on the timestamp lets us order new + legacy rows together.
        $rows = $wpdb->get_results( $wpdb->prepare(
            "SELECT sm.post_id AS post_id, sm.meta_value AS summary,\r\n                        gm.meta_value AS generated_on\r\n                 FROM {$wpdb->postmeta} sm\r\n                 {$search_join}\r\n                 {$batch_join}\r\n                 LEFT JOIN {$wpdb->postmeta} gm\r\n                        ON gm.post_id = sm.post_id AND gm.meta_key = %s\r\n                 WHERE sm.meta_key = %s {$where_search}\r\n                 ORDER BY COALESCE(gm.meta_value + 0, 0) {$order}, sm.meta_id {$order}\r\n                 LIMIT %d OFFSET %d",
            $generated_key,
            $summary_key,
            $per_page,
            $offset
        ) );
        // phpcs:enable
        $items = array();
        foreach ( $rows as $row ) {
            $post_id = absint( $row->post_id );
            $items[] = array(
                'post_id'      => $post_id,
                'summary'      => $row->summary,
                'generated_on' => ( $row->generated_on ? absint( $row->generated_on ) : 0 ),
                'manual'       => (bool) get_post_meta( $post_id, '_wpsummarize_summary_set_manual', true ),
                'batch_id'     => get_post_meta( $post_id, '_wpsummarize_summary_batch_id', true ),
                'running'      => ( function_exists( 'wpsummarize_check_if_summary_is_generating' ) ? wpsummarize_check_if_summary_is_generating( $post_id ) : (bool) get_post_meta( $post_id, 'wpsummarize_running_api', true ) ),
                'has_revision' => get_post_meta( $post_id, '_wpsummarize_summary_revision', true ) !== '',
            );
        }
        $this->items = $items;
        $columns = $this->get_columns();
        $hidden = array();
        $sortable = $this->get_sortable_columns();
        $this->_column_headers = array($columns, $hidden, $sortable);
        $this->set_pagination_args( array(
            'total_items' => $total_items,
            'per_page'    => $per_page,
            'total_pages' => (int) ceil( $total_items / $per_page ),
        ) );
    }

}

/**
 * AJAX: regenerate a single summary.
 *
 * Queues the generation asynchronously (Action Scheduler processes it on its next
 * tick) rather than running it inline. A synchronous run here would block the
 * admin-ajax request on the outbound API call and could trip Action Scheduler's
 * 300s time limit, leaving the post stuck on "Running".
 */
function wpsummarize_ajax_regenerate_summary() {
    $post_id = ( isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0 );
    if ( !$post_id || !isset( $_POST['nonce'] ) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wpsummarize_row_action_' . $post_id ) ) {
        wp_send_json_error( array(
            'message' => esc_html__( 'Security check failed.', 'wpsummarize' ),
        ) );
    }
    if ( !current_user_can( 'manage_options' ) ) {
        wp_send_json_error( array(
            'message' => esc_html__( 'Insufficient permissions.', 'wpsummarize' ),
        ) );
    }
    $queued = wpsummarize_queue_summary_async( $post_id );
    if ( !$queued ) {
        wp_send_json_error( array(
            'message' => esc_html__( 'Could not queue regeneration. Please try again.', 'wpsummarize' ),
        ) );
    }
    wp_send_json_success( array(
        'message' => esc_html__( 'Summary regeneration queued. It will be processed shortly — refresh in a minute to see the result.', 'wpsummarize' ),
    ) );
}

add_action( 'wp_ajax_wpsummarize_regenerate_summary', 'wpsummarize_ajax_regenerate_summary' );
/**
 * AJAX: revert a summary to its stored previous revision.
 */
function wpsummarize_ajax_revert_summary() {
    $post_id = ( isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0 );
    if ( !$post_id || !isset( $_POST['nonce'] ) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wpsummarize_row_action_' . $post_id ) ) {
        wp_send_json_error( array(
            'message' => esc_html__( 'Security check failed.', 'wpsummarize' ),
        ) );
    }
    if ( !current_user_can( 'manage_options' ) ) {
        wp_send_json_error( array(
            'message' => esc_html__( 'Insufficient permissions.', 'wpsummarize' ),
        ) );
    }
    $revision = get_post_meta( $post_id, '_wpsummarize_summary_revision', true );
    if ( '' === $revision ) {
        wp_send_json_error( array(
            'message' => esc_html__( 'No previous summary to revert to.', 'wpsummarize' ),
        ) );
    }
    // Swap current <-> revision so the action is itself reversible.
    $current = get_post_meta( $post_id, '_wpsummarize_summary_set', true );
    update_post_meta( $post_id, '_wpsummarize_summary_set', wp_kses_post( $revision ) );
    update_post_meta( $post_id, '_wpsummarize_summary_revision', wp_kses_post( $current ) );
    // Reverting is a manual intervention; mark it so batch runs don't overwrite it.
    update_post_meta( $post_id, '_wpsummarize_summary_set_manual', intval( time() ) );
    wp_send_json_success( array(
        'message' => esc_html__( 'Summary reverted to the previous version.', 'wpsummarize' ),
    ) );
}

add_action( 'wp_ajax_wpsummarize_revert_summary', 'wpsummarize_ajax_revert_summary' );
/**
 * AJAX: clear a stuck 'wpsummarize_running_api' flag for a post.
 *
 * Used when a generation action timed out (Action Scheduler force-fails at ~300s)
 * before it could clear its own flag, leaving the post showing "Running".
 */
function wpsummarize_ajax_clear_stuck_flag() {
    $post_id = ( isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0 );
    if ( !$post_id || !isset( $_POST['nonce'] ) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wpsummarize_row_action_' . $post_id ) ) {
        wp_send_json_error( array(
            'message' => esc_html__( 'Security check failed.', 'wpsummarize' ),
        ) );
    }
    if ( !current_user_can( 'manage_options' ) ) {
        wp_send_json_error( array(
            'message' => esc_html__( 'Insufficient permissions.', 'wpsummarize' ),
        ) );
    }
    delete_post_meta( $post_id, 'wpsummarize_running_api' );
    wp_send_json_success( array(
        'message' => esc_html__( 'Cleared. You can regenerate this summary now.', 'wpsummarize' ),
    ) );
}

add_action( 'wp_ajax_wpsummarize_clear_stuck_flag', 'wpsummarize_ajax_clear_stuck_flag' );
/**
 * Handle bulk actions (regenerate selected / delete summary) on the dashboard.
 * Bulk requests come in as GET from the list-table form, so we verify the
 * WP_List_Table bulk nonce and act on the selected post IDs.
 */
function wpsummarize_handle_summaries_bulk_actions() {
    if ( !is_admin() || !current_user_can( 'manage_options' ) ) {
        return;
    }
    $page = ( isset( $_REQUEST['page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) : '' );
    if ( 'wpsummarize' !== $page ) {
        return;
    }
    // Determine requested action from either bulk dropdown.
    $action = '-1';
    if ( isset( $_REQUEST['action'] ) && '-1' !== $_REQUEST['action'] ) {
        $action = sanitize_text_field( wp_unslash( $_REQUEST['action'] ) );
    } elseif ( isset( $_REQUEST['action2'] ) && '-1' !== $_REQUEST['action2'] ) {
        $action = sanitize_text_field( wp_unslash( $_REQUEST['action2'] ) );
    }
    if ( '-1' === $action || empty( $_REQUEST['summary_post'] ) ) {
        return;
    }
    // WP_List_Table sets this nonce field for bulk actions.
    check_admin_referer( 'bulk-wpsummarize_summaries' );
    $post_ids = array_map( 'absint', (array) $_REQUEST['summary_post'] );
    $count = 0;
    foreach ( $post_ids as $post_id ) {
        if ( !$post_id ) {
            continue;
        }
        if ( 'regenerate' === $action ) {
            wpsummarize_queue_summary_async( $post_id );
            $count++;
        } elseif ( 'delete_summary' === $action ) {
            delete_post_meta( $post_id, '_wpsummarize_summary_set' );
            delete_post_meta( $post_id, '_wpsummarize_summary_set_manual' );
            delete_post_meta( $post_id, '_wpsummarize_summary_batch_id' );
            delete_post_meta( $post_id, '_wpsummarize_summary_generated' );
            $count++;
        }
    }
    $redirect = add_query_arg( array(
        'page'                   => 'wpsummarize',
        'wpsummarize_bulk_done'  => $action,
        'wpsummarize_bulk_count' => $count,
    ), admin_url( 'admin.php' ) );
    wp_safe_redirect( $redirect );
    exit;
}

add_action( 'admin_init', 'wpsummarize_handle_summaries_bulk_actions' );
/**
 * Admin notice confirming a completed bulk action.
 */
function wpsummarize_summaries_bulk_notice() {
    if ( empty( $_GET['wpsummarize_bulk_done'] ) ) {
        return;
    }
    $action = sanitize_text_field( wp_unslash( $_GET['wpsummarize_bulk_done'] ) );
    $count = ( isset( $_GET['wpsummarize_bulk_count'] ) ? absint( $_GET['wpsummarize_bulk_count'] ) : 0 );
    if ( 'regenerate' === $action ) {
        $msg = sprintf( 
            /* translators: %d: number of summaries */
            _n(
                '%d summary queued for regeneration.',
                '%d summaries queued for regeneration.',
                $count,
                'wpsummarize'
            ),
            $count
         );
    } elseif ( 'delete_summary' === $action ) {
        $msg = sprintf( 
            /* translators: %d: number of summaries */
            _n(
                '%d summary deleted.',
                '%d summaries deleted.',
                $count,
                'wpsummarize'
            ),
            $count
         );
    } else {
        return;
    }
    echo '<div class="notice notice-success is-dismissible"><p>' . esc_html( $msg ) . '</p></div>';
}

add_action( 'admin_notices', 'wpsummarize_summaries_bulk_notice' );
/**
 * Enqueue dashboard list-table styles + inline JS for row actions and toggles.
 */
function wpsummarize_enqueue_dashboard_assets(  $hook  ) {
    // Dashboard page is the top-level menu; hook is "toplevel_page_wpsummarize".
    if ( 'toplevel_page_wpsummarize' !== $hook ) {
        return;
    }
    $css = '
        .wpsummarize-summary-cell { max-width: 100%; line-height: 1.5; }
        .wpsummarize-source { display: inline-block; padding: 2px 8px; border-radius: 3px; font-size: 12px; }
        .wpsummarize-source-batch { background: #e7f5ff; color: #0a558c; }
        .wpsummarize-source-manual { background: #fcf3e6; color: #996800; }
        .wpsummarize-source-auto { background: #edf7ed; color: #1e7e34; }
        .wpsummarize-batch-id { font-size: 11px; color: #646970; }
        .wpsummarize-post-status { color: #646970; font-weight: normal; }
        .wpsummarize-status-running { color: #b26a00; font-weight: 600; }
        .column-summary { width: 40%; }
        .column-source, .column-date { width: 14%; }
        /* Inset the bulk-actions and search rows so controls aren\'t flush to the edges. */
        .wpsummarize-summaries-form .tablenav { padding: 0 12px; box-sizing: border-box; }
        .wpsummarize-summaries-form .search-box { margin-right: 12px; }
        .wpsummarize-summaries-form .wp-list-table { margin-top: 4px; }
        .bulkactions {min-width:400px}
        #doaction {margin-top:5px}
        .tablenav .actions {	padding: 0 8px 10px 0;}
        .wpsummarize-summaries-form .tablenav.bottom {margin-bottom: 20px;margin-top:10px}
    ';
    wp_register_style( 'wpsummarize-dashboard', false );
    wp_enqueue_style( 'wpsummarize-dashboard' );
    wp_add_inline_style( 'wpsummarize-dashboard', $css );
    $js = "\r\n    (function(\$){\r\n        \$(document).on('click', '.wpsummarize-summary-toggle', function(e){\r\n            e.preventDefault();\r\n            var cell = \$(this).closest('.wpsummarize-summary-cell');\r\n            cell.find('.wpsummarize-summary-short').toggle();\r\n            cell.find('.wpsummarize-summary-full').toggle();\r\n        });\r\n\r\n        function rowAction(action, link, confirmMsg){\r\n            if (confirmMsg && !window.confirm(confirmMsg)) { return; }\r\n            var postId = \$(link).data('post');\r\n            var nonce  = \$(link).data('nonce');\r\n            var orig   = \$(link).text();\r\n            \$(link).text(wpSummarizeDash.working);\r\n            \$.post(wpSummarizeDash.ajax_url, {\r\n                action: action,\r\n                post_id: postId,\r\n                nonce: nonce\r\n            }).done(function(resp){\r\n                window.alert(resp && resp.data && resp.data.message ? resp.data.message : wpSummarizeDash.done);\r\n            }).fail(function(){\r\n                window.alert(wpSummarizeDash.error);\r\n            }).always(function(){\r\n                \$(link).text(orig);\r\n            });\r\n        }\r\n\r\n        \$(document).on('click', '.wpsummarize-row-regenerate', function(e){\r\n            e.preventDefault();\r\n            rowAction('wpsummarize_regenerate_summary', this, wpSummarizeDash.confirmRegen);\r\n        });\r\n        \$(document).on('click', '.wpsummarize-row-revert', function(e){\r\n            e.preventDefault();\r\n            rowAction('wpsummarize_revert_summary', this, wpSummarizeDash.confirmRevert);\r\n        });\r\n        \$(document).on('click', '.wpsummarize-row-clear-stuck', function(e){\r\n            e.preventDefault();\r\n            rowAction('wpsummarize_clear_stuck_flag', this, wpSummarizeDash.confirmClear);\r\n        });\r\n    })(jQuery);\r\n    ";
    wp_register_script(
        'wpsummarize-dashboard',
        '',
        array('jquery'),
        false,
        true
    );
    wp_enqueue_script( 'wpsummarize-dashboard' );
    wp_add_inline_script( 'wpsummarize-dashboard', $js );
    wp_localize_script( 'wpsummarize-dashboard', 'wpSummarizeDash', array(
        'ajax_url'      => admin_url( 'admin-ajax.php' ),
        'working'       => esc_html__( 'Working...', 'wpsummarize' ),
        'done'          => esc_html__( 'Done.', 'wpsummarize' ),
        'error'         => esc_html__( 'Something went wrong. Please try again.', 'wpsummarize' ),
        'confirmRegen'  => esc_html__( 'Regenerate this summary?', 'wpsummarize' ),
        'confirmRevert' => esc_html__( 'Revert to the previous summary version?', 'wpsummarize' ),
        'confirmClear'  => esc_html__( 'Clear the stuck "running" flag for this post?', 'wpsummarize' ),
    ) );
}

add_action( 'admin_enqueue_scripts', 'wpsummarize_enqueue_dashboard_assets' );
// Ensure this hooks into the admin_menu
add_action( 'admin_menu', 'wpsummarize_admin_menu' );
function wpsummarize_sanitize_svg(  $svg  ) {
    $allowed_tags = array(
        'svg'  => array(
            'xmlns'   => array(),
            'viewbox' => array(),
            'fill'    => array(),
        ),
        'path' => array(
            'd' => array(),
        ),
    );
    return wp_kses( $svg, $allowed_tags );
}
