<?php
/**
 * Menu class.
 *
 * @package wpRigel\Pollify
 * @since 1.0.0
 */

declare(strict_types=1);

namespace wpRigel\Pollify\Admin;

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

/**
 * PollsListTable class.
 *
 * @package wpRigel\Pollify
 *
 * @since 1.0.0
 */
class PollsListTable extends \WP_List_Table {

	/**
	 * Per page no.
	 *
	 * @var int
	 */
	private $per_page;

	/**
	 * Table data.
	 *
	 * @var array
	 */
	private $table_data;


	/**
	 * Prepare the columns for rendering on items.
	 *
	 * @return array
	 */
	public function get_columns(): array {
		$columns = array(
			'cb'         => '<input type = "checkbox" />',
			'title'      => __( 'Title', 'poll-creator' ),
			'type'       => __( 'Type', 'poll-creator' ),
			'reference'  => __( 'Source', 'poll-creator' ),
			'status'     => __( 'Status', 'poll-creator' ),
			'response'   => __( 'Total Response', 'poll-creator' ),
			'created_at' => __( 'Created at', 'poll-creator' ),
		);

		return $columns;
	}

	/**
	 * Render the column cb.
	 *
	 * @param object $item The current item.
	 * @param string $column_name The current column name.
	 *
	 * @return string
	 */
	public function column_default( $item, $column_name ) {
		switch ( $column_name ) {
			case 'id':
				return $item->get_id();
			case 'client_id':
				return $item->get_client_id();
			case 'title':
				return $item->get_title();
			case 'type':
				return $item->get_type();
			case 'status':
				return $item->get_status();
			case 'reference':
				return $item->get_reference();
			case 'response':
				return $item->get_response();
			case 'created_at':
				return $item->get_created_at();
			default:
				return $item[ $column_name ];
		}
	}

	/**
	 * Get the primary column name for responsive table behaviour.
	 *
	 * @return string
	 */
	protected function get_primary_column_name(): string {
		return 'title';
	}

	/**
	 * Get sortable columns.
	 *
	 * @return array
	 */
	public function get_sortable_columns() {
		$sortable_columns = [
			'title'      => [ 'title', false ],
			'created_at' => [ 'created_at', false ],
		];

		return $sortable_columns;
	}

	/**
	 * Render the column cb.
	 *
	 * @param object $item The current item.
	 *
	 * @return string
	 */
	public function column_cb( $item ) {
		return sprintf(
			'<input type="checkbox" name="poll_id[]" value="%d" />',
			$item->get_id()
		);
	}

	/**
	 * Add row actions with column title.
	 *
	 * @param object $item The current item.
	 *
	 * @return array
	 */
	public function column_title( $item ) {
		$page               = pollify_filter_input( INPUT_GET, 'page', POLLIFY_FILTER_SANITIZE_STRING );
		$confirm_text       = __( 'Are you sure you want to reset the results? If you do reset, the results are not achievable again.', 'poll-creator' );
		$confirm_trash_text = __( 'Are you sure you want to move this poll to trash? It will also removed the poll block from the editor and you will not be able to roll it back anymore.', 'poll-creator' );

		$nonce       = wp_create_nonce( 'pollify_reset_results' );
		$trash_nonce = wp_create_nonce( 'pollify_trash_poll' );

		// Different actions for trash vs normal polls.
		if ( 'trash' === $item->get_status() ) {
			$actions = array(
				'view'               => sprintf(
					'<a href="%s">' . __( 'View results', 'poll-creator' ) . '</a>',
					esc_url(
						add_query_arg(
							[
								'page'    => $page,
								'action'  => 'view_results',
								'poll_id' => $item->get_client_id(),
							]
						)
					)
				),
				'delete_permanently' => sprintf( '<a class="submitdelete pollify-delete-permanently" data-poll-id="%s" href="#">' . __( 'Delete Permanently', 'poll-creator' ) . '</a>', esc_attr( $item->get_client_id() ) ),
			);
		} else {
			$actions = array(
				'view'  => sprintf(
					'<a href="%s">' . __( 'View results', 'poll-creator' ) . '</a>',
					esc_url(
						add_query_arg(
							[
								'page'    => $page,
								'action'  => 'view_results',
								'poll_id' => $item->get_client_id(),
							]
						)
					)
				),
				'reset' => sprintf(
					'<a class="submitdelete" onclick="return confirm(\'%s\')" href="%s">' . __( 'Reset Results', 'poll-creator' ) . '</a>',
					esc_js( $confirm_text ),
					esc_url(
						add_query_arg(
							[
								'page'    => $page,
								'action'  => 'reset_results',
								'poll_id' => $item->get_client_id(),
								'_nonce'  => $nonce,
							]
						)
					)
				),
				'trash' => sprintf(
					'<a class="submitdelete" onclick="return confirm(\'%s\')" href="%s">' . __( 'Trash', 'poll-creator' ) . '</a>',
					esc_js( $confirm_trash_text ),
					esc_url(
						add_query_arg(
							[
								'page'         => $page,
								'action'       => 'trash_poll',
								'poll_id'      => $item->get_client_id(),
								'reference_id' => $item->get_reference(),
								'_nonce'       => $trash_nonce,
							]
						)
					)
				),
			);
		}

		// Wrap the title with view result link.
		$title = sprintf(
			'<a href="%s">%s</a>',
			esc_url(
				add_query_arg(
					[
						'page'    => $page,
						'action'  => 'view_results',
						'poll_id' => $item->get_client_id(),
					]
				)
			),
			esc_html( $item->get_title() )
		);

		return sprintf( '<strong>%1$s</strong> %2$s', $title, $this->row_actions( $actions ) );
	}

