<?php
/**
 * Custom List Table for displaying data in a table format in WordPress plugin.
 *
 * @link       https://personalizewp.com/
 * @since      3.2.0 Merged into PWP
 * @since      1.1.0
 *
 * @package    PersonalizeWP
 * @subpackage PersonalizeWP/Admin
 */

namespace PersonalizeWP\Admin;

defined( 'ABSPATH' ) || exit; // Exit if accessed directly.

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

/**
 * Custom List Table for displaying data in a table format in WordPress plugin.
 */
class ListTableScoringRules extends \WP_List_Table {

	/**
	 * The screen name.
	 *
	 * @since 1.1.0
	 *
	 * @var string
	 */
	public $screen_id = 'pwp_scoring_rules';

	/**
	 * Default number of items per page
	 *
	 * @since 1.1.0
	 *
	 * @var int
	 */
	const ITEMS_PER_PAGE = 20;

	/**
	 * Class constructor
	 *
	 * @since 1.1.0
	 */
	public function __construct() {
		parent::__construct(
			[
				'singular' => 'scoring_rule',
				'plural'   => 'scoring_rules',
				'ajax'     => false,
				'screen'   => $this->screen_id,
			]
		);
	}

	/**
	 * Retrieve the table columns.
	 *
	 * @since 1.1.0
	 *
	 * @return array Associative array of table columns with column name as key and column title as value.
	 */
	public function get_columns() {
		return [
			'name'       => __( 'Name', 'personalizewp' ),
			'type'       => __( 'Type', 'personalizewp' ),
			'conditions' => __( 'Item', 'personalizewp' ),
			'lead_score' => __( 'Score Value', 'personalizewp' ),
		];
	}

	/**
	 * Get sortable columns
	 *
	 * @since 1.1.0
	 *
	 * @return array
	 */
	protected function get_sortable_columns() {
		return [
			'name'       => [ 'name', true, __( 'Name', 'personalizewp' ), __( 'Table ordered by Name.', 'personalizewp' ), 'asc' ],
			'lead_score' => [ 'lead_score', false ],
		];
	}

	/**
	 * Gets the name of the default primary column.
	 *
	 * @since 1.1.0
	 *
	 * @return string Name of the default primary column, in this case, 'name'.
	 */
	protected function get_default_primary_column_name() {
		return 'name';
	}

	/**
	 * Handles the scoring rule type column output.
	 *
	 * @since 1.1.0
	 *
	 * @param array $item Scoring Rule
	 *
	 * @return string
	 */
	protected function column_type( $item ) {
		return esc_html( PageScoringRules::translate_type( $item['type'] ) );
	}

	/**
	 * Handles the scoring rule conditions column output.
	 *
	 * @since 1.1.0
	 *
	 * @param array $item Scoring Rule
	 *
	 * @return string
	 */
	protected function column_conditions( $item ) {
		return esc_html( PageScoringRules::translate_conditions( $item['conditions'], $item['type'] ) );
	}

	/**
	 * Generates and displays row action links.
	 *
	 * @since 1.1.0
	 *
	 * @param array  $item        Item being acted upon.
	 * @param string $column_name Current column name.
	 * @param string $primary     Primary column name.
	 *
	 * @return string Row actions output for Scoring rule, or an empty string if the current column is not the primary column.
	 */
	protected function handle_row_actions( $item, $column_name, $primary ) {
		if ( $primary !== $column_name ) {
			return '';
		}

		$actions = array();

		$actions['edit'] = sprintf(
			'<a href="%s" aria-label="%s" rel="bookmark">%s</a>',
			admin_url( PageScoringRules::$edit_url . $item['ID'] ),
			/* translators: %s: Scoring rule name. */
			esc_attr( sprintf( _x( 'Edit &#8220;%s&#8221;', 'Scoring rule name', 'personalizewp' ), $item['name'] ) ),
			esc_html__( 'Edit', 'personalizewp' )
		);

		$actions['delete'] = sprintf(
			'<a class="trash" data-show-modal="#deleteScoringRuleModal" href="%s" aria-label="%s">%s</a>',
			wp_nonce_url( admin_url( PageScoringRules::$delete_url . $item['ID'] ), 'delete-scoring-rule-' . $item['ID'] ),
			/* translators: %s: Scoring rule name. */
			esc_attr( sprintf( _x( 'Delete &#8220;%s&#8221;', 'Scoring rule name', 'personalizewp' ), $item['name'] ) ),
			esc_html__( 'Delete', 'personalizewp' )
		);

		return $this->row_actions( $actions );
	}

	/**
	 * Default column renderer
	 *
	 * @since 1.1.0
	 *
	 * @param array  $item        Scoring rule
	 * @param string $column_name List table column
	 *
	 * @return mixed
	 */
	protected function column_default( $item, $column_name ) {
		$col = '';
		switch ( $column_name ) {
			case 'name':
				$col = sprintf(
					'<a href="%s" aria-label="%s" rel="bookmark">%s</a>',
					admin_url( PageScoringRules::$edit_url . $item['ID'] ),
					/* translators: %s: Scoring rule name. */
					esc_attr( sprintf( _x( 'Edit &#8220;%s&#8221;', 'Scoring rule name', 'personalizewp' ), $item['name'] ) ),
					esc_html( $item['name'] )
				);
				break;

			default:
				$col = esc_html( $item[ $column_name ] );
				break;
		}
		return $col;
	}

