<?php

namespace KupShop\OrderingBundle\Admin\Actions;

use KupShop\AdminBundle\Admin\Actions\AbstractAction;
use KupShop\AdminBundle\Admin\Actions\ActionResult;
use KupShop\AdminBundle\Admin\Actions\IAction;
use KupShop\AdminBundle\Admin\Actions\OrderActionResult;
use KupShop\AdminBundle\Admin\Actions\OrderActionWrapper;
use KupShop\OrderDiscountBundle\Util\DiscountManager;
use KupShop\OrderingBundle\Exception\CartValidationException;
use KupShop\OrderingBundle\Util\Purchase\PurchaseUtil;

class UseDiscountCouponAction extends AbstractAction implements IAction
{
    /** @var OrderActionWrapper */
    private $orderActionWrapper;

    /** @var PurchaseUtil */
    protected $purchaseUtil;

    /** @var DiscountManager */
    protected $discountManager;

    /**
     * @required
     */
    public function setOrderActionWrapper(OrderActionWrapper $orderActionWrapper): void
    {
        $this->orderActionWrapper = $orderActionWrapper;
    }

    /**
     * @required
     */
    public function setPurchaseUtil(PurchaseUtil $purchaseUtil): void
    {
        $this->purchaseUtil = $purchaseUtil;
    }

    /**
     * @required
     */
    public function setDiscountManager(?DiscountManager $discountManager): void
    {
        $this->discountManager = $discountManager;
    }

    public function getTypes(): array
    {
        return ['orders'];
    }

    public function isEnabled()
    {
        return findModule(\Modules::ORDER_DISCOUNT);
    }

    public function getName(): string
    {
        return translate('useDiscountCode', 'orders');
    }

    public function execute(&$data, array $config, string $type): ActionResult
    {
        return $this->orderActionWrapper->wrap(function (\Order &$order) use ($config) {
            $coupon = trim($config['couponNumber']);
            if (empty($coupon)) {
                return (new OrderActionResult(false, 'Kód kupónu je prázdný.'))->setRecalculate(false);
            }

            if ($coupons = $order->getData('discounts')['used_coupons'] ?? []) {
                $coupon_already_used = in_array(
                    strtolower($coupon),
                    array_map('strtolower', $coupons)
                );

                if ($coupon_already_used) {
                    return (new OrderActionResult(false, 'Slevový kód už byl na objednávku uplatněn.'))->setRecalculate(false);
                }
            }

            $order_discounts = [];
            if (!$this->discountManager->couponNumberExists($coupon, $order_discounts)) {
                return (new OrderActionResult(false, 'Slevový kód neexistuje.'))->setRecalculate(false);
            }

            $purchaseState = $this->purchaseUtil->createStateFromOrder($order, true);
            $purchaseState->addCoupon($coupon);
            $this->discountManager->setPurchaseState($purchaseState);
            try {
                $this->discountManager->recalculate($order_discounts);
                $this->purchaseUtil->ensureTotalIsNotNegative($purchaseState);

                $applied = [];
                foreach ($order_discounts as $id => $order_discount) {
                    if (in_array($id, $purchaseState->getUsedDiscounts())) {
                        $applied[] = $order_discount;
                    }
                }

                if (!$applied) {
                    if ($user_messages = $this->discountManager->getUserMessages()) {
                        $message = implode("\r\n", array_column($user_messages, 'message'));
                    } else {
                        $message = translate_shop('error', 'order')['coupon_not_valid'];
                    }

                    return (new OrderActionResult(false, $message))->setRecalculate(false);
                }

                $coupons = $purchaseState->getActiveCoupons();
                $purchaseState->setCustomData(['used_coupons' => array_keys($coupons)]);

                $this->purchaseUtil->createOrderFromPurchaseState($purchaseState, $order->id);
                $order->logHistory("Slevový kupón '{$coupon}' byl přidán k objednávce.");
                $order = \Order::get($order->id);

                return (new OrderActionResult(true, 'Slevový kupón byl přidán k objednávce.'))->setRecalculate(false);
            } catch (CartValidationException $e) {
                return (new OrderActionResult(false, $e->getMessage()))->setRecalculate(false);
            }
        });
    }
}
