<?php
/**
 * Donations list table (WP_List_Table extension).
 *
 * @package Donatico\Admin
 */

declare(strict_types=1);

namespace Donatico\Admin;

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

use Donatico\Database\DonationRepository;
use Donatico\Models\Donation;

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

/**
 * Renders the Donatico donations management table.
 */
class DonationsList extends \WP_List_Table {

	/** @var DonationRepository */
	private DonationRepository $repository;

	/**
	 * @param DonationRepository $repository
	 */
	public function __construct( DonationRepository $repository ) {
		parent::__construct(
			array(
				'singular' => 'donation',
				'plural'   => 'donations',
				'ajax'     => false,
			)
		);

		$this->repository = $repository;
	}

	// -------------------------------------------------------------------------
	// Column definitions
	// -------------------------------------------------------------------------

	/**
	 * @return array<string, string>
	 */
	public function get_columns(): array {
		return array(
			'cb'         => '<input type="checkbox">',
			'id'         => __( '#', 'donatico' ),
			'donor_name' => __( 'Donor', 'donatico' ),
			'amount'     => __( 'Amount', 'donatico' ),
			'status'     => __( 'Status', 'donatico' ),
			'created_at' => __( 'Date', 'donatico' ),
		);
	}

	/**
	 * @return array<string, array{string, bool}>
	 */
	protected function get_sortable_columns(): array {
		return array(
			'id'         => array( 'id', true ),
			'donor_name' => array( 'donor_name', false ),
			'amount'     => array( 'amount', false ),
			'status'     => array( 'status', false ),
			'created_at' => array( 'created_at', true ),
		);
	}

	/**
	 * @return array<string, string>
	 */
	protected function get_bulk_actions(): array {
		return array(
			'delete' => __( 'Delete', 'donatico' ),
		);
	}

	// -------------------------------------------------------------------------
	// Column renderers
	// -------------------------------------------------------------------------

	/**
	 * @param Donation $item
	 * @return string
	 */
	protected function column_cb( $item ): string {
		return sprintf( '<input type="checkbox" name="donation_ids[]" value="%d">', $item->getId() );
	}

	/**
	 * @param Donation $item
	 * @return string
	 */
	protected function column_id( $item ): string {
		return '<strong>#' . esc_html( (string) $item->getId() ) . '</strong>';
	}

	/**
	 * Donor column with row actions (Delete).
	 *
	 * @param Donation $item
	 * @return string
	 */
	protected function column_donor_name( $item ): string {
		$delete_url = wp_nonce_url(
			add_query_arg(
				array(
					'page'        => 'donatico-donations',
					'action'      => 'delete',
					'donation_id' => $item->getId(),
				),
				admin_url( 'admin.php' )
			),
			'donatico_delete_donation_' . $item->getId()
		);

		$row_actions = array(
			'delete' => sprintf(
				'<a href="%s" class="donatico-delete-link" onclick="return confirm(\'%s\')">%s</a>',
				esc_url( $delete_url ),
				esc_js( __( 'Delete this donation? This cannot be undone.', 'donatico' ) ),
				esc_html__( 'Delete', 'donatico' )
			),
		);

		$name = $item->isAnonymous()
			? '<em>' . esc_html__( 'Anonymous', 'donatico' ) . '</em>'
			: esc_html( $item->getDonorName() );

		$email = $item->isAnonymous() ? '' : '<br><small>' . esc_html( $item->getDonorEmail() ) . '</small>';

		return $name . $email . $this->row_actions( $row_actions );
	}

	/**
	 * @param Donation $item
	 * @return string
	 */
	protected function column_amount( $item ): string {
		$currency = esc_html( $item->getCurrency() );
		$amount   = esc_html( $item->getFormattedAmount() );
		return "<strong>{$amount}</strong> <small>{$currency}</small>";
	}

	/**
	 * Render a coloured status badge.
	 *
	 * @param Donation $item
	 * @return string
	 */
	protected function column_status( $item ): string {
		$status    = $item->getStatus();
		$css_class = 'donatico-status donatico-status--' . esc_attr( $status );
		$labels    = array(
			Donation::STATUS_PENDING   => __( 'Pending', 'donatico' ),
			Donation::STATUS_COMPLETED => __( 'Completed', 'donatico' ),
			Donation::STATUS_FAILED    => __( 'Failed', 'donatico' ),
			Donation::STATUS_REFUNDED  => __( 'Refunded', 'donatico' ),
		);
		$label = $labels[ $status ] ?? ucfirst( $status );
		return "<span class=\"{$css_class}\">" . esc_html( $label ) . '</span>';
	}

