<?php
declare(strict_types=1);

namespace EHxMe\Classes;

if (!defined('ABSPATH')) {
    exit;
}

use EHxMe\Helpers\Helper;
use EHxMe\Models\Payment;
use EHxMe\Services\Request;
use WP_List_Table;
 
class PaymentDataTable extends WP_List_Table 
{
    /**
     * Constructor for the Payment_Data_Table class.
     *
     * Initializes the parent class and sets up the necessary properties.
     *
     * @param array $args Arguments for the WP_List_Table class constructor.
     */
    public function __construct() 
    {
        parent::__construct([
            'singular' => 'Payment',
            'plural'   => 'Payments',
            'ajax'     => false
        ]);
    }
        
    /**
     * Get the columns for the list table.
     *
     * @return array An associative array where the keys are the column slugs and the values are the column names.
     */
    public function get_columns(): array 
    {
        return [
            'cb' => '<input type="checkbox" />',
            'display_name' => 'Username',
            'amount' => 'Amount',
            'charge' => 'Charge',
            'method' => 'Payment Method',
            'status' => 'Status',
            'created_at' => 'Created At'
        ];
    }
        
    /**
     * Get the sortable columns for the list table.
     *
     * @return array An associative array where the keys are the column slugs and the values are arrays containing the column name and a boolean indicating whether the column is sortable.
     *
     * @since 1.0.0
     */
    public function get_sortable_columns(): array 
    {
        return [
            'display_name'  => ['display_name', false],
            'amount'     => ['amount', false],
            'status'     => ['status', false],
            'created_at' => ['created_at', false]
        ];
    }
        
    /**
     * Generate the checkbox HTML for the list table.
     *
     * This function generates the HTML for a checkbox input element that will be used in the list table.
     * The checkbox is used for selecting multiple items for bulk actions.
     *
     * @param array $item An associative array representing a single row in the list table.
     *                    The array should contain the 'id' key, which corresponds to the transaction ID.
     *
     * @return string The HTML for the checkbox input element.
     */
    public function column_cb($item): string 
    {
        return sprintf('<input type="checkbox" name="transaction[]" value="%s" />', $item['id']);
    }
        
    /**
     * Handles the output for the default columns in the list table.
     *
     * This function is called when the default columns are being displayed in the list table.
     * It checks the column name and returns the appropriate value based on the column.
     *
     * @param array $item An associative array representing a single row in the list table.
     *                    The array should contain the column slugs as keys and their corresponding values.
     * @param string $column_name The name of the column being displayed.
     *
     * @return mixed The value to be displayed in the specified column.
     */
    public function column_default($item, $column_name): mixed 
    {
        switch ($column_name) {
            case 'display_name':

                $delete_link = Helper::generateQueryArg(['action' => 'ehxme_payments_delete', 'page' => AdminMenuHandler::$pages['payment'], 'id' => $item['id']]);

                $actions = [
                    'delete' => '<a href="' . esc_url($delete_link) . '" onclick="return confirm(\'Are you sure?\')">Delete</a>',
                ];

                return $item[$column_name] . $this->row_actions($actions);
            case 'status':
                $status_classes = [
                    'pending' => 'background: orange; color: white; padding: 4px 8px; border-radius: 4px;',
                    'success' => 'background: green; color: white; padding: 4px 8px; border-radius: 4px;',
                    'cancel'  => 'background: red; color: white; padding: 4px 8px; border-radius: 4px;',
                ];
                return sprintf('<span style="%s">%s</span>', $status_classes[$item[$column_name]], ucfirst($item[$column_name]));
            case 'amount':
            case 'charge':
                return Helper::currencyFormat($item[$column_name] ?? 0);
            default:
                return $item[$column_name];
        }
    }
    
