<?php

namespace YSquare\GiftCert\Model;

use OxidEsales\Eshop\Core\Price;
use OxidEsales\Eshop\Core\Registry;

class Basket extends Basket_parent
{

    /**
     * Array of gift certificates applied on basket price
     *
     * @var array
     */
    protected $_aGiftcerts = array();

    /**
     * Array of gift certificates applied on basket price
     *
     * @var array
     */
    protected $_aGiftcertRealDiscount = array();

    /**
     * current active Discount from gift certificates
     *
     * @var float
     */
    protected $_giftCertSum = 0.0;

    /**
     * brutto Price before Pool is used
     */
    protected $_giftCertIntermediateTotal = 0;

    /**
     * currently used amount of giftcert pool money
     */
    protected $_giftCertPoolAmountUsed = 0;


    /**
     * Checks and sets gift cert information.
     *
     * @param string $sGiftcertId gift cert ID
     */
    public function addGiftcert($sGiftcertId)
    {
        try { // trying to load voucher and apply it

            $oGiftcert = oxNew(\YSquare\GiftCert\Model\GiftCert::class);

            $oGiftcert->getGiftcertByNr($sGiftcertId, true);
            $oGiftcert->isNotReserved();
            $oGiftcert->markAsReserved();


            // saving voucher info
            $this->_aGiftcerts[$oGiftcert->ysgiftcert__ysgiftcertnr->value] = $oGiftcert;
        } catch (\OxidEsales\Eshop\Core\Exception\VoucherException $oEx) {

            // problems adding voucher
            Registry::get("oxUtilsView")->addErrorToDisplay($oEx, false, true);
        }

        $this->onUpdate();
    }

    /**
     * Removes Giftcert from basket if it exists
     *
     * @param $sGiftcertId
     * @throws oxSystemComponentException
     */
    public function removeGiftcert($sGiftcertId)
    {
        // removing if it exists
        if (isset($this->_aGiftcerts[$sGiftcertId])) {
            $oGiftcert = oxNew(GiftCert::class);
            $oGiftcert->getGiftcertByNr($sGiftcertId);
            $oGiftcert->unMarkAsReserved();

            // unset it if exists this voucher in DB or not
            unset($this->_aGiftcerts[$sGiftcertId]);
        }
        $this->onUpdate();
    }

    /**
     * List of Gift Certificates in basket
     *
     * @return array
     */
    public function getGiftCertList()
    {
        return $this->_aGiftcerts;
    }

    /**
     * Sum of the value of all redeemed gift certificates
     *
     * @return object
     * @throws oxSystemComponentException
     */
    public function getGiftCertSum()
    {
        if ($this->_giftCertSum > 0) {
            $oTotalPrice = oxNew(Price::class);
            $oTotalPrice->setBruttoPriceMode();
            $oTotalPrice->setPrice($this->_giftCertSum);
            return $oTotalPrice;
        }
        return false;
    }

    /**
     * @param $giftcertNr
     * @return int|mixed
     */
    public function getGiftCertRealDiscount($giftcertNr)
    {
        $realDiscount = 0;
        if (isset($this->_aGiftcertRealDiscount[$giftcertNr])) {
            $realDiscount = $this->_aGiftcertRealDiscount[$giftcertNr];
        }
        $oDiscountPrice = oxNew(Price::class);
        $oDiscountPrice->setBruttoPriceMode();
        $oDiscountPrice->setPrice($realDiscount);
        return $oDiscountPrice;
    }

    /**
     * Returns the Sum before pool is applied
     *
     * @return mixed|Price
     */
    public function getGiftcertIntermediateTotal()
    {
        $intermediateSum = oxNew(Price::class);
        $intermediateSum->setBruttoPriceMode();
        $intermediateSum->setPrice($this->_giftCertIntermediateTotal);
        return $intermediateSum;
    }

    /**
     * Returns the price that is actually used out of the giftcert money pool
     *
     * @return mixed|Price
     */
    public function getGiftCertUsedPoolAmount()
    {
//        if($this->_giftCertPoolAmountUsed > 0) {
        $poolPrice = oxNew(Price::class);
        $poolPrice->setBruttoPriceMode();
        $poolPrice->setPrice($this->_giftCertPoolAmountUsed);
        return $poolPrice;
//        }
//        return false;
    }

