<?php
/**
 * Pre-Order orders list table.
 *
 * @package  YITH\PreOrder\Admin
 */

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

require_once ABSPATH . 'wp-admin/includes/class-wp-posts-list-table.php';

/**
 * YITH_Pre_Order_Products_List Class.
 */
class YITH_Pre_Order_Orders_List extends WP_Posts_List_Table {

	/**
	 * The post type.
	 *
	 * @var string
	 */
	protected $post_type = '';

	/**
	 * The number of posts per page for the list table.
	 *
	 * @var string
	 */
	public $posts_per_page = 30;

	/**
	 * Construct
	 *
	 * @param array  $args      An associative array of arguments.
	 * @param string $post_type The post type.
	 */
	public function __construct( $args, $post_type ) {
		parent::__construct( $args );
		$this->post_type = $post_type;
		add_action( 'pre_get_posts', array( $this, 'alter_orders_query' ) );
		add_filter( "manage_edit-shop_order_columns", array( $this, 'define_columns' ) );

	}

	/**
	 * Define which columns to show on this screen.
	 *
	 * @param array $columns Existing columns.
	 * @return array
	 */
	public function define_columns( $columns ) {
		$show_columns                     = array();
		$show_columns['cb']               = $columns['cb'];
		$show_columns['order_number']     = _x( 'Order', 'Column name for WooCommerce orders', 'yith-pre-order-for-woocommerce' );
		$show_columns['order_date']       = __( 'Order date', 'yith-pre-order-for-woocommerce' );
		$show_columns['order_status']     = __( 'Order status', 'yith-pre-order-for-woocommerce' );
		$show_columns['customer']         = __( 'Customer', 'yith-pre-order-for-woocommerce' );
		$show_columns['ywpo_products']    = __( 'Products', 'yith-pre-order-for-woocommerce' );
		$show_columns['ywpo_status']      = __( 'Pre-order status', 'yith-pre-order-for-woocommerce' );
		$show_columns['order_total']      = __( 'Total', 'yith-pre-order-for-woocommerce' );
		$show_columns['ywpo_charge_type'] = __( 'Payment type', 'yith-pre-order-for-woocommerce' );
		$show_columns['ywpo_payment']     = __( 'Payment status', 'yith-pre-order-for-woocommerce' );
		$show_columns['ywpo_actions']     = '';

		return $show_columns;
	}

	/**
	 * Add the 'meta_key' and 'meta_value' for identifying orders that contain pre-order items.
	 *
	 * @param WP_Query $query The WP_Query instance (passed by reference).
	 */
	public function alter_orders_query( $query ) {
		if ( $query->is_main_query() ) {
			$query->set( 'meta_key', '_order_has_preorder' );
			$query->set( 'meta_value', 'yes' );
		}
	}

