<?php

declare(strict_types=1);

/**
 * Re-check guest email reuse before Magento submits the quote.
 */

namespace Autogedal\PromoRules\Plugin\Quote;

use Autogedal\PromoRules\Model\Rule\PolicyManager;
use Magento\Framework\Exception\LocalizedException;
use Magento\Quote\Model\Quote;
use Magento\Quote\Model\QuoteManagement;

/**
 * Guards guest coupon submission with the one-email-one-use policy.
 */
class QuoteManagementPlugin
{
    /**
     * @param PolicyManager $policyManager
     */
    public function __construct(
        private readonly PolicyManager $policyManager
    ) {
    }

    /**
     * Prevent quote submission when the guest coupon was already consumed by the same email.
     *
     * @param QuoteManagement $subject
     * @param \Closure $proceed
     * @param Quote $quote
     * @param array $orderData
     * @return mixed
     * @throws LocalizedException
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function aroundSubmit(QuoteManagement $subject, \Closure $proceed, Quote $quote, $orderData = [])
    {
        if (!$quote->getCustomerIsGuest()) {
            return $proceed($quote, $orderData);
        }

        $email = $this->policyManager->resolveGuestEmail($quote);
        if ($email === '') {
            return $proceed($quote, $orderData);
        }

        return $this->policyManager->executeGuestEmailLock(
            $email,
            function () use ($quote, $orderData, $proceed) {
                $couponCode = (string) $quote->getCouponCode();
                if ($couponCode !== '' && !$this->policyManager->canUseGuestCouponCode($couponCode, $quote)) {
                    throw new LocalizedException(
                        __('This coupon has already been used with the same guest email address.')
                    );
                }

                $order = $proceed($quote, $orderData);
                if ($order !== null) {
                    $this->policyManager->syncGuestEmailUsage($order, true);
                }

                return $order;
            }
        );
    }
}
