<?php
/**
 * Export Requests List Table
 *
 * @link  https://personalizewp.com/
 * @since 3.3.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';
}

class ListTableExportRequests extends \WP_List_Table {
	/**
	 * Screen ID
	 *
	 * @var string
	 */
	public $screen_id = 'pwp_export_requests';

	/**
	 * Items per page
	 */
	const ITEMS_PER_PAGE = 20;

	public function __construct() {
		parent::__construct(
			array(
				'singular' => 'export_request',
				'plural'   => 'export_requests',
				'ajax'     => false,
				'screen'   => $this->screen_id,
			)
		);
	}

	/**
	 * Retrieve the table columns.
	 *
	 * @return array Associative array of table columns with column name as key and column title as value.
	 */
	public function get_columns() {
		return array(
			'cb'         => '<input type="checkbox" />',
			'title'      => __( 'Requester', 'personalizewp' ),
			'status'     => __( 'Status', 'personalizewp' ),
			'date'       => __( 'Requested', 'personalizewp' ),
			'next_steps' => __( 'Next steps', 'personalizewp' ),
		);
	}

	/**
	 * Get sortable columns
	 *
	 * @return array
	 */
	protected function get_sortable_columns() {
		return array(
			'title' => array( 'title', true ),
			'date'  => array( 'date', true ),
		);
	}

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

	/**
	 * @param \WP_Post $item Export request
	 *
	 * @return string
	 */
	protected function column_cb( $item ) {
		return sprintf( '<input type="checkbox" name="export_ids[]" value="%d" />', (int) $item->ID );
	}

	/**
	 * Display exporter email via title, with meta fallback
	 *
	 * @param \WP_Post $item Export request
	 *
	 * @return string
	 */
	protected function column_title( $item ) {
		$email = $item->post_title;
		if ( ! is_email( $email ) ) {
			$email = get_post_meta( $item->ID, Data_Export::META_EXPORT_EMAIL, true );
		}
		if ( empty( $email ) ) {
			return '&mdash;';
		}
		return sprintf( '<a href="mailto:%1$s">%1$s</a>', esc_attr( $email ) );
	}

	/**
	 * Display status of the export.
	 *
	 * @param \WP_Post $item Export request
	 *
	 * @return string
	 */
	protected function column_status( $item ) {

		$status    = get_post_meta( $item->ID, Data_Export::META_EXPORT_STATUS, true );
		$timestamp = false;
		$label     = '';
		switch ( $status ) {
			case Data_Export::STATUS_PENDING:
				$label = _x( 'Pending', 'Export status', 'personalizewp' );
				break;

			case Data_Export::STATUS_PROCESSING:
				$label     = _x( 'Processing', 'Export status', 'personalizewp' );
				$timestamp = get_post_meta( $item->ID, Data_Export::META_EXPORT_PROCESSING_DATE, true );
				break;

			case Data_Export::STATUS_COMPLETED:
				$label     = _x( 'Completed', 'Export status', 'personalizewp' );
				$timestamp = get_post_meta( $item->ID, Data_Export::META_EXPORT_COMPLETED_DATE, true );
				break;

			case Data_Export::STATUS_FAILED:
				$label = _x( 'Failed', 'Export status', 'personalizewp' );
				break;
		}

		$output = sprintf(
			'<span class="status-label status-request-%s">%s <span class="status-date">%s</span></span>',
			esc_attr( $status ),
			esc_html( $label ),
			esc_html( $this->get_timestamp_as_date( $timestamp ) ),
		);

		return wp_kses( $output, array( 'span' => array( 'class' => array() ) ) );
	}

	/**
	 * Converts a timestamp for display.
	 *
	 * @since 3.5.0
	 *
	 * @param int $timestamp Event timestamp.
	 * @return string Human readable date.
	 */
	protected function get_timestamp_as_date( $timestamp ) {
		if ( empty( $timestamp ) ) {
			return '';
		}

		$time_diff = time() - $timestamp;

		if ( $time_diff >= 0 && $time_diff < DAY_IN_SECONDS ) {
			/* translators: %s: Human-readable time difference. */
			return sprintf( __( '%s ago', 'personalizewp' ), human_time_diff( $timestamp ) );
		}

		return sprintf(
			/* translators: 1: export request date format, 2: privacy request time format. */
			__( '%1$s at %2$s', 'personalizewp' ),
			/* translators: export request date format. See https://www.php.net/manual/en/datetime.format.php */
			date_i18n( __( 'Y/m/d', 'personalizewp' ), $timestamp ),
			/* translators: export request time format. See https://www.php.net/manual/en/datetime.format.php */
			date_i18n( __( 'g:i a', 'personalizewp' ), $timestamp )
		);
	}

	/**
	 * Display when the export was requested.
	 *
	 * @param \WP_Post $item Export request
	 *
	 * @return string
	 */
	protected function column_date( $item ) {
		$requested_time = human_time_diff( strtotime( $item->post_date ), current_time( 'timestamp' ) );
		/* translators: %s: human readable time difference */
		return esc_html( sprintf( __( '%s ago', 'personalizewp' ), $requested_time ) );
	}

	/**
	 * Display the actions for the export.
	 *
	 * @param \WP_Post $item Export request
	 *
	 * @return string
	 */
	protected function column_next_steps( $item ) {

		$next_steps = array();

		$status = get_post_meta( $item->ID, Data_Export::META_EXPORT_STATUS, true );
		switch ( $status ) {
			case Data_Export::STATUS_PENDING:
				// $next_steps['download'] = esc_html_e( 'Generate export data', 'personalizewp' );
				break;

			case Data_Export::STATUS_COMPLETED:
				$email = Data_Export::instance()->get_export_email( $item->ID );
				if ( ! empty( $email ) ) {
					$email_sent    = get_post_meta( $item->ID, Data_Export::META_EXPORT_EMAIL_SENT, true );
					$email_message = empty( $email_sent ) ? __( 'Send email', 'personalizewp' ) : __( 'Resend email', 'personalizewp' );

					$next_steps['email'] = '<a href="' . esc_url(
						wp_nonce_url(
							admin_url( PageDataExport::$export_email_url . (int) $item->ID ),
							'pwp-export-email-' . (int) $item->ID
						)
					) . '">' . esc_html( $email_message ) . '</a> ';
				}

			// case Data_Export::STATUS_FAILED:
			case Data_Export::STATUS_PROCESSING:
				$next_steps['delete'] = '<a class="submitdelete" href="' . esc_url(
					wp_nonce_url(
						admin_url( PageDataExport::$delete_export_url . (int) $item->ID ),
						'pwp-delete-export-' . (int) $item->ID
					)
				) . '">' . esc_html__( 'Delete request', 'personalizewp' ) . '</a>';
				break;
		}

		// Always allow deleting
		$next_steps['delete'] = '<a class="submitdelete" href="' . esc_url(
			wp_nonce_url(
				admin_url( PageDataExport::$delete_export_url . (int) $item->ID ),
				'pwp-delete-export-' . (int) $item->ID
			)
		) . '">' . esc_html__( 'Delete request', 'personalizewp' ) . '</a>';

		$_count = count( $next_steps );
		$i      = 0;
		foreach ( $next_steps as $action => $link ) {
			++$i;

			$separator = ( $i < $_count ) ? ' | ' : '';

			echo "<span class='$action'>{$link}{$separator}</span>";
		}
	}

	/**
	 * Generates and displays row action links.
	 *
	 * @param \WP_Post $item        Item being acted upon.
	 * @param string   $column_name Current column name.
	 * @param string   $primary     Primary column name.
	 *
	 * @return string Row actions output for Export request, 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();
		$status  = get_post_meta( $item->ID, Data_Export::META_EXPORT_STATUS, true );

		// Possible actions.
		$allow_generate   = false;
		$allow_regenerate = false;
		$allow_download   = false;

		// Logic checks for actions
		if ( Data_Export::STATUS_PENDING === $status ) {
			$allow_generate = true;
		}

		if ( Data_Export::STATUS_PROCESSING === $status ) {
			// Check if the processing has timed-out, allow regeneration.
			$timestamp = get_post_meta( $item->ID, Data_Export::META_EXPORT_PROCESSING_DATE, true );
			if ( empty( $timestamp ) || ( time() - HOUR_IN_SECONDS ) > $timestamp ) {
				$allow_regenerate = true;
			}
		}

		if ( Data_Export::STATUS_COMPLETED === $status ) {
			// Check if the file already exists, as no need to re-generate.
			if ( Data_Export::instance()->has_export_file( $item->ID ) ) {
				$allow_download = true;
			} else {
				$allow_regenerate = true;
			}
		}

		if ( $allow_generate ) {

			$actions['download'] = sprintf(
				'<button type="button" class="button-link" data-pwp-export-download="%s" data-pwp-nonce="%s">%s</button>
				<span hidden class="export-processing">%s<span class="export-progress"></span></span>
				<span hidden class="notice inline notice-alt notice-success" role="alert">%s</span>
				',
				esc_attr( (int) $item->ID ),
				esc_attr( wp_create_nonce( 'pwp-export-data-' . $item->ID ) ),
				esc_html__( 'Gather export data', 'personalizewp' ),
				esc_html__( 'Gathering export data...', 'personalizewp' ),
				esc_html__( 'Your export has been generated and will download automatically.', 'personalizewp' ),
			);

		} elseif ( $allow_regenerate ) {

			$actions['download'] = sprintf(
				'<button type="button" class="button-link" data-pwp-export-download="%s" data-pwp-nonce="%s">%s</button>
				<span hidden class="export-processing">%s<span class="export-progress"></span></span>
				<span hidden class="notice inline notice-alt notice-success" role="alert">%s</span>
				',
				esc_attr( (int) $item->ID ),
				esc_attr( wp_create_nonce( 'pwp-export-data-' . $item->ID ) ),
				esc_html__( 'Re-gather export data', 'personalizewp' ),
				esc_html__( 'Gathering export data...', 'personalizewp' ),
				esc_html__( 'Your export has been generated and will download automatically.', 'personalizewp' ),
			);

		} elseif ( $allow_download ) {

			$actions['download'] = sprintf(
				'<a href="%s" target="_blank">%s</a>',
				esc_url(
					admin_url( PageDataExport::$download_url . (int) $item->ID )
				),
				esc_html__( 'Download export data', 'personalizewp' ),
			);
		}

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

	/**
	 * Retrieves the list of bulk actions available for this table.
	 *
	 * @return array
	 */
	public function get_bulk_actions() {
		return array(
			'delete' => __( 'Delete', 'personalizewp' ),
		);
	}

	/**
	 * Generates content for a single row of the table, allows adding class at TR level.
	 *
	 * @since 3.5.0
	 *
	 * @param \WP_Post $item The current request.
	 */
	public function single_row( $item ) {
		$status = get_post_meta( $item->ID, Data_Export::META_EXPORT_STATUS, true );

		echo '<tr id="request-' . esc_attr( $item->ID ) . '" class="status-request-' . esc_attr( $status ) . '">';
		$this->single_row_columns( $item );
		echo '</tr>';
	}

	/**
	 * Prepares the list of items for displaying.
	 */
	public function prepare_items() {

		$per_page     = (int) get_user_meta( get_current_user_id(), 'edit_pwp_export_requests_per_page', true );
		$per_page     = $per_page ? $per_page : self::ITEMS_PER_PAGE;
		$current_page = $this->get_pagenum();

		$query_args = array(
			'post_type'      => Data_Export::POST_TYPE,
			'posts_per_page' => $per_page,
			'paged'          => $current_page,
			'orderby'        => 'date',
			'order'          => 'DESC',
		);

		// Sorting
		if ( ! empty( $_GET['orderby'] ) ) {
			$_orderby = sanitize_text_field( wp_unslash( $_GET['orderby'] ) );
			$parsed   = $this->parse_orderby( $_orderby );
			if ( $parsed ) {
				if ( 'status' === $parsed ) {
					$query_args['meta_query'] = array(
						'status_clause' => array(
							'key'     => Data_Export::META_EXPORT_STATUS,
							'compare' => 'EXISTS',
						),
					);
					$query_args['orderby']    = 'status_clause';

				} else {
					$query_args['orderby'] = $parsed;
				}
			}
		}
		if ( ! empty( $_GET['order'] ) ) {
			$_order = sanitize_text_field( wp_unslash( $_GET['order'] ) );
			$parsed = $this->parse_order( $_order );
			if ( $parsed ) {
				$query_args['order'] = $parsed;
			}
		}

		$query       = new \WP_Query();
		$this->items = $query->query( $query_args );
		$total_items = $query->found_posts;

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

	/**
	 * Validates that the 'orderby' is valid
	 *
	 * @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.
	 *
	 * @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';
		}
	}
}