	/**
	 * Prepares the list of items for displaying.
	 */
	public function prepare_items() {
		global $mode, $avail_post_stati, $wp_query, $per_page;

		if ( ! empty( $_REQUEST['mode'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$mode = 'excerpt' === $_REQUEST['mode'] ? 'excerpt' : 'list'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.WP.GlobalVariablesOverride.Prohibited
			set_user_setting( 'posts_list_mode', $mode );
		} else {
			$mode = get_user_setting( 'posts_list_mode', 'list' ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
		}
		$post_type = $this->post_type;

		// Is going to call wp().
		$avail_post_stati = wp_edit_posts_query( // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
			array(
				'post_type'   => $post_type,
				'post_status' => isset( $_REQUEST['post_status'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['post_status'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			)
		);

		$this->set_hierarchical_display( is_post_type_hierarchical( $post_type ) && 'menu_order title' === $wp_query->query['orderby'] );

		$per_page = $this->get_items_per_page( 'edit_' . $post_type . '_per_page' ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
		if ( empty( $per_page ) ) {
			$per_page = $this->posts_per_page; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
		}

		/** This filter is based on the "edit_posts_per_page" filter, documented in wp-admin/includes/post.php */
		$per_page = apply_filters( 'ywpo_orders_list_edit_posts_per_page', $per_page, $post_type ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited

		if ( $this->hierarchical_display ) {
			$total_items = $wp_query->post_count;
		} elseif ( $wp_query->found_posts || $this->get_pagenum() === 1 ) {
			$total_items = $wp_query->found_posts;
		} else {
			$post_counts = (array) wp_count_posts( $post_type, 'readable' );

			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
			if ( isset( $_REQUEST['post_status'] ) && in_array( $_REQUEST['post_status'], $avail_post_stati, true ) ) {
				$total_items = $post_counts[ $_REQUEST['post_status'] ]; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
			} else {
				$total_items = array_sum( $post_counts );
				// Subtract post types that are not included in the admin all list.
				foreach ( get_post_stati( array( 'show_in_admin_all_list' => false ) ) as $state ) {
					$total_items -= $post_counts[ $state ];
				}
			}
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended

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

	/**
	 * Gets a list of CSS classes for the WP_List_Table table tag.
	 *
	 * @return array
	 */
	protected function get_table_classes() {
		global $mode;

		$mode_class = esc_attr( 'table-view-' . $mode );

		return array( 'widefat', 'fixed', 'striped', $mode_class, is_post_type_hierarchical( $this->screen->post_type ) ? 'pages' : 'posts', 'yith-plugin-fw__classic-table' );
	}

	/**
	 * Gets a list of sortable columns.
	 *
	 * @return array
	 */
	protected function get_sortable_columns() {
		return array(
			'name' => array( 'name', false ),
		);
	}

	/**
	 * Get views.
	 *
	 * @global array $locked_post_status This seems to be deprecated.
	 * @global array $avail_post_stati
	 * @return array
	 */
	protected function get_views() {
		global $locked_post_status, $avail_post_stati, $wp_query;

		$post_type = $this->post_type;

		if ( ! empty( $locked_post_status ) ) {
			return array();
		}

		$status_links = array();
		$num_posts    = $this->count_posts( $post_type, 'readable' );
		$total_posts  = array_sum( (array) $num_posts );
		$class        = '';

		$current_user_id = get_current_user_id();
		$all_args        = array(
			'page'    => 'yith_wcpo_panel',
			'tab'     => 'pre-orders',
			'sub_tab' => 'orders',
		);

		// Subtract post types that are not included in the admin all list.
		foreach ( get_post_stati( array( 'show_in_admin_all_list' => false ) ) as $state ) {
			$total_posts -= $num_posts->$state;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( empty( $class ) && ( $this->is_base_request() || isset( $_REQUEST['all_posts'] ) ) ) {
			$class = 'current';
		}

		$all_inner_html = sprintf(
		/* translators: %s: Number of posts. */
			_nx(
				'All <span class="count">(%s)</span>',
				'All <span class="count">(%s)</span>',
				$total_posts,
				'posts'
			),
			number_format_i18n( $total_posts )
		);

		$status_links['all'] = $this->get_link( $all_args, $all_inner_html, $class );

		foreach ( get_post_stati( array( 'show_in_admin_status_list' => true ), 'objects' ) as $status ) {
			$class = '';

			$status_name = $status->name;

			if ( ! in_array( $status_name, $avail_post_stati, true ) || empty( $num_posts->$status_name ) ) {
				continue;
			}

			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
			if ( isset( $_REQUEST['post_status'] ) && $status_name === $_REQUEST['post_status'] ) {
				$class = 'current';
			}

			$status_args = array(
				'page'        => 'yith_wcpo_panel',
				'tab'         => 'pre-orders',
				'sub_tab'     => 'orders',
				'post_status' => $status_name,
			);

			$status_label = sprintf(
				translate_nooped_plural( $status->label_count, $num_posts->$status_name ),
				number_format_i18n( $num_posts->$status_name )
			);

			$status_links[ $status_name ] = $this->get_link( $status_args, $status_label, $class );
		}

		return $status_links;
	}

	/**
	 * Count number of posts of a post type and if user has permissions to view.
	 *
	 * This function provides an efficient method of finding the amount of post's
	 * type a blog has. Another method is to count the amount of items in
	 * get_posts(), but that method has a lot of overhead with doing so. Therefore,
	 * when developing for 2.5+, use this function instead.
	 *
	 * The $perm parameter checks for 'readable' value and if the user can read
	 * private posts, it will display that for the user that is signed in.
	 *
	 * @since 2.5.0
	 *
	 * @global wpdb $wpdb WordPress database abstraction object.
	 *
	 * @param string $type Optional. Post type to retrieve count. Default 'post'.
	 * @param string $perm Optional. 'readable' or empty. Default empty.
	 * @return stdClass Number of posts for each status.
	 */
	private function count_posts( $type = 'post', $perm = '' ) {
		global $wpdb;

		if ( ! post_type_exists( $type ) ) {
			return new stdClass();
		}

		$query  = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts}";
		$query .= " LEFT JOIN {$wpdb->prefix}postmeta as i ON {$wpdb->posts}.ID = i.post_id";
		$query .= ' WHERE post_type = %s';
		$query .= " AND i.meta_key = '_order_has_preorder' AND i.meta_value = 'yes'";

		if ( 'readable' === $perm && is_user_logged_in() ) {
			$post_type_object = get_post_type_object( $type );
			if ( ! current_user_can( $post_type_object->cap->read_private_posts ) ) {
				$query .= $wpdb->prepare(
					" AND (post_status != 'private' OR ( post_author = %d AND post_status = 'private' ))",
					get_current_user_id()
				);
			}
		}

		$query .= ' GROUP BY post_status';

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
		$results = (array) $wpdb->get_results( $wpdb->prepare( $query, $type ), ARRAY_A );
		$counts  = array_fill_keys( get_post_stati(), 0 );

		foreach ( $results as $row ) {
			$counts[ $row['post_status'] ] = $row['num_posts'];
		}

		/**
		 * Modify returned post counts by status for the current post type.
		 *
		 * @since 3.7.0
		 *
		 * @param stdClass $counts An object containing the current post_type's post
		 *                         counts by status.
		 * @param string   $type   Post type.
		 * @param string   $perm   The permission to determine if the posts are 'readable'
		 *                         by the current user.
		 */
		return apply_filters( 'ywpo_orders_list_count_posts', (object) $counts, $type, $perm );
	}

	/**
	 * Determine if the current view is the "All" view.
	 *
	 * @since 4.2.0
	 *
	 * @return bool Whether the current view is the "All" view.
	 */
	protected function is_base_request() {
		$vars = $_GET; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		unset( $vars['paged'] );

		if ( empty( $vars ) ) {
			return true;
		} elseif (
			3 === count( $vars ) &&
			( ! empty( $vars['page'] ) && 'yith_wcpo_panel' === $vars['page'] ) &&
			( ! empty( $vars['tab'] ) && 'pre-orders' === $vars['tab'] ) &&
			( ! empty( $vars['sub_tab'] ) && 'orders' === $vars['sub_tab'] )
		) {
				return true;
		}

		return 1 === count( $vars ) && ! empty( $vars['mode'] );
	}

	/**
	 * Custom version of the get_edit_link() function to get the link formatted for 'admin.php' instead of 'edit.php'.
	 *
	 * @param string[] $args  Associative array of URL parameters for the link.
	 * @param string   $label Link text.
	 * @param string   $class Optional. Class attribute. Default empty string.
	 *
	 * @return string
	 */
	private function get_link( $args, $label, $class = '' ) {
		$url = add_query_arg( $args, 'admin.php' );

		$class_html   = '';
		$aria_current = '';

		if ( ! empty( $class ) ) {
			$class_html = sprintf(
				' class="%s"',
				esc_attr( $class )
			);

			if ( 'current' === $class ) {
				$aria_current = ' aria-current="page"';
			}
		}

		return sprintf(
			'<a href="%s"%s%s>%s</a>',
			esc_url( $url ),
			$class_html,
			$aria_current,
			$label
		);
	}

	/**
	 * Retrieves the list of bulk actions available for this table.
	 *
	 * @return array
	 */
	protected function get_bulk_actions() {
		$actions          = array();
		$actions['trash'] = __( 'Move to Trash' );
		return $actions;
	}

	/**
	 * Generates the table navigation above or below the table
	 *
	 * @param string $which Tablenav location.
	 */
	protected function display_tablenav( $which ) {
		if ( 'top' === $which ) {
			wp_nonce_field( 'bulk-' . $this->_args['plural'] );
		}
		?>
		<div class="tablenav <?php echo esc_attr( $which ); ?>">

			<?php if ( $this->has_items() ) : ?>
				<div class="alignleft actions bulkactions">
					<?php $this->bulk_actions( $which ); ?>
				</div>
				<?php
			endif;
			$this->extra_tablenav( $which );
			$this->pagination( $which );
			?>

			<br class="clear" />
		</div>
		<?php
	}

}