    /**
     * Handles the output for the extra navigation bar at the top of the list table.
     *
     * This function generates the HTML for the extra navigation bar at the top of the list table.
     * It includes dropdown filters for users and payment statuses.
     *
     * @param string $which The context for the extra table navigation.
     *                      It can be either 'top' or 'bottom'.
     *
     * @return void
     */
    public function extra_tablenav($which): void 
    {
        if ($which === 'top') {
            $users = get_users([
                'fields'  => ['ID', 'display_name'],
                'orderby' => 'display_name',
                'order'   => 'ASC'
            ]);
            
            $selected_user = Request::getInput('filter_user');
            $selected_status = Request::getInput('filter_status');
            ?>
            <div class="alignleft actions">
                <input type="hidden" name="page" value="<?php echo esc_html(AdminMenuHandler::$pages['payment']); ?>">

                <input type="hidden" name="<?php echo esc_html(Helper::NONCE_NAME) ?>" value="<?php echo esc_html(wp_create_nonce(Helper::NONCE_NAME)) ?>">

                <!-- User Filter -->
                <select name="filter_user">
                    <option value="">All Users</option>
                    <?php foreach ($users as $user) : ?>
                        <option value="<?php echo esc_attr($user->ID); ?>" <?php selected($selected_user, $user->ID); ?>>
                            <?php echo esc_html($user->display_name); ?>
                        </option>
                    <?php endforeach; ?>
                </select>
    
                <!-- Status Filter -->
                <select name="filter_status">
                    <option value="">All Statuses</option>
                    <option value="pending" <?php selected($selected_status, 'pending'); ?>>Pending</option>
                    <option value="success" <?php selected($selected_status, 'success'); ?>>Success</option>
                    <option value="cancel" <?php selected($selected_status, 'cancel'); ?>>Cancel</option>
                </select>
    
                <input type="submit" class="button" value="Filter">
            </div>
            <?php
        }
    } 

    /**
     * Prepares the items to be displayed in the list table.
     *
     * This function retrieves the necessary data from the database, applies filters and sorting,
     * and sets up pagination for the list table. It then populates the items property with the
     * retrieved data.
     *
     * @return void
     */
    public function prepare_items(): void 
    {
        // Get query results and pagination parameters
        [$data, $per_page, $total_items] = $this->get_query_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()];
        $this->items = $data;
    }
    
    /**
     * Get paginated payment results with filters and sorting
     * 
     * @return array [$data, $per_page, $total_items]
     */
    public function get_query_results()
    {
        // Set up base query with table alias
        $payment = new Payment();
        $payment->table(Payment::$table, 'p')
            ->select(['p.*', 'u.display_name','u.user_email'])
            ->join('users', 'u.ID', '=', 'p.user_id', 'u');

        // Apply filters
        $filter_user = Request::getInput('filter_user');
        $filter_status = Request::getInput('filter_status');

        if ($filter_user) {
            $payment->where('p.user_id', (int) $filter_user);
        }

        if ($filter_status) {
            $payment->where('p.status', $filter_status);
        }

        // Handle sorting
        $valid_orderby = [
            'id' => 'p.id',
            'display_name' => 'u.display_name',
            'email' => 'u.user_email',
            'amount' => 'p.amount',
            'charge' => 'p.charge',
            'payment_method' => 'p.method',
            'created_at' => 'p.created_at',
            'status' => 'p.status'
        ];

        $orderby = $valid_orderby[Request::getInput('orderby', 'id')] ?? 'p.id';
        $order_input = strtoupper(Request::getInput('order', 'DESC'));
        $order = in_array($order_input, ['ASC', 'DESC']) ? $order_input : 'DESC';

        $payment->orderBy($orderby, $order);

        // Get total count before pagination
        $total_items = $payment->getCount();

        // Handle pagination
        $per_page = Request::getInput('per_page', 10);
        $current_page = $this->get_pagenum();
        $offset = ($current_page - 1) * $per_page;

        if ($per_page !== -1) {
            $payment->limit($per_page)->offset($offset);
        }

        // Execute query and format results
        $data = $payment->get(ARRAY_A);

        return [
            $data,
            $per_page,
            $total_items,
            $current_page
        ];
    }
    
    /**
     * Retrieves payment data for the current user.
     *
     * This function connects to the WordPress database, retrieves payment data for the current user,
     * and returns the data as an array of associative arrays.
     *
     * @return array
     */
    public static function getData(): array|object
    {
        global $wpdb;
        $payment_table = esc_sql((new Payment)->getTableName());

        // Query: Join with wp_users and wp_usermeta
        $query = $wpdb->prepare("SELECT * FROM %1s WHERE user_id = %d ORDER BY id DESC", $payment_table, get_current_user_id());

        $data = $wpdb->get_results($query);

        return $data ?? [];
    }

}