<?php

namespace Shop\Infrastructure\Models\Product;

use Propel\Runtime\Collection\ObjectCollection;
use Shop\Domain\Customer\Contracts\CustomerEntityInterface;
use Shop\Domain\Product\Contracts\ProductEntityInterface;
use Shop\Presentation\Helpers\Text;
use Shop\Infrastructure\Models\Position\Position;
use Shop\Infrastructure\Models\Product\Base\Product as BaseProduct;
use Propel\Runtime\ActiveQuery\Criteria;
use Shop\Infrastructure\Models\Position\PositionQuery;
use Propel\Runtime\Connection\ConnectionInterface;
use Shop\Infrastructure\Models\Product\Map\ProductTableMap;

/**
 * Skeleton subclass for representing a row from the 'shop_products' table.
 *
 *
 *
 * You should add additional methods to this class to meet the
 * application requirements.  This class will only be generated as
 * long as it does not already exist in the output directory.
 *
 */
class Product extends BaseProduct implements ProductEntityInterface
{

    const FAKE_PERCENT = 20;

    protected $salePriceDiff;

    private $export = false;
    private $favorite = false;

    /**
     * @return int
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function getPositionsCount(): int
    {
        return parent::getPositions()->count();
    }

    /**
     * @return string
     */
    public function getName(): string
    {
        return $this->title;
    }


    public function getSalePriceDiff()
    {
        return $this->salePriceDiff;
    }

    public function getOldPrice()
    {
        return ceil((self::FAKE_PERCENT / 100 + 1) * $this->getPrice());
    }

    /**
     * @param CustomerEntityInterface $customer
     * @return array
     * @throws \Propel\Runtime\Exception\PropelException
     * @todo пофиксить выход из цикла
     */
    public function getPrices(CustomerEntityInterface $customer): array
    {

        $positions = $this->getPositions(new Criteria());

        $prices = [
            $this->getPrice()
        ];

        foreach ($positions as $position) {
            /**
             * @var Position $position
             */
            if (!in_array($position->getPricelistSheetId(), $customer->getAccessPrices(), true)
                || (int)$position->getRemain() == 0
            ) {
                continue;
            }
            $prices[] = $position->getPriceFinal();
        }
        asort($prices);

        return $prices;
    }

    /**
     * @param type $complex_rate
     * @return array
     * @todo пофиксить выход из цикла
     */
    public function getPricesOld(CustomerEntityInterface $customer): array
    {

        $positions = $this->getPositions();

        $price = (int)$this->getOldPrice();

        foreach ($positions as $position) {
            if (!in_array($position->getPricelistSheetId(), $customer->getAccessPrices(), true)
                || (int)$position->getRemain() == 0
            ) {
                continue;
            }
            $price = $position->getPriceOldFinal() > $price ? $position->getPriceOldFinal() : $price;
        }

        $max = $this->getPricePositionsDiff($customer);

        return $max > 0 ? [$price] : [];
    }

    /**
     * Получение позиций которые относяткя к прайсу
     * @param CustomerEntityInterface $customer
     * @return ObjectCollection
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function getCurrentPositions(CustomerEntityInterface $customer): ObjectCollection
    {

        $pos = $this->getPositions();

        foreach ($pos as $position) {

            if (
                (int)$position->getRemain() === 0 ||
                !in_array($position->getPricelistSheetId(), $customer->getAccessPrices(), true)
            ) {
                $pos->removeObject($position);
            }

        }

        return $pos;
    }

    /**
     *
     * @param type $type
     * @return type
     */
    public function getSalePositions($type, CustomerEntityInterface $customer)
    {
        $criteria = new Criteria;
        $criteria->add("remain", 0, Criteria::GREATER_THAN);
        // $criteria->add("price", 0, Criteria::GREATER_THAN);
        $criteria->add("sale_id", $type, (is_array($type) ? Criteria::IN : Criteria::EQUAL));
        $criteria->add("pricelist_sheet_id", implode(",", $customer->getAccessPrices()));
        $criteria->setLimit(1);

        $pos = $this->getPositions($criteria);

        return $pos;
    }


    /**
     *
     * @param type $type
     * @return type
     */
    public function getSalePositionsDiff($type, CustomerEntityInterface $customer): int
    {

        if ($this->salePriceDiff !== null) {
            return $this->salePriceDiff;
        }

        $pos = $this->getSalePositions($type, $customer);
        $m = [];
        foreach ($pos as $p) {
            $m [] = round($p->getPriceOld() - $p->getPrice());
        }

        $this->salePriceDiff = count($m) ? max($m) : 0;

        return $this->salePriceDiff;
    }

