<?php
/**
 * Shared cart action handlers for admin UI.
 *
 * @package EDD\Pro\CartRecovery\Admin\Carts
 * @copyright Copyright (c) 2026, Sandhills Development, LLC
 * @license https://opensource.org/licenses/gpl-2.0.php GNU Public License
 * @since 3.6.5
 */

namespace EDD\Pro\CartRecovery\Admin\Carts;

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

use EDD\Pro\CartRecovery\Carts\Repository;
use EDD\Pro\CartRecovery\Emails\Service;
use EDD\EventManagement\SubscriberInterface;
use EDD\Pro\CartRecovery\Traits\Debug;

/**
 * Centralises cart-related admin actions (bulk + AJAX).
 */
final class Actions implements SubscriberInterface {
	use Debug;

	/**
	 * Email service.
	 *
	 * @var Service|null
	 */
	private $email_service;

	/**
	 * Cart repository.
	 *
	 * @var Repository|null
	 */
	private $cart_repo;

	/**
	 * Constructor.
	 *
	 * @since 3.6.5
	 */
	public function __construct() {
		$this->cart_repo     = new Repository();
		$this->email_service = new Service();
	}

	/**
	 * Returns the subscribed events.
	 *
	 * @since 3.6.5
	 * @return array
	 */
	public static function get_subscribed_events(): array {
		return array(
			'wp_ajax_edd_acr_mark_recovered'       => 'ajax_mark_recovered',
			'wp_ajax_edd_acr_delete_cart'          => 'ajax_delete_cart',
			'load-download_page_edd-cart-recovery' => 'handle_bulk_actions',
			'edd_acr_send_recovery_email'          => 'handle_send_recovery_email',
		);
	}