	/**
	 * Render the column type using icon.
	 *
	 * @param object $item The current item.
	 *
	 * @return string
	 */
	public function column_type( $item ) {
		$icon = $item->get_icon();

		// Check if the icon is an SVG string.
		if ( strpos( $icon, '<svg' ) !== false ) {
			// If it's an SVG, render it directly.
			$icon_html = $icon;
		} else {
			// If it's a dashicon class or other string, wrap it in dashicons format.
			$icon_html = sprintf( '<span class="dashicons dashicons-%s"></span>', esc_attr( $icon ) );
		}

		return sprintf( '<span tooltip="%s" flow="right">%s</span>', ucfirst( $item->get_type() ?? '' ), $icon_html );
	}

	/**
	 * Render the column reference.
	 *
	 * @param object $item The current item.
	 *
	 * @return string
	 */
	public function column_reference( $item ) {
		if ( is_numeric( $item->get_reference() ) ) {
			$id = $item->get_reference();

			if ( ! empty( $id ) ) {
				$post_title = get_the_title( $item->get_reference() );

				$actions = array(
					'edit' => sprintf( '<a href="%s" targe="_blank">' . __( 'Edit', 'poll-creator' ) . '</a>', get_edit_post_link( $id ) ),
					'view' => sprintf( '<a href="%s" targe="_blank">' . __( 'View frontend', 'poll-creator' ) . '</a>', get_permalink( $id ) ),
				);

				// Wrap the title with view result link.
				$title     = sprintf( '<a href="%s">%s</a>', get_edit_post_link( $id ), $post_title );
				$reference = sprintf( '<strong>%1$s</strong> %2$s', $title, $this->row_actions( $actions ) );
			}
		} else {
			$reference = esc_html( $item->get_reference() );
		}

		return $reference;
	}

	/**
	 * Render the column status.
	 *
	 * @param object $item The current item.
	 *
	 * @return string
	 */
	public function column_status( $item ) {
		$statuses = [
			'publish'  => __( 'Open', 'poll-creator' ),
			'draft'    => __( 'Closed', 'poll-creator' ),
			'schedule' => __( 'Schedule', 'poll-creator' ),
			'trash'    => __( 'Trash', 'poll-creator' ),
		];

		$settins = $item->get_settings() ?? [];

		if ( 'schedule' === $item->get_status() ) {
			$end_date = get_date_from_gmt( $settins['endDate'], get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) );
			/* translators: %s: poll end date */
			$ended_text = sprintf( __( 'Ended at %s', 'poll-creator' ), $end_date );

			// Check if the poll ended.
			if ( strtotime( $settins['endDate'] ) < time() ) {
				return sprintf( '<span tooltip="%s" flow="right" class="pollify-status status-draft">%s <span class="dashicons dashicons-info"></span></span>', esc_attr( $ended_text ), esc_html__( 'Closed', 'poll-creator' ) );
			}

			/* translators: %s: poll end date */
			$end_date_text = sprintf( __( 'Will be ended on %s', 'poll-creator' ), $end_date );

			return sprintf( '<span tooltip="%s" flow="right" class="pollify-status status-%s">%s <span class="dashicons dashicons-info"></span></span>', esc_attr( $end_date_text ), esc_attr( $item->get_status() ), esc_html( $statuses[ $item->get_status() ] ?? '' ) );
		}