    /**
     * Recalculates the total price after subtraction of redeemed gift certificates
     *
     * @throws oxSystemComponentException
     */
    protected function _calcTotalPrice()
    {
        parent::_calcTotalPrice();

        // subtract all gift certificates from Article brutto and add costs again (diff of article brutto and total)
        $this->_giftCertSum = 0;
        $currentTotal = $this->getPrice()->getPrice();
        $bruttoSumArticles = $this->getBruttoSum() - $this->_oVoucherDiscount->getPrice();

        //get delivery costs
        $oDeliveryCost = $this->getDeliveryCost();
        if ($oDeliveryCost) {
            //add delivery costs so voucher is also applied for delivery costs
            $bruttoSumArticles += $oDeliveryCost->getBruttoPrice();
        }

        $diffTotalProductsPrice = $currentTotal - $bruttoSumArticles;

        foreach ($this->_aGiftcerts as $giftcert) {
            $bruttoSumArticles -= $giftcert->ysgiftcert__ysrestdiscount->value;
            if ($bruttoSumArticles >= 0) {
                $this->_giftCertSum += $giftcert->ysgiftcert__ysrestdiscount->value;
                $this->_aGiftcertRealDiscount[$giftcert->ysgiftcert__ysgiftcertnr->value] = $giftcert->ysgiftcert__ysrestdiscount->value;
            } else {
                // if discount is higher than articles value just add the discount needed to reach 0
                $this->_giftCertSum += $giftcert->ysgiftcert__ysrestdiscount->value + $bruttoSumArticles;
                $this->_aGiftcertRealDiscount[$giftcert->ysgiftcert__ysgiftcertnr->value] = $giftcert->ysgiftcert__ysrestdiscount->value + $bruttoSumArticles;
                $bruttoSumArticles = 0;
                break;
            }
        }

        // Store the final price before pool amount is applied
        $this->_giftCertIntermediateTotal = $bruttoSumArticles;

        // If Redeem Pool is activated we check if the user wants to use it
        // and use it to reduce the basket value
        $usePoolMoney = $this->useMoneyPool();

        if (Registry::getConfig()->getConfigParam('blYsGiftcertRedeemToPool')
            && $bruttoSumArticles > 0
            && $usePoolMoney == 1) {
            $myuser = $this->getUser();
            $poolBalance = $myuser->oxuser__ys_giftcert_pool_amount->value;
            $bruttoSumArticles -= $poolBalance;
            if ($bruttoSumArticles < 0) {
                $this->_giftCertPoolAmountUsed = $bruttoSumArticles + $poolBalance;
                $bruttoSumArticles = 0;
            } else {
                $this->_giftCertPoolAmountUsed = $poolBalance;
            }
        } else {
            $this->_giftCertPoolAmountUsed = 0;
        }

        $oTotalPrice = oxNew(Price::class);
        $oTotalPrice->setBruttoPriceMode();
        $oTotalPrice->setPrice($bruttoSumArticles + $diffTotalProductsPrice);
        $this->setPrice($oTotalPrice);
        $this->_oTotalDiscount->add($this->_giftCertPoolAmountUsed + $this->_giftCertSum);
    }

    public function getPriceForPayment()
    {
        $dPrice = parent::getPriceForPayment();

        foreach ($this->_aGiftcerts as $giftcert) {
            $dPrice -= $giftcert->ysgiftcert__ysrestdiscount->value;
            if ($dPrice < 0) {
                $dPrice = 0;
                break;
            }
        }
        if ($this->useMoneyPool()) {
            $dPrice -= $this->_giftCertPoolAmountUsed;
            if ($dPrice < 0) {
                $dPrice = 0;
            }
        }

        return $dPrice;
    }

    /**
     * Checks if the money pool should be used (aka was selected by the user to use)
     *
     * @return mixed|string|null
     */
    public function useMoneyPool()
    {
        $usePoolMoney = Registry::getRequest()->getRequestEscapedParameter('ys_giftcert_use_pool_money');
        if ($usePoolMoney != 1) {
            $session = Registry::getSession();
            $usePoolMoney = $session->getVariable('ys_giftcert_use_pool_money');
        }
        return $usePoolMoney;
    }

    /**
     * KLARNA Workaround to add our vouchers as discounts
     *
     */
    protected function _addDiscountsAsProducts($oOrder = null, $iLang = null)
    {
        // First let KLARNA do its stuff
        parent::_addDiscountsAsProducts($oOrder, $iLang);

        // Now add our Total Giftcerts Value as another discount
        $giftcertSumup = $this->_giftCertPoolAmountUsed + $this->_giftCertSum;
        $oGiftcertDiscount = oxNew(Price::class);
        $oGiftcertDiscount->setBruttoPriceMode();
        $oGiftcertDiscount->add($giftcertSumup);

        if ($this->_isServicePriceSet($oGiftcertDiscount)) {
            $this->klarnaOrderLines[] = $this->_getKlarnaCheckoutVoucherDiscount($oGiftcertDiscount, $iLang);
        }
    }
}