    /**
     * @param CustomerEntityInterface $customer
     * @return int
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function getPricePositionsDiff(CustomerEntityInterface $customer): int
    {

        $pos = $this->getPositions();
        $m = [];
        foreach ($pos as $p) {
            if (!in_array($p->getPricelistSheetId(), $customer->getAccessPrices())
                || (int)$p->getRemain() == 0
            ) {
                continue;
            }
            $m [] = round($p->getPriceOldFinal($customer) - $p->getPriceFinal($customer));
        }

        return count($m) ? max($m) : 0;
    }

    /**
     * является ли товар новинкой
     * @param int $days
     * @return bool
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function isNewDate(int $days): bool
    {
        $date = date_create();
        date_sub($date, date_interval_create_from_date_string(sprintf('%s days', $days)));

        return $this->getDateCreate()->getTimestamp() >= $date->getTimestamp();
    }

    /**
     * @return array
     */
    public function getGroupListArray(): array
    {
        $list = [];
        foreach ($this->getProductGroups() as $group) {
            $list [] = $group->getname();
        }
        return $list;
    }

    /**
     * запрос модифицированные добавляет комплексную наценку
     * @param Criteria|null $criteria
     * @param ConnectionInterface|null $con
     * @return array|ObjectCollection|Position[]
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function getPositions(Criteria $criteria = null, ConnectionInterface $con = null)
    {
        $partial = $this->collPositionsPartial && !$this->isNew();
        if (null === $this->collPositions || null !== $criteria || $partial) {
            if ($this->isNew() && null === $this->collPositions) {
                // return empty collection
                $this->initPositions();
            } else {

                $collPositions = PositionQuery::create(null, $criteria)
                    ->withComplexRate()
                    ->filterByProduct($this)
                    ->find($con);

                if (null !== $criteria) {
                    if (false !== $this->collPositionsPartial && count($collPositions)) {
                        $this->initPositions(false);

                        foreach ($collPositions as $obj) {
                            if (false == $this->collPositions->contains($obj)) {
                                $this->collPositions->append($obj);
                            }
                        }

                        $this->collPositionsPartial = true;
                    }

                    return $collPositions;
                }

                if ($partial && $this->collPositions) {
                    foreach ($this->collPositions as $obj) {
                        if ($obj->isNew()) {
                            $collPositions[] = $obj;
                        }
                    }
                }

                $this->collPositions = $collPositions;
                $this->collPositionsPartial = false;
            }
        }

        return $this->collPositions;
    }

    /**
     * @return string
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function getTitleWithArticleBrand(): string
    {
        return sprintf('%s [%s %s]', $this->getTitle(), $this->getArticle(), $this->getBrand()->getName());
    }

    /**
     * Set the value of [price] column.
     *
     * @param string $v new value
     * @return $this|\Shop\Infrastructure\Models\Product\Product The current object (for fluent API support)
     */
    public function setPrice($v)
    {
        if ($v !== null) {
            $v = (string)$v;
        }

        if ($v === '') {
            $v = null;
        }

        if ($this->price !== $v) {
            $this->price = $v;
            $this->modifiedColumns[ProductTableMap::COL_PRICE] = true;
        }

        return $this;
    }

    /**
     * установка спуер цены
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function setHitSale(): void
    {
        (new \Shop\Infrastructure\Models\ProductHitSale\ProductHitSale)
            ->setProductId($this->getId())
            ->setImageHash(md5($this->getImg()))
            ->save();
    }

    /**
     * Удаления супер цены
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function removeHitSale(): void
    {
        $this->getProductHitSale()->delete();
    }

    /**
     * Установим супер цену
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function setSuperPrice(): void
    {
        (new \Shop\Infrastructure\Models\ProductSuperPrice\ProductSuperPrice)
            ->setProductId($this->getId())
            ->setImageHash(md5($this->getImg()))
            ->save();
    }

    /**
     * Удаление супер цены
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function removeSuperPrice(): void
    {
        $this->getProductSuperPrice()->delete();
    }

    public function isSuperPrice(): bool
    {
        return $this->getProductSuperPrice() !== null;
    }

    public function isHitSale(): bool
    {
        return $this->getProductHitSale() !== null;
    }


    public function isFavorite(): bool
    {
        return $this->favorite;
    }

    public function setFavorite(): void
    {
        $this->favorite = true;
    }

    public function removeFavorite(): void
    {
        $this->favorite = false;
    }


    public function setExport(): void
    {
        $this->export = true;
    }

    public function isExport(): bool
    {
        return $this->export;
    }

    public function removeExport(): void
    {
        $this->export = false;
    }

    /**
     * @return string
     */
    public function getProductNameForSeo(): string
    {
        return Text::caseText($this->getTitle());
    }
}