	/**
	 * @param Donation $item
	 * @return string
	 */
	protected function column_created_at( $item ): string {
		return esc_html(
			wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $item->getCreatedAt() ) )
		);
	}

	/**
	 * Fallback renderer for any unmapped column.
	 *
	 * @param Donation $item
	 * @param string   $column_name
	 * @return string
	 */
	protected function column_default( $item, $column_name ): string {
		return '—';
	}

	// -------------------------------------------------------------------------
	// Data preparation
	// -------------------------------------------------------------------------

	/**
	 * Query, sort, paginate, and load the items + pagination into WP_List_Table.
	 *
	 * @return void
	 */
	public function prepare_items(): void {
		$this->processBulkAction();
		$this->processRowAction();

		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		$search  = isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : '';
		$status  = isset( $_GET['status'] ) ? sanitize_key( wp_unslash( $_GET['status'] ) ) : '';
		$orderby = isset( $_GET['orderby'] ) ? sanitize_key( wp_unslash( $_GET['orderby'] ) ) : 'created_at';
		$order   = isset( $_GET['order'] ) ? sanitize_key( wp_unslash( $_GET['order'] ) ) : 'DESC';
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		$per_page     = 20;
		$current_page = $this->get_pagenum();

		$args = array(
			'search'  => $search,
			'status'  => $status,
			'orderby' => $orderby,
			'order'   => $order,
			'limit'   => $per_page,
			'offset'  => ( $current_page - 1 ) * $per_page,
		);

		$this->items = $this->repository->findAll( $args );

		$total_items = $this->repository->count( array( 'search' => $search, 'status' => $status ) );

		$this->set_pagination_args(
			array(
				'total_items' => $total_items,
				'per_page'    => $per_page,
				'total_pages' => (int) ceil( $total_items / $per_page ),
			)
		);

		$this->_column_headers = array(
			$this->get_columns(),
			array(),
			$this->get_sortable_columns(),
		);
	}

	// -------------------------------------------------------------------------
	// Actions
	// -------------------------------------------------------------------------

	/**
	 * Handle Delete bulk action.
	 *
	 * @return void
	 */
	private function processBulkAction(): void {
		if ( 'delete' !== $this->current_action() ) {
			return;
		}

		if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['_wpnonce'] ) ), 'bulk-donations' ) ) {
			return;
		}

		$ids = isset( $_POST['donation_ids'] ) ? array_map( 'absint', (array) $_POST['donation_ids'] ) : array();

		foreach ( $ids as $id ) {
			$this->repository->delete( $id );
		}
	}

	/**
	 * Handle the single-row Delete row action.
	 *
	 * @return void
	 */
	private function processRowAction(): void {
		if ( ! isset( $_GET['action'] ) || 'delete' !== sanitize_key( wp_unslash( $_GET['action'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			return;
		}

		$donation_id = isset( $_GET['donation_id'] ) ? absint( $_GET['donation_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended

		if ( ! $donation_id ) {
			return;
		}

		if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_GET['_wpnonce'] ) ), 'donatico_delete_donation_' . $donation_id ) ) {
			wp_die( esc_html__( 'Security check failed.', 'donatico' ) );
		}

		$this->repository->delete( $donation_id );

		wp_safe_redirect(
			add_query_arg( array( 'page' => 'donatico-donations', 'deleted' => '1' ), admin_url( 'admin.php' ) )
		);
		exit;
	}

	// -------------------------------------------------------------------------
	// Status filter views
	// -------------------------------------------------------------------------

	/**
	 * @return array<string, string>
	 */
	protected function get_views(): array {
		$current = isset( $_GET['status'] ) ? sanitize_key( wp_unslash( $_GET['status'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$base    = add_query_arg( 'page', 'donatico-donations', admin_url( 'admin.php' ) );

		$views  = array();
		$counts = array(
			''                         => $this->repository->count(),
			Donation::STATUS_COMPLETED => $this->repository->count( array( 'status' => Donation::STATUS_COMPLETED ) ),
			Donation::STATUS_PENDING   => $this->repository->count( array( 'status' => Donation::STATUS_PENDING ) ),
			Donation::STATUS_FAILED    => $this->repository->count( array( 'status' => Donation::STATUS_FAILED ) ),
			Donation::STATUS_REFUNDED  => $this->repository->count( array( 'status' => Donation::STATUS_REFUNDED ) ),
		);

		$labels = array(
			''                         => __( 'All', 'donatico' ),
			Donation::STATUS_COMPLETED => __( 'Completed', 'donatico' ),
			Donation::STATUS_PENDING   => __( 'Pending', 'donatico' ),
			Donation::STATUS_FAILED    => __( 'Failed', 'donatico' ),
			Donation::STATUS_REFUNDED  => __( 'Refunded', 'donatico' ),
		);

		foreach ( $labels as $status => $label ) {
			$url       = $status ? add_query_arg( 'status', $status, $base ) : $base;
			$class     = $current === $status ? ' class="current"' : '';
			$views[ $status ] = sprintf(
				'<a href="%s"%s>%s <span class="count">(%d)</span></a>',
				esc_url( $url ),
				$class,
				esc_html( $label ),
				$counts[ $status ]
			);
		}

		return $views;
	}

	// -------------------------------------------------------------------------
	// Page render
	// -------------------------------------------------------------------------

	/**
	 * Render the donations list page.
	 * Callback registered via add_submenu_page().
	 *
	 * @return void
	 */
	public function render(): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'donatico' ) );
		}

		$this->prepare_items();

		include DONATICO_PLUGIN_DIR . 'templates/admin/donations-list.php';
	}
}
