<?php

/**
 * Endpoint to update payment data like shipping method and address.
 *
 * @package WooCommerce\PayPalCommerce\Button\Endpoint
 */
declare (strict_types=1);
namespace WooCommerce\PayPalCommerce\Googlepay\Endpoint;

use WooCommerce\PayPalCommerce\Vendor\Psr\Log\LoggerInterface;
use Throwable;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
use WooCommerce\PayPalCommerce\Button\Exception\NonceValidationException;
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
/**
 * Class UpdatePaymentDataEndpoint
 */
class UpdatePaymentDataEndpoint
{
    const ENDPOINT = 'ppc-googlepay-update-payment-data';
    /**
     * The request data helper.
     *
     * @var RequestData
     */
    private $request_data;
    /**
     * The logger.
     *
     * @var LoggerInterface
     */
    private $logger;
    /**
     * UpdatePaymentDataEndpoint constructor.
     *
     * @param RequestData     $request_data The request data helper.
     * @param LoggerInterface $logger The logger.
     */
    public function __construct(RequestData $request_data, LoggerInterface $logger)
    {
        $this->request_data = $request_data;
        $this->logger = $logger;
    }
    /**
     * Returns the nonce.
     *
     * @return string
     */
    public static function nonce(): string
    {
        return self::ENDPOINT;
    }
    /**
     * Handles the request.
     *
     * @throws RuntimeException When a validation fails.
     */
    public function handle_request(): void
    {
        try {
            $data = $this->request_data->read_request($this->nonce());
            // Validate payment data.
            if (!isset($data['paymentData'])) {
                throw new RuntimeException(__('No paymentData provided.', 'woocommerce-paypal-payments'));
            }
            $payment_data = $data['paymentData'];
            // Set context as cart.
            if (is_callable('wc_maybe_define_constant')) {
                // @phpstan-ignore function.alreadyNarrowedType
                wc_maybe_define_constant('WOOCOMMERCE_CART', \true);
            }
            $this->update_addresses($payment_data);
            $this->update_shipping_method($payment_data);
            WC()->cart->calculate_shipping();
            WC()->cart->calculate_fees();
            WC()->cart->calculate_totals();
            $total = (float) WC()->cart->get_total('numeric');
            $shipping_fee = (float) WC()->cart->get_shipping_total();
            // Shop settings.
            $base_location = wc_get_base_location();
            $shop_country_code = $base_location['country'];
            $currency_code = get_woocommerce_currency();
            wp_send_json_success(array('total' => $total, 'shipping_fee' => $shipping_fee, 'currency_code' => $currency_code, 'country_code' => $shop_country_code, 'shipping_options' => $this->get_shipping_options()));
        } catch (NonceValidationException $error) {
            wp_send_json_error(array('message' => $error->getMessage()), 400);
        } catch (Throwable $error) {
            $this->logger->error("UpdatePaymentDataEndpoint execution failed. {$error->getMessage()} {$error->getFile()}:{$error->getLine()}");
            wp_send_json_error();
        }
    }
    /**
     * Returns the array of available shipping methods.
     *
     * @return array
     */
    public function get_shipping_options(): array
    {
        $shipping_options = array();
        $calculated_packages = WC()->shipping->calculate_shipping(WC()->cart->get_shipping_packages());
        if (!isset($calculated_packages[0]) && !isset($calculated_packages[0]['rates'])) {
            return array();
        }
        foreach ($calculated_packages[0]['rates'] as $rate) {
            /**
             * The shipping rate.
             *
             * @var \WC_Shipping_Rate $rate
             */
            $shipping_options[] = array('id' => $rate->get_id(), 'label' => $rate->get_label(), 'description' => html_entity_decode(wp_strip_all_tags(wc_price((float) $rate->get_cost(), array('currency' => get_woocommerce_currency()))), \ENT_QUOTES, 'UTF-8'), 'cost' => $rate->get_cost());
        }
        if (!isset($shipping_options[0])) {
            return array();
        }
        $chosen_shipping_methods = WC()->session->get('chosen_shipping_methods');
        return array('defaultSelectedOptionId' => $chosen_shipping_methods[0] ?? null ? $chosen_shipping_methods[0] : $shipping_options[0]['id'], 'shippingOptions' => $shipping_options);
    }
    /**
     * Update addresses.
     *
     * @param array $payment_data The payment data.
     * @return void
     */
    private function update_addresses(array $payment_data): void
    {
        if (!in_array($payment_data['callbackTrigger'] ?? '', array('SHIPPING_ADDRESS', 'INITIALIZE'), \true)) {
            return;
        }
        /**
         * The shipping methods.
         *
         * @var \WC_Customer|null $customer
         */
        $customer = WC()->customer;
        if (!$customer) {
            return;
        }
        $customer->set_billing_postcode($payment_data['shippingAddress']['postalCode'] ?? '');
        $customer->set_billing_country($payment_data['shippingAddress']['countryCode'] ?? '');
        $customer->set_billing_state('');
        $customer->set_billing_city($payment_data['shippingAddress']['locality'] ?? '');
        $customer->set_shipping_postcode($payment_data['shippingAddress']['postalCode'] ?? '');
        $customer->set_shipping_country($payment_data['shippingAddress']['countryCode'] ?? '');
        $customer->set_shipping_state('');
        $customer->set_shipping_city($payment_data['shippingAddress']['locality'] ?? '');
        // Save the data.
        $customer->save();
        WC()->session->set('customer', WC()->customer->get_data());
    }
    /**
     * Update shipping method.
     *
     * @param array $payment_data The payment data.
     * @return void
     */
    private function update_shipping_method(array $payment_data): void
    {
        $rate_id = $payment_data['shippingOptionData']['id'];
        $calculated_packages = WC()->shipping->calculate_shipping(WC()->cart->get_shipping_packages());
        if ($rate_id && isset($calculated_packages[0]['rates'][$rate_id])) {
            WC()->session->set('chosen_shipping_methods', array($rate_id));
        }
    }
}