		// Wrap the status with span tag so later I can style it.
		return sprintf( '<span class="pollify-status status-%s">%s</span>', esc_attr( $item->get_status() ), esc_html( $statuses[ $item->get_status() ] ?? '' ) );
	}

	/**
	 * Render the column response.
	 *
	 * @param object $item The current item.
	 *
	 * @return string
	 */
	public function column_response( $item ) {
		// Get link for view-results page.
		$view_results_link = apply_filters(
			'pollify_list_table_view_response_url',
			add_query_arg(
				[
					'page'    => 'pollify',
					'action'  => 'view_results',
					'tab'     => 'votes',
					'poll_id' => $item->get_client_id(),
				],
				admin_url( 'admin.php' )
			),
			$item
		);

		ob_start();
		?>
		<div class="post-com-count-wrapper">
			<a href="<?php echo esc_url( $view_results_link ); ?>" class="post-com-count post-com-count-approved">
				<span class="comment-count-approved" aria-hidden="true"><?php echo esc_html( $item->get_response() ) ?? 0; ?></span>
				<span class="screen-reader-text">
					<?php
						/* translators: %s: votes count */
						echo esc_html( wp_sprintf( __( '%s votes', 'poll-creator' ), $item->get_response() ) );
					?>
				</span>
			</a>
		</div>
		<?php
		return ob_get_clean();
	}

	/**
	 * Render the column created_at.
	 *
	 * @param object $item The current item.
	 *
	 * @return string
	 */
	public function column_created_at( $item ) {
		return date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $item->get_created_at() ) );
	}

	/**
	 * Get the views for the table.
	 *
	 * @return array
	 */
	protected function get_views() {
		$current_status = pollify_filter_input( INPUT_GET, 'status', POLLIFY_FILTER_SANITIZE_STRING );
		$current_type   = pollify_filter_input( INPUT_POST, 'type', POLLIFY_FILTER_SANITIZE_STRING );

		// Get counts for each status, filtered to the same type as the list.
		global $wpdb;

		if ( ! empty( $current_type ) && 'all' !== $current_type ) {
			$counts = $wpdb->get_results(
				$wpdb->prepare(
					'SELECT status, COUNT(*) as count FROM %i WHERE type = %s GROUP BY status',
					$wpdb->prefix . 'pollify_poll',
					$current_type
				),
				ARRAY_A
			);
		} else {
			$registered_types = array_keys( apply_filters( 'pollify_map_feedback_classes', [ 'poll' => true ], null ) );
			$placeholders     = implode( ', ', array_fill( 0, count( $registered_types ), '%s' ) );

			// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
			$counts = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT status, COUNT(*) as count FROM %i WHERE type IN ($placeholders) GROUP BY status",
					$wpdb->prefix . 'pollify_poll',
					...$registered_types
				),
				ARRAY_A
			);
			// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
		}

		$status_counts = [
			'all'     => 0,
			'publish' => 0,
			'draft'   => 0,
			'trash'   => 0,
		];

		foreach ( $counts as $count_row ) {
			$status = $count_row['status'];
			$count  = (int) $count_row['count'];

			if ( 'trash' === $status ) {
				$status_counts['trash'] = $count;
			} elseif ( 'publish' === $status ) {
				$status_counts['publish'] = $count;
			} elseif ( 'draft' === $status ) {
				$status_counts['draft'] = $count;
			}

			if ( 'trash' !== $status ) {
				$status_counts['all'] += $count;
			}
		}

		$views = [
			'all'     => '<a href="' . admin_url( 'admin.php?page=pollify' ) . '" class="' . ( empty( $current_status ) ? 'current' : '' ) . '">' . __( 'All', 'poll-creator' ) . ' <span class="count">(' . $status_counts['all'] . ')</span></a>',
			'publish' => '<a href="' . admin_url( 'admin.php?page=pollify&status=publish' ) . '" class="' . ( 'publish' === $current_status ? 'current' : '' ) . '">' . __( 'Open', 'poll-creator' ) . ' <span class="count">(' . $status_counts['publish'] . ')</span></a>',
			'draft'   => '<a href="' . admin_url( 'admin.php?page=pollify&status=draft' ) . '" class="' . ( 'draft' === $current_status ? 'current' : '' ) . '">' . __( 'Closed', 'poll-creator' ) . ' <span class="count">(' . $status_counts['draft'] . ')</span></a>',
			'trash'   => '<a href="' . admin_url( 'admin.php?page=pollify&status=trash' ) . '" class="' . ( 'trash' === $current_status ? 'current' : '' ) . '">' . __( 'Trash', 'poll-creator' ) . ' <span class="count">(' . $status_counts['trash'] . ')</span></a>',
		];

		return $views;
	}

	/**
	 * Render the table nav.
	 *
	 * @param string $which The position of the nav.
	 *
	 * @return void
	 */
	protected function extra_tablenav( $which ) {
		if ( 'top' === $which ) {
			$type = pollify_filter_input( INPUT_POST, 'type', POLLIFY_FILTER_SANITIZE_STRING );
			// Call FeedbackFactory class and get the feedback types.
			$feedback_types = \wpRigel\Pollify\FeedbackFactory::get_class_map();
			?>
			<div class="alignleft actions bulkactions">
				<select name="type" id="poll-type" >
					<option value="all" <?php selected( 'all', $type, true ); ?>><?php esc_html_e( 'All types', 'poll-creator' ); ?></option>
					<?php
					if ( ! empty( $feedback_types ) && is_array( $feedback_types ) ) {
						foreach ( array_keys( $feedback_types ) as $feedback_key ) {
							printf(
								'<option value="%1$s" %2$s>%3$s</option>',
								esc_attr( $feedback_key ),
								selected( $feedback_key, $type, false ),
								esc_html( ucfirst( $feedback_key ) )
							);
						}
					}
					?>
				</select>
				<?php
				submit_button( __( 'Filter', 'poll-creator' ), '', 'filter_action', false, [ 'id' => 'pollify-filter-action-button' ] );
				?>
			</div>
			<?php
		}
	}

	/**
	 * Prepare the items for rendering on the table.
	 *
	 * @return void
	 */
	public function prepare_items() {
		$search   = pollify_filter_input( INPUT_POST, 's', POLLIFY_FILTER_SANITIZE_STRING );
		$columns  = $this->get_columns();
		$sortable = $this->get_sortable_columns();

		// Set up the columns.
		$this->_column_headers = [ $columns, [], $sortable ];

		// Set per page depending on screen option.
		$this->per_page = $this->get_items_per_page( 'polls_per_page', 10 );

		// Set some default args for getting the table data.
		$args = [
			'per_page' => $this->per_page,
			'page'     => $this->get_pagenum(),
		];

		// Set type from extra nav filter; default to registered types so count matches display.
		$type = pollify_filter_input( INPUT_POST, 'type', POLLIFY_FILTER_SANITIZE_STRING );

		if ( ! empty( $type ) && 'all' !== $type ) {
			$args['type'] = $type;
		}

		// Set status if someone filter.
		$status = pollify_filter_input( INPUT_GET, 'status', POLLIFY_FILTER_SANITIZE_STRING ) ?: 'all';

		if ( ! empty( $status ) && in_array( $status, array_keys( $this->get_views() ), true ) ) {
			$args['status'] = $status;
		}

		// Set search term if someonce search.
		if ( ! empty( $search ) ) {
			$args['search'] = $search;
		}

		// Set order and order by depending on filter input value.
		$order   = pollify_filter_input( INPUT_GET, 'order', POLLIFY_FILTER_SANITIZE_STRING ) ?: 'DESC';
		$orderby = pollify_filter_input( INPUT_GET, 'orderby', POLLIFY_FILTER_SANITIZE_STRING ) ?: 'id';

		if ( isset( $orderby, $order ) && in_array( $orderby, array_keys( $sortable ), true ) && in_array( strtoupper( $order ), [ 'ASC', 'DESC' ], true ) ) {
			$args['orderby'] = $orderby;
			$args['order']   = $order;
		}

		// Get the table data depending on args.
		$this->table_data = $this->get_table_data( $args );

		// Get total counts depending on args.
		$args['count'] = true;
		$total_items   = intval( $this->get_table_data( $args ) );

		// Set the pagination.
		$this->set_pagination_args(
			[
				'total_items' => $total_items, // total number of items.
				'per_page'    => $this->per_page, // items to show on a page.
				'total_pages' => ceil( $total_items / $this->per_page ), // use ceil to round up.
			]
		);

		// Set the final items for dispalying.
		$this->items = $this->table_data;
	}

	/**
	 * Get data from tables.
	 *
	 * @param array $args The arguments for getting the data.
	 *
	 * @return array|int
	 */
	private function get_table_data( $args ) {
		return \wpRigel\Pollify\FeedbackManager::get_instance()->all( $args );
	}
}
