<?

namespace Shop\Services;

use Shop\Contracts\CustomerComplexInterface;
use Shop\DTO\BasketItem;
use Shop\DTO\CustomerComplex;
use Shop\Repositories\Position;

/**
 * Use Case Basket
 *
 * @author Admin
 */
class Basket
{

    protected $basket;
    protected $main;
    protected $positionRepo;

    static $bastetDto;

    function __construct(\Core\Basket\Basket $basket, \Shop\Config\Main $main, Position $positionRepo)
    {
        $this->basket = $basket;
        $this->main = $main;
        $this->positionRepo = $positionRepo;
    }

    /**
     * Добавляем товар в корзину
     * @param \Shop\DTO\BasketItemRequest $item
     * @return integer
     */
    public function add(\Shop\DTO\BasketItemRequest $item): string
    {

        $key = $this->basket->addItem($item->getArtice(), $item->getPrice(), $item->getAmount(),
                                      [
            "name"  => $item->getName(),
            "desc"  => $item->getDesc(),
            "ref"   => $item->getRef(),
            "brand" => $item->getBrand(),
            "shop"  => $item->getShop(),
            "menagerComment"  => $item->getMenagerComment()
        ]);

        return $key;
    }

    /**
     * Проверка наличия товара
     * @param \Shop\DTO\BasketItemRequest $item
     * @return false|\Shop\DTO\BasketItem
     */
    public function itemExist(\Shop\DTO\BasketItemRequest $item): int
    {
        $key = $this->basket->createKey($item->getDesc(), $item->getPrice());
        if ( ! $item = $this->basket->getItemByKey($key)) {
            return 0;
        }
        return $this->buildItem($key, $item)->getAmount();
    }

    /**
     * получение кол-ва товара в корзине по ref позиции
     * @param type $ref
     */
    public function itemExistByRef($ref): int
    {

        foreach ($this->basket->getItems() as $item) {

            if ($item["data"]["ref"] == $ref) {

                return $item["amount"];
            }
        }

        return 0;
    }

    /**
     * Удаление по ключу
     * @param type $hash
     * @return boolean
     */
    public function delete($hash)
    {
        if ($this->basket->deleteByKey($hash) === true) {
            return true;
        }

        return false;
    }

    /**
     * Получение корзины
     * @return \Shop\DTO\Basket
     */
    public function getBasket(CustomerComplexInterface $customerComplex = null): \Shop\DTO\Basket
    {

        $count = $this->basket->getCount();
        $summ = $this->basket->getSumm();
        $items = [];
        foreach ($this->basket->getItems() as $k => $item) {
            $items[] = $this->buildItem($k, $item);
        }

        $basket = new \Shop\DTO\Basket($summ, $count, $items);

        if(!$customerComplex){
            return $basket;
        }

        if(is_a(self::$bastetDto, \Shop\DTO\Basket::class)){
            return self::$bastetDto;
        }

        $summ = 0;
        $newItems = [];
        $count = 0;

        foreach ($basket->getItems() as $item){

            if(!$position = $this->positionRepo->findByRefId($item->getRef())){
                $item->setState(BasketItem::STATE_OUT_STOCK);
                continue;
            }

            /**
             * только так получаем позиции с корректным ценообразованием
             */
            $allPositions = $position->getProduct()->getCurrentPositions($customerComplex);

            $currentPrice = null;

            foreach ($allPositions as $findPosition){

                if($findPosition->getRefId() !== $item->getRef()){
                    continue;
                }


                if($findPosition->getRealSizes() !== $item->getDesc()){
                    continue;
                }

                $currentPrice = $findPosition->getPriceFinal();
                break;
            }

            if(!$currentPrice){
                $item->setState(BasketItem::STATE_OUT_STOCK);
                continue;
            }

            if($item->getPrice() > $currentPrice){
                $item->setState(BasketItem::STATE_DOWN_PRICE);
                $item->setPrice($currentPrice);
            }
            elseif($item->getPrice() < $currentPrice){
                $item->setState(BasketItem::STATE_UP_PRICE);
                $item->setPrice($currentPrice);
            }

            $price = (int)$item->getAmount() * (float)$item->getPrice();
            $summ += $price;


            if ($item->getAmount() > 0) {
                $count +=(int) $item->getAmount();
            }

            $newItems[]= $item;

        }

        //dump($summ, $count, $newItems);

        $basket = new \Shop\DTO\Basket($summ, $count, $newItems);

        self::$bastetDto = $basket;

        return $basket;
    }
    
    /**
     * 
     * @return int
     */
    public function getScoresInBasket(): int
    {
        $scores = 0;

        foreach ($this->getBasket()->getItems() as $item) {
            if (strpos($item->getMenagerComment(),"score")!==false) {
                continue;
            }
            $scores = $scores + $item->getPrice() * $item->getAmount();
        }
        return abs($scores);
    }

    /**
     * 
     * @param type $k
     * @param array $item
     * @return type
     */
    private function buildItem($k, array $item): \Shop\DTO\BasketItem
    {

        return (new \Shop\DTO\BasketItem())
                        ->setId($k)
                        ->setPrice($item["price"])
                        ->setAmount($item["amount"])
                        ->setName($item["data"]["name"])
                        ->setArticle($item["article"])
                        ->setRef($item["data"]["ref"])
                        ->setBrand($item["data"]["brand"])
                        ->setDesc($item["data"]["desc"])
                        ->setShop($item["data"]["shop"])
                        ->setMenagerComment(isset($item["data"]["menagerComment"])?$item["data"]["menagerComment"]:null)
        ;
    }

    public function clearBasket()
    {
        $this->basket->clear();
        return true;
    }

    /**
     * 
     * @return int
     */
    public function calculateScore():int
    {
        $summ = $this->getBasket()->getSumm();
        
        if($this->main->getOrderScoreSumm() > 0){
            $amount = floor($summ / $this->main->getOrderScoreSumm());
            return (int)$amount * $this->main->getOrderScoreVolume();
        }
        
        return 0;
    }

}