<?php

declare (strict_types=1);
namespace DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Service\Ucp\Checkout\Builder;

use Automattic\WooCommerce\StoreApi\Utilities\CartController;
use WC_Customer;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Service\Ucp\Checkout\State\CheckoutSessionDataRepository;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Service\Ucp\Checkout\Violations\Violation;
use DropshippingExportFreeVendor\WPDesk\Library\DropshippingExport\Service\Ucp\Checkout\Violations\Violations;
/**
 * Applies UCP fulfillment data to WooCommerce customer and shipping.
 *
 * @see https://ucp.dev/2026-01-23/schemas/shopping/types/fulfillment.json
 *
 * @phpstan-import-type ShippingDestination from CheckoutSessionBuilder
 * @phpstan-import-type FulfillmentOption from CheckoutSessionBuilder
 * @phpstan-import-type FulfillmentGroup from CheckoutSessionBuilder
 * @phpstan-import-type FulfillmentMethod from CheckoutSessionBuilder
 * @phpstan-import-type Fulfillment from CheckoutSessionBuilder
 */
final class FulfillmentApplier
{
    private CartController $cart_controller;
    private CheckoutSessionDataRepository $session_data;
    public function __construct(CartController $cart_controller, CheckoutSessionDataRepository $session_data)
    {
        $this->cart_controller = $cart_controller;
        $this->session_data = $session_data;
    }
    /**
     * Set fulfillment address and shipping method from UCP fulfillment data.
     *
     * @param Fulfillment  $fulfillment UCP fulfillment object.
     * @param WC_Customer $customer    WooCommerce customer.
     */
    public function apply(array $fulfillment, WC_Customer $customer): Violations
    {
        $violations = Violations::empty();
        $cart = $this->cart_controller->get_cart_instance();
        $method = $fulfillment['methods'][0] ?? null;
        if (null === $method && $cart->needs_shipping()) {
            $violations = $violations->add(Violation::missing('Shipping address and method are required for physical products', 'fulfillment.methods[0]'));
        }
        if (null === $method) {
            return $violations;
        }
        $this->set_shipping_address($method, $customer);
        $this->select_shipping_rate($method);
        return $violations;
    }
    /**
     * @param FulfillmentMethod $method   Fulfillment method.
     * @param WC_Customer       $customer WooCommerce customer.
     */
    private function set_shipping_address(array $method, WC_Customer $customer): void
    {
        $dest = $this->resolve_destination($method);
        if (null === $dest) {
            return;
        }
        $customer->set_shipping_first_name(\wc_clean(\wp_unslash($dest['first_name'] ?? '')));
        $customer->set_shipping_last_name(\wc_clean(\wp_unslash($dest['last_name'] ?? '')));
        $customer->set_shipping_phone(\wc_clean(\wp_unslash($dest['phone_number'] ?? '')));
        $customer->set_shipping_country(\wc_clean(\wp_unslash($dest['address_country'] ?? '')));
        $customer->set_shipping_postcode(\wc_clean(\wp_unslash($dest['postal_code'] ?? '')));
        $customer->set_shipping_state(\wc_clean(\wp_unslash($dest['address_region'] ?? '')));
        $customer->set_shipping_city(\wc_clean(\wp_unslash($dest['address_locality'] ?? '')));
        $customer->set_shipping_address_1(\wc_clean(\wp_unslash($dest['street_address'] ?? '')));
        $customer->set_shipping_address_2(\wc_clean(\wp_unslash($dest['extended_address'] ?? '')));
        if (isset($dest['id'])) {
            $this->session_data->set_destination_id($dest['id']);
        }
        // Set billing address (copy from shipping if not already set).
        if (!$customer->get_billing_address_1()) {
            $customer->set_billing_first_name(\wc_clean(\wp_unslash($dest['first_name'] ?? '')));
            $customer->set_billing_last_name(\wc_clean(\wp_unslash($dest['last_name'] ?? '')));
            $customer->set_billing_phone(\wc_clean(\wp_unslash($dest['phone_number'] ?? '')));
            $customer->set_billing_country(\wc_clean(\wp_unslash($dest['address_country'] ?? '')));
            $customer->set_billing_postcode(\wc_clean(\wp_unslash($dest['postal_code'] ?? '')));
            $customer->set_billing_state(\wc_clean(\wp_unslash($dest['address_region'] ?? '')));
            $customer->set_billing_city(\wc_clean(\wp_unslash($dest['address_locality'] ?? '')));
            $customer->set_billing_address_1(\wc_clean(\wp_unslash($dest['street_address'] ?? '')));
            $customer->set_billing_address_2(\wc_clean(\wp_unslash($dest['extended_address'] ?? '')));
        }
        $customer->save();
    }
    /**
     * @param FulfillmentMethod $method Fulfillment method.
     */
    private function select_shipping_rate(array $method): void
    {
        if (empty($method['groups'])) {
            return;
        }
        $selected_option_id = $method['groups'][0]['selected_option_id'] ?? null;
        if (null !== $selected_option_id) {
            $this->cart_controller->select_shipping_rate(0, $selected_option_id);
        }
    }
    /**
     * Resolve the selected destination from a fulfillment method.
     *
     * @param FulfillmentMethod $method Fulfillment method.
     * @return ShippingDestination|null Selected destination or first available.
     */
    private function resolve_destination(array $method): ?array
    {
        $selected_id = $method['selected_destination_id'] ?? null;
        $destinations = $method['destinations'] ?? [];
        if (empty($destinations)) {
            return null;
        }
        $destinations = \array_map(static fn($dest) => $dest['root'] ?? $dest, $destinations);
        foreach ($destinations as $dest) {
            if (isset($dest['id']) && $dest['id'] === $selected_id) {
                return $dest;
            }
        }
        return $destinations[0] ?? null;
    }
}
