<?php

declare(strict_types=1);

namespace Australcode\Rewards\Rest;

use Australcode\Rewards\Domain\Redemption\RedemptionQuote;
use Australcode\Rewards\Hooks\RedemptionCartHook;
use Australcode\Rewards\Service\RedemptionService;
use WP_REST_Request;
use WP_REST_Response;

defined( 'ABSPATH' ) || exit;

/**
 * REST endpoints under acrwd/v1/redemption:
 *  - GET  /redemption/quote   preview points -> discount (no side effects)
 *  - POST /redemption/apply   store the chosen points in the cart session
 *  - POST /redemption/clear   remove the redemption from the session
 *
 * The actual debit happens at checkout (RedemptionCartHook), not here.
 */
final class RedemptionController extends AbstractController {

	public function __construct(
		private readonly RedemptionService $redemption,
		private readonly RedemptionCartHook $cart,
	) {
	}

	public function register(): void {
		add_action( 'rest_api_init', array( $this, 'register_routes' ) );
	}

	public function register_routes(): void {
		$points_arg = array(
			'points' => array(
				'type'              => 'integer',
				'required'          => true,
				'sanitize_callback' => 'absint',
			),
		);

		register_rest_route(
			self::REST_NAMESPACE,
			'/redemption/quote',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'get_quote' ),
				'permission_callback' => array( $this, 'check_logged_in' ),
				'args'                => $points_arg,
			)
		);

		register_rest_route(
			self::REST_NAMESPACE,
			'/redemption/apply',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'apply' ),
				'permission_callback' => array( $this, 'check_logged_in' ),
				'args'                => $points_arg,
			)
		);

		register_rest_route(
			self::REST_NAMESPACE,
			'/redemption/clear',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'clear' ),
				'permission_callback' => array( $this, 'check_logged_in' ),
			)
		);
	}

	public function check_logged_in(): bool {
		return is_user_logged_in();
	}

	public function get_quote( WP_REST_Request $request ): WP_REST_Response {
		$quote = $this->redemption->quote(
			get_current_user_id(),
			(int) $request->get_param( 'points' ),
			$this->cart_subtotal()
		);
		return new WP_REST_Response( $this->payload( $quote ), 200 );
	}

	public function apply( WP_REST_Request $request ): WP_REST_Response {
		$quote = $this->redemption->quote(
			get_current_user_id(),
			(int) $request->get_param( 'points' ),
			$this->cart_subtotal()
		);

		if ( ! $quote->valid ) {
			return new WP_REST_Response( $this->payload( $quote ), 422 );
		}

		$this->cart->set_session_points( $quote->points );
		return new WP_REST_Response( $this->payload( $quote ), 200 );
	}

	public function clear( WP_REST_Request $request ): WP_REST_Response {
		unset( $request );
		$this->cart->clear_session();
		return new WP_REST_Response( array( 'cleared' => true ), 200 );
	}

	private function cart_subtotal(): float {
		$cart = WC()->cart;
		return null !== $cart ? (float) $cart->get_subtotal() : 0.0;
	}

	/**
	 * @return array<string,mixed>
	 */
	private function payload( RedemptionQuote $quote ): array {
		return array(
			'valid'  => $quote->valid,
			'points' => $quote->points,
			'amount' => $quote->amount,
			'reason' => $quote->reason,
		);
	}
}
