<?php

/**
 * Endpoint to handle PayPal Subscription created.
 *
 * @package WooCommerce\PayPalCommerce\Button\Endpoint
 */
declare (strict_types=1);
namespace WooCommerce\PayPalCommerce\Button\Endpoint;

use Exception;
use WooCommerce\PayPalCommerce\Vendor\Psr\Log\LoggerInterface;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingSubscriptions;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use WooCommerce\PayPalCommerce\Button\Exception\NonceValidationException;
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\Button\Helper\Context;
use WooCommerce\PayPalCommerce\Button\Helper\WooCommerceOrderCreator;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
/**
 * Class ApproveSubscriptionEndpoint
 */
class ApproveSubscriptionEndpoint implements \WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface
{
    const ENDPOINT = 'ppc-approve-subscription';
    const VALID_SUBSCRIPTION_STATUSES = array('ACTIVE', 'APPROVED');
    /**
     * Helper providing context: is current page is checkout, what type of checkout it is, etc.
     *
     * @var Context $context
     */
    private Context $context;
    /**
     * The request data helper.
     *
     * @var RequestData
     */
    private $request_data;
    /**
     * The order endpoint.
     *
     * @var OrderEndpoint
     */
    private $order_endpoint;
    /**
     * The session handler.
     *
     * @var SessionHandler
     */
    private $session_handler;
    /**
     * Whether the final review is enabled.
     *
     * @var bool
     */
    protected $final_review_enabled;
    /**
     * The WooCommerce order creator.
     *
     * @var WooCommerceOrderCreator
     */
    protected $wc_order_creator;
    /**
     * The WC gateway.
     *
     * @var PayPalGateway
     */
    protected $gateway;
    private BillingSubscriptions $billing_subscriptions;
    private LoggerInterface $logger;
    private SubscriptionHelper $subscription_helper;
    public function __construct(\WooCommerce\PayPalCommerce\Button\Endpoint\RequestData $request_data, OrderEndpoint $order_endpoint, SessionHandler $session_handler, bool $final_review_enabled, WooCommerceOrderCreator $wc_order_creator, PayPalGateway $gateway, Context $context, BillingSubscriptions $billing_subscriptions, LoggerInterface $logger, SubscriptionHelper $subscription_helper)
    {
        $this->request_data = $request_data;
        $this->order_endpoint = $order_endpoint;
        $this->session_handler = $session_handler;
        $this->final_review_enabled = $final_review_enabled;
        $this->wc_order_creator = $wc_order_creator;
        $this->gateway = $gateway;
        $this->context = $context;
        $this->billing_subscriptions = $billing_subscriptions;
        $this->logger = $logger;
        $this->subscription_helper = $subscription_helper;
    }
    /**
     * The nonce.
     *
     * @return string
     */
    public static function nonce(): string
    {
        return self::ENDPOINT;
    }
    /**
     * Handles the request.
     *
     * @throws RuntimeException When order not found or handling failed.
     */
    public function handle_request(): void
    {
        try {
            $data = $this->request_data->read_request($this->nonce());
            if (!isset($data['order_id'])) {
                throw new RuntimeException('No order id given');
            }
            $order = $this->order_endpoint->order($data['order_id']);
            $this->session_handler->replace_order($order);
            $paypal_subscription_id = $data['subscription_id'];
            if (isset($paypal_subscription_id)) {
                $this->validate_subscription($paypal_subscription_id);
                WC()->session->set('ppcp_subscription_id', $paypal_subscription_id);
            }
            $should_create_wc_order = $data['should_create_wc_order'] ?? \false;
            if (!$this->final_review_enabled && !$this->context->is_checkout() && $should_create_wc_order) {
                $wc_order = $this->wc_order_creator->create_from_paypal_order($order, WC()->cart);
                $this->gateway->process_payment($wc_order->get_id());
                $order_received_url = $wc_order->get_checkout_order_received_url();
                wp_send_json_success(array('order_received_url' => $order_received_url));
            }
            wp_send_json_success();
        } catch (NonceValidationException $error) {
            wp_send_json_error(array('message' => $error->getMessage()), 400);
        } catch (Exception $error) {
            $this->logger->error('Subscription approve failed: ' . $error->getMessage());
            wp_send_json_error(array('name' => $error instanceof PayPalApiException ? $error->name() : '', 'message' => $error->getMessage(), 'code' => $error->getCode(), 'details' => $error instanceof PayPalApiException ? $error->details() : (object) array()));
        }
    }
    /**
     * Validates subscription status and plan ID.
     *
     * @param string $subscription_id The PayPal subscription ID.
     * @throws RuntimeException When subscription status is invalid or plan ID doesn't match.
     */
    private function validate_subscription(string $subscription_id): void
    {
        $subscription = $this->billing_subscriptions->subscription($subscription_id);
        $status = $subscription->status ?? '';
        if (!in_array($status, self::VALID_SUBSCRIPTION_STATUSES, \true)) {
            throw new RuntimeException("Invalid subscription status: {$status}");
        }
        $plan_id = $subscription->plan_id ?? '';
        $expected_plan_id = $this->subscription_helper->paypal_subscription_variation_from_cart();
        if (!$expected_plan_id) {
            $expected_plan_id = $this->subscription_helper->paypal_subscription_id();
        }
        if (!$plan_id || !$expected_plan_id || $plan_id !== $expected_plan_id) {
            throw new RuntimeException('Subscription plan ID does not match any cart product plan');
        }
    }
}