<?php

/**
 * LinkCentral Links Overview Class
 *
 * This class extends WP_List_Table to create a custom table for displaying and managing LinkCentral links.
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
// Exit if accessed directly
if ( !class_exists( 'WP_List_Table' ) ) {
    require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}
class LinkCentral_Links_Overview extends WP_List_Table {
    /**
     * URL prefix for links
     */
    private $url_prefix;

    /**
     * Search term storage for filters
     */
    private $search_term = '';

    /**
     * Per-page options
     */
    private $per_page_options = [
        20,
        50,
        100,
        200
    ];

    /**
     * Get preserved URL parameters (excluding status-specific ones)
     */
    private static function get_preserved_params( $exclude = [] ) {
        $params = $_GET;
        $default_exclude = ['post_status', 'filter_broken'];
        $exclude = array_merge( $default_exclude, $exclude );
        foreach ( $exclude as $param ) {
            unset($params[$param]);
        }
        return $params;
    }

    /**
     * Constructor
     */
    public function __construct() {
        parent::__construct( [
            'singular' => __( 'Link', 'linkcentral' ),
            'plural'   => __( 'Links', 'linkcentral' ),
            'ajax'     => false,
        ] );
        $this->url_prefix = get_option( 'linkcentral_url_prefix', 'go' );
    }

    /**
     * Define the columns for the links table
     */
    public function get_columns() {
        return [
            'cb'              => '<input type="checkbox" />',
            'title'           => __( 'Name', 'linkcentral' ),
            'slug'            => __( 'Short URL', 'linkcentral' ),
            'destination_url' => __( 'Destination', 'linkcentral' ),
            'category'        => __( 'Category', 'linkcentral' ),
            'clicks'          => __( 'Clicks', 'linkcentral' ),
            'date'            => __( 'Date Created', 'linkcentral' ),
        ];
    }

    /**
     * Define sortable columns for the table
     */
    public function get_sortable_columns() {
        return [
            'title'  => ['title', false],
            'date'   => 'date',
            'clicks' => 'clicks',
        ];
    }

    /**
     * Prepare the items for the table to process
     */
    public function prepare_items() {
        $per_page = $this->per_page_options[0];
        // Default to first option in array
        // Allow per_page to be overridden via URL parameter for quick changes
        if ( isset( $_GET['per_page'] ) && is_numeric( $_GET['per_page'] ) ) {
            $requested_per_page = intval( $_GET['per_page'] );
            // Validate against allowed options for security
            if ( in_array( $requested_per_page, $this->per_page_options ) ) {
                $per_page = $requested_per_page;
            }
        }
        $current_page = $this->get_pagenum();
        $post_status = ( isset( $_GET['post_status'] ) ? sanitize_key( wp_unslash( $_GET['post_status'] ) ) : 'any' );
        // Check for broken links filter
        $filter_broken = ( isset( $_GET['filter_broken'] ) ? sanitize_key( wp_unslash( $_GET['filter_broken'] ) ) : '' );
        // Handle search - prefer GET but allow POST for form compatibility
        $search_term = '';
        if ( isset( $_GET['s'] ) ) {
            $search_term = sanitize_text_field( wp_unslash( $_GET['s'] ) );
        } elseif ( isset( $_POST['s'] ) ) {
            $search_term = sanitize_text_field( wp_unslash( $_POST['s'] ) );
        }
        // Set up the query arguments
        $args = [
            'post_type'      => 'linkcentral_link',
            'posts_per_page' => $per_page,
            'paged'          => $current_page,
            'post_status'    => $post_status,
        ];
        // Add search functionality
        if ( !empty( $search_term ) ) {
            // Use custom search to search only in linkcentral_link posts
            add_filter(
                'posts_where',
                array($this, 'extend_search_where'),
                10,
                2
            );
            add_filter(
                'posts_join',
                array($this, 'extend_search_join'),
                10,
                2
            );
            add_filter(
                'posts_groupby',
                array($this, 'extend_search_groupby'),
                10,
                2
            );
            // Store search term for use in filters
            $this->search_term = $search_term;
        }
        // Handle sorting - default to title ASC
        $orderby = ( isset( $_GET['orderby'] ) ? sanitize_key( $_GET['orderby'] ) : 'title' );
        $order = ( isset( $_GET['order'] ) ? sanitize_key( $_GET['order'] ) : 'ASC' );
        // Map WordPress parameters
        $orderby = ( $orderby === 't' ? 'title' : (( $orderby === 'c' ? 'clicks' : $orderby )) );
        $order = strtoupper( $order );
        // Handle special cases
        if ( $orderby === 'clicks' ) {
            $args['meta_key'] = '_linkcentral_click_count';
            $args['orderby'] = 'meta_value_num';
            // Use WordPress's built-in numeric sorting
            $args['order'] = $order;
        } else {
            $args['orderby'] = $orderby;
            $args['order'] = $order;
        }
        $query = new WP_Query($args);
        // Remove filters after query
        if ( !empty( $search_term ) ) {
            remove_filter( 'posts_where', array($this, 'extend_search_where'), 10 );
            remove_filter( 'posts_join', array($this, 'extend_search_join'), 10 );
            remove_filter( 'posts_groupby', array($this, 'extend_search_groupby'), 10 );
        }
        $this->items = $query->posts;
        $total_items = $query->found_posts;
        // Set up pagination
        $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()];
    }

    /**
     * Extend search WHERE clause to include title, slug, and destination URL
     *
     * @param string $where The WHERE clause
     * @param WP_Query $query The WP_Query object
     * @return string Modified WHERE clause
     */
    public function extend_search_where( $where, $query ) {
        global $wpdb;
        if ( !empty( $this->search_term ) && $query->get( 'post_type' ) === 'linkcentral_link' ) {
            $search_term = '%' . $wpdb->esc_like( $this->search_term ) . '%';
            $where .= $wpdb->prepare(
                " AND (\n                ({$wpdb->posts}.post_title LIKE %s) OR \n                ({$wpdb->posts}.post_name LIKE %s) OR \n                (pm.meta_value LIKE %s)\n            )",
                $search_term,
                $search_term,
                $search_term
            );
        }
        return $where;
    }

    /**
     * Extend search JOIN clause to include postmeta table
     *
     * @param string $join The JOIN clause
     * @param WP_Query $query The WP_Query object
     * @return string Modified JOIN clause
     */
    public function extend_search_join( $join, $query ) {
        global $wpdb;
        // Only join postmeta table when we have a search term and we're querying links
        if ( !empty( $this->search_term ) && $query->get( 'post_type' ) === 'linkcentral_link' ) {
            $join .= " LEFT JOIN {$wpdb->postmeta} pm ON ({$wpdb->posts}.ID = pm.post_id AND pm.meta_key = '_linkcentral_destination_url')";
        }
        return $join;
    }

    /**
     * Extend search GROUP BY clause to avoid duplicate results
     *
     * @param string $groupby The GROUP BY clause
     * @param WP_Query $query The WP_Query object
     * @return string Modified GROUP BY clause
     */
    public function extend_search_groupby( $groupby, $query ) {
        global $wpdb;
        if ( !empty( $this->search_term ) && $query->get( 'post_type' ) === 'linkcentral_link' ) {
            $groupby = "{$wpdb->posts}.ID";
        }
        return $groupby;
    }

    /**
     * Default column rendering
     *
     * @param object $item Current item
     * @param string $column_name Name of the column
     * @return string
     */
    public function column_default( $item, $column_name ) {
        switch ( $column_name ) {
            case 'destination_url':
                $destination_url = get_post_meta( $item->ID, '_linkcentral_destination_url', true );
                $dynamic_rules = get_post_meta( $item->ID, '_linkcentral_dynamic_rules', true );
                $output = linkcentral_truncate_url( $destination_url );
                return $output;
            case 'category':
                return get_the_term_list(
                    $item->ID,
                    'linkcentral_category',
                    '',
                    ', ',
                    ''
                );
            case 'date':
                return get_the_date( 'd F Y', $item->ID );
            default:
                return __( 'Unavailable', 'linkcentral' );
        }
    }

    /**
     * Render the checkbox column
     *
     * @param object $item Current item
     * @return string
     */
    public function column_cb( $item ) {
        return sprintf( '<input type="checkbox" name="link[]" value="%s" />', $item->ID );
    }

    /**
     * Render the title column
     *
     * @param object $item Current item
     * @return string
     */
    public function column_title( $item ) {
        $edit_link = get_edit_post_link( $item->ID );
        $title = '<strong>';
        // Only add edit link if user has edit capability
        if ( current_user_can( 'linkcentral_create_edit_links' ) ) {
            $title .= '<a class="row-title" href="' . $edit_link . '">' . esc_html( $item->post_title ) . '</a>';
        } else {
            $title .= esc_html( $item->post_title );
        }
        $status = get_post_status( $item->ID );
        $status_object = get_post_status_object( $status );
        if ( $status !== 'publish' ) {
            if ( $status === 'draft' ) {
                $status_label = __( 'Draft (inactive)', 'linkcentral' );
            } else {
                $status_label = $status_object->label;
            }
            $title .= ' &mdash; <span class="linkcentral-post-state">' . $status_label . '</span>';
        }
        if ( $item->post_password ) {
            $title .= ' <span class="dashicons dashicons-lock" title="' . esc_attr__( 'Password protected', 'linkcentral' ) . '"></span>';
        }
        $title .= '</strong>';
        $actions = [
            'id' => sprintf( '<span class="linkcentral-post-id">ID: %d</span>', $item->ID ),
        ];
        if ( $status === 'trash' ) {
            if ( current_user_can( 'linkcentral_create_edit_links' ) ) {
                $actions['untrash'] = sprintf( '<a href="%s">%s</a>', wp_nonce_url( admin_url( sprintf( 'admin.php?page=linkcentral&action=untrash&link=%d', $item->ID ) ), 'untrash-link_' . $item->ID ), __( 'Untrash', 'linkcentral' ) );
                $actions['delete'] = sprintf(
                    '<a href="%s" class="submitdelete" onclick="return confirm(\'%s\');">%s</a>',
                    get_delete_post_link( $item->ID, '', true ),
                    esc_js( __( 'You are about to permanently delete this link. This action cannot be undone. Are you sure?', 'linkcentral' ) ),
                    __( 'Delete Permanently', 'linkcentral' )
                );
            }
        } else {
            if ( current_user_can( 'linkcentral_create_edit_links' ) ) {
                $actions['edit'] = sprintf( '<a href="%s">%s</a>', $edit_link, __( 'Edit', 'linkcentral' ) );
                $actions['trash'] = sprintf( '<a href="%s">%s</a>', get_delete_post_link( $item->ID ), __( 'Trash', 'linkcentral' ) );
            }
        }
        return $title . $this->row_actions( $actions );
    }

    /**
     * Render the slug column
     *
     * @param object $item Current item
     * @return string
     */
    public function column_slug( $item ) {
        $short_url = linkcentral_get_link_url( $item->ID, $item->post_name );
        return sprintf(
            '%s <button class="button button-small linkcentral-copy-url" data-url="%s">%s</button>',
            $short_url,
            esc_attr( $short_url ),
            __( 'Copy', 'linkcentral' )
        );
    }

    /**
     * Render the clicks column
     *
     * @param object $item Current item
     * @return string
     */
    public function column_clicks( $item ) {
        $click_count = $this->get_click_count( $item->ID );
        // Update the click count in post meta for sorting
        update_post_meta( $item->ID, '_linkcentral_click_count', $click_count );
        return sprintf( '<span class="linkcentral-click-count" data-link-id="%d">%d</span>', $item->ID, $click_count );
    }

    /**
     * Get the click count for a specific link
     *
     * @param int $link_id Link ID
     * @return int
     */
    private function get_click_count( $link_id ) {
        global $wpdb;
        return (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM `{$wpdb->prefix}linkcentral_stats` WHERE link_id = %d", $link_id ) );
    }

    /**
     * Define bulk actions
     *
     * @return array
     */
    public function get_bulk_actions() {
        $actions = [];
        $post_status = ( isset( $_GET['post_status'] ) ? sanitize_key( wp_unslash( $_GET['post_status'] ) ) : 'any' );
        if ( $post_status === 'trash' ) {
            $actions['untrash'] = __( 'Untrash', 'linkcentral' );
            $actions['delete'] = __( 'Delete Permanently', 'linkcentral' );
        } else {
            $actions['trash'] = __( 'Move to Trash', 'linkcentral' );
        }
        return $actions;
    }

    /**
     * Generate views for different post statuses
     *
     * @return array
     */
    protected function get_views() {
        $current_params = self::get_preserved_params();
        $status_links = array();
        $num_posts = wp_count_posts( 'linkcentral_link', 'readable' );
        $class = '';
        $allposts = '';
        // Calculate total posts excluding 'trash' and 'auto-draft'
        $total_posts = array_sum( (array) $num_posts ) - $num_posts->trash - $num_posts->{'auto-draft'};
        $class = ( empty( $class ) && empty( $_GET['post_status'] ) && empty( $_GET['filter_broken'] ) ? ' class="current"' : '' );
        $all_text = __( 'All', 'linkcentral' );
        $all_url = add_query_arg( $current_params, admin_url( 'admin.php?page=linkcentral' ) );
        $status_links['all'] = sprintf(
            '<a href="%s"%s>%s <span class="count">(%s)</span></a>',
            esc_url( $all_url ),
            $class,
            $all_text,
            number_format_i18n( $total_posts )
        );
        $statuses = get_post_stati( array(
            'show_in_admin_status_list' => true,
        ), 'objects' );
        if ( $statuses ) {
            foreach ( $statuses as $status ) {
                $class = '';
                $status_name = $status->name;
                if ( !in_array( $status_name, array(
                    'publish',
                    'draft',
                    'pending',
                    'trash',
                    'future',
                    'private',
                    'auto-draft'
                ) ) ) {
                    continue;
                }
                if ( empty( $num_posts->{$status_name} ) ) {
                    continue;
                }
                if ( isset( $_GET['post_status'] ) && $status_name === $_GET['post_status'] ) {
                    $class = ' class="current"';
                }
                $status_params = array_merge( $current_params, [
                    'post_status' => $status_name,
                ] );
                $url = add_query_arg( $status_params, admin_url( 'admin.php?page=linkcentral' ) );
                $count = number_format_i18n( $num_posts->{$status_name} );
                // Use WordPress core's translate_nooped_plural function for proper translation
                $status_label = sprintf( translate_nooped_plural( $status->label_count, $num_posts->{$status_name} ), $count );
                $status_links[$status_name] = sprintf(
                    '<a href="%s"%s>%s</a>',
                    esc_url( $url ),
                    $class,
                    $status_label
                );
            }
        }
        return $status_links;
    }

    /**
     * Get current per-page value with validation
     */
    private function get_current_per_page() {
        $per_page = ( isset( $_GET['per_page'] ) ? intval( $_GET['per_page'] ) : $this->per_page_options[0] );
        // Validate against allowed options for security
        return ( in_array( $per_page, $this->per_page_options ) ? $per_page : $this->per_page_options[0] );
    }

    /**
     * Add per-page selector to bottom navigation
     */
    protected function extra_tablenav( $which ) {
        if ( $which === 'bottom' ) {
            $current_per_page = $this->get_current_per_page();
            ?>
            <div class="alignright">
                <select class="linkcentral-per-page-selector" onchange="linkcentralChangePerPage(this.value)">
                    <?php 
            foreach ( $this->per_page_options as $option ) {
                ?>
                        <option value="<?php 
                echo esc_attr( $option );
                ?>" <?php 
                selected( $current_per_page, $option );
                ?>>
                            <?php 
                echo esc_html( $option );
                ?> <?php 
                esc_html_e( 'per page', 'linkcentral' );
                ?>
                        </option>
                    <?php 
            }
            ?>
                </select>
            </div>
            <?php 
        }
        parent::extra_tablenav( $which );
    }

    /**
     * Render the main links overview page
     */
    public static function render_all_links_page() {
        $list_table = new self();
        $list_table->prepare_items();
        $post_status = ( isset( $_GET['post_status'] ) ? sanitize_key( wp_unslash( $_GET['post_status'] ) ) : 'any' );
        $current_params = self::get_preserved_params();
        $trash_url = add_query_arg( array_merge( $current_params, [
            'post_status' => 'trash',
        ] ), admin_url( 'admin.php?page=linkcentral' ) );
        $all_url = add_query_arg( $current_params, admin_url( 'admin.php?page=linkcentral' ) );
        // Display admin notices
        self::display_admin_notices();
        include LINKCENTRAL_PLUGIN_DIR . 'views/links-overview-page.php';
    }

    /**
     * Initialize the class
     */
    public static function init() {
        add_action( 'admin_init', array(__CLASS__, 'process_bulk_action') );
    }

    /**
     * Process bulk actions
     */
    public static function process_bulk_action() {
        if ( !isset( $_REQUEST['page'] ) || $_REQUEST['page'] !== 'linkcentral' ) {
            return;
        }
        $list_table = new self();
        $action = $list_table->current_action();
        if ( empty( $action ) ) {
            return;
        }
        // Check nonce for all actions
        $nonce = ( isset( $_REQUEST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) : '' );
        if ( !wp_verify_nonce( $nonce, 'bulk-' . $list_table->_args['plural'] ) && !wp_verify_nonce( $nonce, 'untrash-link_' . (( isset( $_REQUEST['link'] ) ? absint( $_REQUEST['link'] ) : '' )) ) ) {
            wp_die( 'Security check failed' );
        }
        $post_ids = [];
        if ( isset( $_REQUEST['link'] ) && wp_verify_nonce( $nonce, 'bulk-' . $list_table->_args['plural'] ) ) {
            $post_ids = ( is_array( $_REQUEST['link'] ) ? array_map( 'intval', $_REQUEST['link'] ) : [intval( $_REQUEST['link'] )] );
        }
        // Handle individual untrash action
        if ( $action === 'untrash' && isset( $_REQUEST['link'] ) && wp_verify_nonce( $nonce, 'untrash-link_' . absint( $_REQUEST['link'] ) ) ) {
            $post_ids = [intval( $_REQUEST['link'] )];
        }
        if ( empty( $post_ids ) ) {
            return;
        }
        $current_url = add_query_arg( array() );
        // Get current URL with all parameters
        $redirect_url = remove_query_arg( ['action', 'link', '_wpnonce'], $current_url );
        // Remove action-related parameters
        $processed_count = 0;
        switch ( $action ) {
            case 'trash':
                foreach ( $post_ids as $post_id ) {
                    if ( wp_trash_post( $post_id ) ) {
                        $processed_count++;
                    }
                }
                $redirect_url = add_query_arg( 'trashed', $processed_count, $redirect_url );
                break;
            case 'untrash':
                foreach ( $post_ids as $post_id ) {
                    if ( wp_untrash_post( $post_id ) ) {
                        $processed_count++;
                    }
                }
                $redirect_url = add_query_arg( 'untrashed', $processed_count, $redirect_url );
                break;
            case 'delete':
                foreach ( $post_ids as $post_id ) {
                    if ( wp_delete_post( $post_id, true ) ) {
                        $processed_count++;
                    }
                }
                $redirect_url = add_query_arg( 'deleted', $processed_count, $redirect_url );
                break;
        }
        // Perform the redirect
        wp_safe_redirect( $redirect_url );
        exit;
    }

    /**
     * Display admin notices for bulk actions
     */
    private static function display_admin_notices() {
        $messages = array(
            'trashed'   => array(
                'singular' => __( '%s link moved to the Trash.', 'linkcentral' ),
                'plural'   => __( '%s links moved to the Trash.', 'linkcentral' ),
                'type'     => 'updated',
            ),
            'untrashed' => array(
                'singular' => __( '%s link restored from the Trash.', 'linkcentral' ),
                'plural'   => __( '%s links restored from the Trash.', 'linkcentral' ),
                'type'     => 'updated',
            ),
            'deleted'   => array(
                'singular' => __( '%s link permanently deleted.', 'linkcentral' ),
                'plural'   => __( '%s links permanently deleted.', 'linkcentral' ),
                'type'     => 'updated',
            ),
        );
        foreach ( $messages as $key => $message ) {
            if ( isset( $_REQUEST[$key] ) && wp_verify_nonce( wp_create_nonce( 'linkcentral_admin_notice' ), 'linkcentral_admin_notice' ) ) {
                $count = intval( $_REQUEST[$key] );
                $text = ( $count === 1 ? $message['singular'] : $message['plural'] );
                $notice = sprintf( $text, number_format_i18n( $count ) );
                echo "<div class='notice " . esc_attr( $message['type'] ) . " is-dismissible'><p>" . esc_html( $notice ) . "</p></div>";
            }
        }
    }

}