	/**
	 * Process bulk actions for the cart recovery list table.
	 *
	 * This is hooked to 'load-download_page_edd-cart-recovery' which fires before
	 * the page is rendered, allowing us to process actions and redirect cleanly.
	 *
	 * @since 3.6.5
	 */
	public function handle_bulk_actions(): void {
		// Bail if this method was called directly.
		if ( 'load-download_page_edd-cart-recovery' !== current_action() ) {
			_doing_it_wrong( __METHOD__, 'This method is not meant to be called directly.', '3.6.5' );
			return;
		}

		// Check user capability.
		if ( ! current_user_can( 'manage_shop_settings' ) ) {
			return;
		}

		// Get action from either bulk action dropdown.
		$action = isset( $_REQUEST['action'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( '-1' === $action || empty( $action ) ) {
			$action = isset( $_REQUEST['action2'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['action2'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		}

		// Bail if no valid action.
		if ( '-1' === $action || empty( $action ) ) {
			return;
		}

		// Get cart IDs from request.
		$cart_ids = isset( $_GET['cart_ids'] ) ? wp_unslash( $_GET['cart_ids'] ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized

		if ( ! is_array( $cart_ids ) ) {
			$cart_ids = array( $cart_ids );
		}

		$cart_ids = wp_parse_id_list( $cart_ids );

		// Bail if no cart IDs.
		if ( empty( $cart_ids ) ) {
			return;
		}

		// Verify nonce.
		check_admin_referer( 'bulk-edd_acr_carts' );

		// Process the action.
		$success = false;
		$count   = count( $cart_ids );

		switch ( $action ) {
			case 'mark_recovered':
				$success = $this->mark_carts_recovered_bulk( $cart_ids );
				if ( $success ) {
					$message = sprintf(
						/* translators: %d: number of carts */
						_n( '%d cart marked as recovered.', '%d carts marked as recovered.', $count, 'easy-digital-downloads' ),
						$count
					);
					$this->add_admin_notice( $message, 'success' );
				} else {
					$this->add_admin_notice( __( 'Failed to mark carts as recovered.', 'easy-digital-downloads' ), 'error' );
				}
				break;

			case 'delete':
				$success = $this->delete_carts_bulk( $cart_ids );
				if ( $success ) {
					$message = sprintf(
						/* translators: %d: number of carts */
						_n( '%d cart deleted.', '%d carts deleted.', $count, 'easy-digital-downloads' ),
						$count
					);
					$this->add_admin_notice( $message, 'success' );
				} else {
					$this->add_admin_notice( __( 'Failed to delete carts.', 'easy-digital-downloads' ), 'error' );
				}
				break;

			default:
				// Allow extensions to handle custom bulk actions.
				do_action( 'edd_acr_process_bulk_action', $cart_ids, $action );
				break;
		}

		// Redirect back to the list table.
		edd_redirect( wp_get_referer() );
	}

	/**
	 * Bulk helper: mark cart recovered.
	 */
	public function mark_cart_recovered( int $cart_id ): bool {
		return $this->cart_repo->update_status( $cart_id, 'recovered' );
	}

	/**
	 * Bulk helper: delete cart.
	 */
	public function delete_cart( int $cart_id ): bool {
		return $this->cart_repo->delete_cart( $cart_id );
	}

	/**
	 * Bulk helper: send recovery email.
	 *
	 * @since 3.6.5
	 * @param int $cart_id The cart ID.
	 * @return bool Whether the email was sent successfully.
	 */
	public function send_email( int $cart_id ): bool {
		return (bool) $this->email_service->send_recovery_email( $cart_id );
	}

	/**
	 * Bulk helper: mark multiple carts as recovered using a single database query.
	 *
	 * @since 3.6.5
	 * @param array $cart_ids The cart IDs.
	 * @return bool Whether the carts were marked as recovered successfully.
	 */
	public function mark_carts_recovered_bulk( array $cart_ids ): bool {
		if ( empty( $cart_ids ) ) {
			return false;
		}

		return $this->cart_repo->update_status_bulk( $cart_ids, 'recovered' );
	}

	/**
	 * Bulk helper: delete multiple carts using a single database query.
	 *
	 * @since 3.6.5
	 * @param array $cart_ids The cart IDs.
	 * @return bool Whether the carts were deleted successfully.
	 */
	public function delete_carts_bulk( array $cart_ids ): bool {
		if ( empty( $cart_ids ) ) {
			return false;
		}

		return $this->cart_repo->delete_carts_bulk( $cart_ids );
	}

	/**
	 * AJAX callback: mark recovered.
	 *
	 * @since 3.6.5
	 */
	public function ajax_mark_recovered(): void {
		if ( ! current_user_can( 'manage_shop_settings' ) ) {
			wp_send_json_error(
				array( 'message' => __( 'Permission denied.', 'easy-digital-downloads' ) ),
				403
			);
		}

		check_ajax_referer( 'edd_acr_nonce', 'nonce' );

		$cart_id = $this->get_cart_id_from_request();
		if ( ! $cart_id ) {
			wp_send_json_error(
				array( 'message' => __( 'Invalid cart identifier.', 'easy-digital-downloads' ) ),
				400
			);
		}

		if ( ! $this->mark_cart_recovered( $cart_id ) ) {
			$this->log_failure( 'mark_recovered', $cart_id );
			wp_send_json_error(
				array( 'message' => __( 'Unable to update cart status.', 'easy-digital-downloads' ) ),
				500
			);
		}

		wp_send_json_success( __( 'Cart marked as recovered.', 'easy-digital-downloads' ) );
	}

	/**
	 * AJAX callback: delete cart.
	 *
	 * @since 3.6.5
	 */
	public function ajax_delete_cart(): void {
		if ( ! current_user_can( 'manage_shop_settings' ) ) {
			wp_send_json_error(
				array( 'message' => __( 'Permission denied.', 'easy-digital-downloads' ) ),
				403
			);
		}

		check_ajax_referer( 'edd_acr_nonce', 'nonce' );

		$cart_id = $this->get_cart_id_from_request();
		if ( ! $cart_id ) {
			wp_send_json_error(
				array( 'message' => __( 'Invalid cart identifier.', 'easy-digital-downloads' ) ),
				400
			);
		}

		if ( ! $this->delete_cart( $cart_id ) ) {
			$this->log_failure( 'delete_cart', $cart_id );
			wp_send_json_error(
				array( 'message' => __( 'Failed to delete cart.', 'easy-digital-downloads' ) ),
				500
			);
		}

		wp_send_json_success( __( 'Cart deleted.', 'easy-digital-downloads' ) );
	}

	/**
	 * Handles the edd-action URL parameter for sending a recovery email.
	 *
	 * This follows the same pattern as edd_resend_purchase_receipt for consistency.
	 *
	 * @since 3.6.5
	 * @param array $data Request data from $_GET.
	 */
	public function handle_send_recovery_email( $data ): void {
		// Check user capability.
		if ( ! current_user_can( 'manage_shop_settings' ) ) {
			wp_die(
				esc_html__( 'You do not have permission to send recovery emails.', 'easy-digital-downloads' ),
				esc_html__( 'Error', 'easy-digital-downloads' ),
				array( 'response' => 403 )
			);
		}

		// Verify nonce.
		if ( ! isset( $data['_wpnonce'] ) || ! wp_verify_nonce( $data['_wpnonce'], 'edd_acr_send_recovery_email' ) ) {
			wp_die(
				esc_html__( 'Security verification failed.', 'easy-digital-downloads' ),
				esc_html__( 'Error', 'easy-digital-downloads' ),
				array( 'response' => 403 )
			);
		}

		// Get cart ID.
		$cart_id = isset( $data['cart_id'] ) ? absint( $data['cart_id'] ) : 0;
		if ( ! $cart_id ) {
			wp_die(
				esc_html__( 'Invalid cart identifier.', 'easy-digital-downloads' ),
				esc_html__( 'Error', 'easy-digital-downloads' ),
				array( 'response' => 400 )
			);
		}

		// Send the email.
		$sent = $this->send_email( $cart_id );

		// Add transient notice.
		if ( $sent ) {
			EDD()->notices->add_transient_notice(
				'edd-acr-email-sent',
				__( 'Recovery email sent successfully.', 'easy-digital-downloads' ),
				'success'
			);
		} else {
			EDD()->notices->add_transient_notice(
				'edd-acr-email-failed',
				__( 'Failed to send recovery email.', 'easy-digital-downloads' ),
				'error'
			);
		}

		// Redirect back without the action parameters.
		edd_redirect(
			remove_query_arg( array( 'edd-action', 'cart_id', '_wpnonce' ) )
		);
	}

	/**
	 * Extracts a cart ID from the current request.
	 *
	 * @since 3.6.5
	 * @return int The cart ID.
	 */
	private function get_cart_id_from_request(): int {
		$cart_id = isset( $_POST['cart_id'] ) ? wp_unslash( $_POST['cart_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Missing

		return absint( $cart_id );
	}

	/**
	 * Logs failures for debugging if available.
	 *
	 * @since 3.6.5
	 * @param string $context The context of the failure.
	 * @param int    $cart_id The cart ID.
	 * @return void
	 */
	private function log_failure( string $context, int $cart_id ): void {
		$this->log( sprintf( '%s failed for cart ID %d', $context, $cart_id ), true );
	}

	/**
	 * Add an admin notice using EDD's notice system.
	 *
	 * @since 3.6.5
	 * @param string $message The message to display.
	 * @param string $type    The notice type (success, error, warning, info).
	 * @return void
	 */
	private function add_admin_notice( string $message, string $type = 'success' ): void {
		EDD()->notices->add_transient_notice(
			'edd_acr_bulk_action',
			$message,
			$type
		);
	}
}