	/**
	 * Generates the table navigation above or below the table
	 *
	 * Overridden to remove bulk actions and nonces
	 *
	 * @since 1.1.0
	 *
	 * @param string $which Top or bottom of table
	 *
	 * @return void
	 */
	protected function display_tablenav( $which ) {
		?>
	<div class="tablenav <?php echo esc_attr( $which ); ?>">

		<?php
		$this->pagination( $which );
		?>

	</div>
		<?php
	}

	/**
	 * Displays the search box.
	 *
	 * @since 1.1.0
	 *
	 * @param string $text     The 'submit' button label.
	 * @param string $input_id ID attribute value for the search input field.
	 */
	public function search_box( $text, $input_id ) {

		$page   = isset( $_REQUEST['page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: nonce verification not required
		$search = isset( $_REQUEST['search'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['search'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: nonce verification not required
		?>
		<p class="search-box">
			<input type="hidden" name="page" value="<?php echo esc_attr( $page ); ?>" />
			<label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_html( $text ); ?>:</label>
			<input type="text" class="search-icon" id="<?php echo esc_attr( $input_id ); ?>" name="search" value="<?php echo esc_attr( $search ); ?>"
				placeholder="<?php esc_html_e( 'Search name or type', 'personalizewp' ); ?>" />
			<input type="submit" class="secondary btn" value="<?php echo esc_html( $text ); ?>" />
		</p>
		<?php
	}

	/**
	 * Prepare the table items. Retrieves and sets the data for the table.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	public function prepare_items() {
		global $wpdb;

		$where = '';
		// Process Searching
		$search = isset( $_REQUEST['search'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['search'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( $search ) {
			$search_cols    = array(
				'name',
				'type',
				'conditions',
			);
			$search_clauses = array();

			foreach ( $search_cols as $col ) {
				$search_clauses[] = $wpdb->prepare( '%i LIKE %s', $col, '%' . $wpdb->esc_like( $search ) . '%' );
			}
			$where .= ' AND (' . implode( ' OR ', $search_clauses ) . ')';
		}

		// Process Ordering
		$orderby = 'name'; // Default when not custom
		if ( ! empty( $_GET['orderby'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: verified elsewhere
			$_orderby = sanitize_text_field( wp_unslash( $_GET['orderby'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: verified elsewhere
			$parsed   = $this->parse_orderby( $_orderby );
			if ( $parsed ) {
				$orderby = $parsed;
			}
		}
		$order   = ! empty( $_GET['order'] ) ? sanitize_text_field( wp_unslash( $_GET['order'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: verified elsewhere
		$order   = $this->parse_order( $order );
		$orderby = 'ORDER BY ' . $orderby . ' ' . $order;

		// Process pagination
		$per_page = $this->get_items_per_page( "edit_{$this->screen_id}_per_page" );
		$page     = $this->get_pagenum();
		$offset   = absint( ( $page - 1 ) * $per_page ) . ', ';
		$limits   = 'LIMIT ' . $offset . $per_page;

		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: custom db table
		// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: inputs sanitised/validated above
		// Get the results from the options above
		$this->items = $wpdb->get_results(
			"SELECT SQL_CALC_FOUND_ROWS * FROM {$wpdb->prefix}pwp_scoring_rules WHERE 1=1 $where $orderby $limits", // nosemgrep: audit.php.wp.security.sqli.input-in-sinks -- Reason: inputs sanitised/validated above
			ARRAY_A
		);
		// phpcs:enable

		$total_items = (int) $wpdb->get_var( 'SELECT FOUND_ROWS()' );

		$this->set_pagination_args(
			array(
				'total_items' => $total_items,
				'per_page'    => $per_page,
			)
		);
	}

	/**
	 * Validates that the 'orderby' is valid
	 *
	 * @since 1.1.0
	 *
	 * @param string $orderby The 'orderby' query variable.
	 * @return string The sanitized 'orderby' query variable.
	 */
	protected function parse_orderby( $orderby ) {

		$orderby = strtolower( $orderby );

		// Used to filter values.
		$allowed_keys = array_keys( $this->get_sortable_columns() );

		if ( ! in_array( $orderby, $allowed_keys, true ) ) {
			return false;
		}

		return $orderby;
	}

	/**
	 * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
	 *
	 * @since 1.1.0
	 *
	 * @param string $order The 'order' query variable.
	 * @return string The sanitized 'order' query variable.
	 */
	protected function parse_order( $order ) {
		if ( ! is_string( $order ) || empty( $order ) ) {
			return 'ASC';
		}

		if ( 'ASC' === strtoupper( $order ) ) {
			return 'ASC';
		} else {
			return 'DESC';
		}
	}
}
