<?php

namespace Leadlion\SalesOrder\Plugin\Model\Quote\Item;

use Magento\Framework\App\RequestInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Quote\Model\Quote\Item;
use Magento\Quote\Model\Quote\Item\AbstractItem;
use Magento\SalesRule\Model\Validator;
use Mageplaza\EditOrder\Helper\Data as HelperData;

/**
 * Class CustomDiscount
 * @package Mageplaza\EditOrder\Plugin\Model
 */
class CustomDiscount
{
    /**
     * @var RequestInterface
     */
    protected $_request;

    /**
     * @var HelperData
     */
    protected $_helperData;

    /**
     * CustomDiscount constructor.
     *
     * @param RequestInterface $request
     * @param HelperData $helperData
     */
    public function __construct(
        RequestInterface $request,
        HelperData $helperData
    ) {
        $this->_request    = $request;
        $this->_helperData = $helperData;
    }

    /**
     * AfterSortItemsByPriority
     *
     * @param Validator $subject
     * @param array $result
     * @param Item[] $items
     *
     * @return array
     * @throws LocalizedException
     */
    public function afterSortItemsByPriority(Validator $subject, $result, $items)
    {
        if (!$this->_helperData->isMpEdit()) {
            return $result;
        }
        $request = $this->_request->getParams();
        if (!isset($request['item'])
            || !count($items)
            || !str_contains($this->_request->getFullActionName(), 'mpeditorder')
            || !$this->_helperData->isEnabled($items[0]->getStore()->getId())) {

            return $result;
        }

        foreach ($items as $item) {
            foreach ($request['item'] as $itemId => $data) {
                if ($itemId === (int) $item->getId()) {
                    if (isset($data['discount_type']) && $data['discount_type'] !== 'default') {
                        $type      = $data['discount_type'];
                        $value     = (is_numeric($data['discount_value']) && $data['discount_value'] > 0)
                            ? $data['discount_value'] : 0;
                        $itemPrice = $subject->getItemPrice($item);
                        if ($itemPrice < 0) {
                            return $result;
                        }

                        $this->calculateDiscount($type, $value, $item, $itemPrice);
                        $children = $item->getChildren();
                        if (!empty($children)) {
                            foreach ($children as $child) {
                                $this->calculateDiscount($type, $value, $child, $subject->getItemPrice($child));
                            }
                        }
                    } else {
                        $item->setMpCustomDiscountType(null);
                        $item->setMpCustomDiscountValue(null);
                    }
                }
            }
        }

        return $result;
    }

    /**
     * CalculateDiscount
     *
     * @param string $type
     * @param string $value
     * @param Item|AbstractItem $item
     * @param string $itemPrice
     *
     * @return void
     * @throws LocalizedException
     */
    public function calculateDiscount($type, $value, $item, $itemPrice)
    {
        if ($item->getParentItem() && $item->getParentItem()->getProductType() === 'bundle') {
            return;
        }

        if ($itemPrice <= 0 || $item->getProductType() === 'bundle') {
            $item->setMpCustomDiscountType($type);
            $item->setMpCustomDiscountValue($value);
            
            if ($item->getProductType() === 'bundle' && $item->getHasChildren()) {
                $this->distributeBundleDiscount($type, $value, $item);
            }
            
            return;
        }

        $itemQty            = $this->_helperData->getQtyItem($item);
        $discountAmount     = $type === 'fixed'
            ? $value * $itemQty
            : ($itemPrice * $value * $itemQty) / 100;
        $discountAmount     = min($itemPrice * $itemQty, $discountAmount);
        $discountPercent    = $type === 'percent' ? $value : ($value * 100) / $itemPrice;
        $baseDiscountAmount = $discountAmount / $item->getStore()->getCurrentCurrencyRate();
        
        $item->setDiscountAmount($discountAmount);
        $item->setBaseDiscountAmount($baseDiscountAmount);
        $item->setDiscountPercent($discountPercent);
        $item->setMpCustomDiscountType($type);
        $item->setMpCustomDiscountValue($value);
    }

    /**
     * Distribute discount proportionally to bundle children
     * 
     * @param string $type
     * @param float $value
     * @param \Magento\Quote\Model\Quote\Item $parentItem
     */
    protected function distributeBundleDiscount($type, $value, $parentItem)
    {
        $children = $parentItem->getChildren();
        if (!$children) {
            return;
        }
        
        $totalChildrenPrice = 0;
        foreach ($children as $child) {
            $childQty = $this->_helperData->getQtyItem($child);
            $totalChildrenPrice += $child->getPriceInclTax() * $childQty;
        }
        
        if ($totalChildrenPrice <= 0) {
            return;
        }
        
        $totalDiscountAmount = $type === 'fixed'
            ? $value
            : ($totalChildrenPrice * $value) / 100;
        $totalDiscountAmount = min($totalChildrenPrice, $totalDiscountAmount);
        
        foreach ($children as $child) {
            $childQty = $this->_helperData->getQtyItem($child);
            $childPrice = $child->getPriceInclTax() * $childQty;
            
            $childDiscountRatio = $childPrice / $totalChildrenPrice;
            $childDiscountAmount = $totalDiscountAmount * $childDiscountRatio;
            
            $childDiscountPercent = $childPrice > 0 
                ? ($childDiscountAmount * 100) / $childPrice 
                : 0;
            $childBaseDiscountAmount = $childDiscountAmount / $child->getStore()->getCurrentCurrencyRate();
            
            $child->setDiscountAmount($childDiscountAmount);
            $child->setBaseDiscountAmount($childBaseDiscountAmount);
            $child->setDiscountPercent($childDiscountPercent);
            $child->setMpCustomDiscountType($type);
            $child->setMpCustomDiscountValue($value);
        }
        
        $parentItem->setMpCustomDiscountType($type);
        $parentItem->setMpCustomDiscountValue($value);
    }
}
