<?php

namespace Thelia\Model;

use Propel\Runtime\Connection\ConnectionInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Thelia\Core\Event\Cart\CartEvent;
use Thelia\Core\Event\Cart\CartItemEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\Base\CartItem as BaseCartItem;
use Thelia\TaxEngine\Calculator;

class CartItem extends BaseCartItem
{
    /** @var EventDispatcherInterface */
    protected $dispatcher;

    /**
     * @param EventDispatcherInterface $dispatcher
     */
    public function setDisptacher(EventDispatcherInterface $dispatcher)
    {
        $this->dispatcher = $dispatcher;
    }

    /**
     * @param ConnectionInterface|null $con
     * @return bool
     */
    public function preInsert(ConnectionInterface $con = null)
    {
        parent::preInsert($con);

        if ($this->dispatcher) {
            $cartItemEvent = new CartItemEvent($this);
            $this->dispatcher->dispatch(TheliaEvents::CART_ITEM_CREATE_BEFORE, $cartItemEvent);
        }
        return true;
    }

    /**
     * @param ConnectionInterface|null $con
     * @return bool
     */
    public function preUpdate(ConnectionInterface $con = null)
    {
        parent::preUpdate($con);

        if ($this->dispatcher) {
            $cartItemEvent = new CartItemEvent($this);
            $this->dispatcher->dispatch(TheliaEvents::CART_ITEM_UPDATE_BEFORE, $cartItemEvent);
        }
        return true;
    }

    /**
     * @param ConnectionInterface|null $con
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function postInsert(ConnectionInterface $con = null)
    {
        parent::postInsert($con);

        if ($this->dispatcher) {
            $cartEvent = new CartEvent($this->getCart());

            $this->dispatcher->dispatch(TheliaEvents::AFTER_CARTADDITEM, $cartEvent);
        }
    }

    /**
     * @param ConnectionInterface|null $con
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function postUpdate(ConnectionInterface $con = null)
    {
        parent::postUpdate($con);

        if ($this->dispatcher) {
            $cartEvent = new CartEvent($this->getCart());

            $this->dispatcher->dispatch(TheliaEvents::AFTER_CARTUPDATEITEM, $cartEvent);
        }
    }

    /**
     * @param $value
     * @return $this
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function updateQuantity($value)
    {
        $currentQuantity = $this->getQuantity();

        if ($value <= 0) {
            $value = $currentQuantity;
        }

        if (ConfigQuery::checkAvailableStock()) {
            $productSaleElements = $this->getProductSaleElements();
            $product = $productSaleElements->getProduct();

            if ($product->getVirtual() === 0) {
                if ($productSaleElements->getQuantity() < $value) {
                    $value = $currentQuantity;
                }
            }
        }

        $this->setQuantity($value);

        return $this;
    }

    /**
     * @param $value
     * @return $this
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function addQuantity($value)
    {
        $currentQuantity = $this->getQuantity();
        $newQuantity = $currentQuantity + $value;

        if (ConfigQuery::checkAvailableStock()) {
            $productSaleElements = $this->getProductSaleElements();
            $product = $productSaleElements->getProduct();

            if ($product->getVirtual() === 0) {
                if ($productSaleElements->getQuantity() < $newQuantity) {
                    $newQuantity = $currentQuantity;
                }
            }
        }

        $this->setQuantity($newQuantity);

        return $this;
    }

    /**
     * @return float
     */
    public function getRealPrice()
    {
        return (float) ((int) $this->getPromo() === 1 ? $this->getPromoPrice() : $this->getPrice());
    }

    /**
     * @param ConnectionInterface|null $con
     * @param null $locale
     * @return Product
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function getProduct(ConnectionInterface $con = null, $locale = null)
    {
        $product = parent::getProduct($con);

        $translation = $product->getTranslation($locale);

        if ($translation->isNew()) {
            if (ConfigQuery::getDefaultLangWhenNoTranslationAvailable() == Lang::REPLACE_BY_DEFAULT_LANGUAGE) {
                $locale = Lang::getDefaultLanguage()->getLocale();
            }
        }

        $product->setLocale($locale);

        return $product;
    }

    /**
     * @param Country $country
     * @param State|null $state
     * @return float
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function getRealTaxedPrice(Country $country, State $state = null)
    {
        return (int) $this->getPromo() === 1 ? $this->getTaxedPromoPrice($country, $state) : $this->getTaxedPrice($country, $state);
    }

    /**
     * @param Country $country
     * @param State|null $state
     * @return float
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function getTaxedPrice(Country $country, State $state = null)
    {
        $taxCalculator = new Calculator();

        return $taxCalculator->load($this->getProduct(), $country, $state)->getTaxedPrice($this->getPrice());
    }

    /**
     * @param Country $country
     * @param State|null $state
     * @return float
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function getTaxedPromoPrice(Country $country, State $state = null)
    {
        $taxCalculator = new Calculator();

        return $taxCalculator->load($this->getProduct(), $country, $state)->getTaxedPrice($this->getPromoPrice());
    }

    /**
     * @since Version 2.3
     * @param Country $country
     * @param State|null $state
     * @return float
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function getTotalRealTaxedPrice(Country $country, State $state = null)
    {
        return (int) $this->getPromo() === 1 ? $this->getTotalTaxedPromoPrice($country, $state) : $this->getTotalTaxedPrice($country, $state);
    }

    /**
     * @since Version 2.3
     * @param Country $country
     * @param State|null $state
     * @return float
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function getTotalTaxedPrice(Country $country, State $state = null)
    {
        return round($this->getTaxedPrice($country, $state) * $this->getQuantity(), 2);
    }

    /**
     * @since Version 2.3
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function getTotalTaxedPromoPrice(Country $country, State $state = null)
    {
        return round($this->getTaxedPromoPrice($country, $state) * $this->getQuantity(), 2);
    }

    /**
     * @since Version 2.4
     * @return float
     */
    public function getTotalPrice()
    {
        return round($this->getPrice() * $this->getQuantity(), 2);
    }

    /**
     * @since Version 2.4
     * @return float
     */
    public function getTotalPromoPrice()
    {
        return round($this->getPromoPrice() * $this->getQuantity(), 2);
    }

    /**
     * @since Version 2.4
     * @return float
     */
    public function getTotalRealPrice()
    {
        return round($this->getRealPrice() * $this->getQuantity(), 2);
    }
}
