<?php

namespace Shop\Repositories;

use Core\Repository\CrudInterface;
use Core\Repository\PropelQueryAbstract;
use DateTime;
use Propel\Runtime\ActiveQuery\Criteria;
use Propel\Runtime\Collection\ObjectCollection;
use Shop\Models\Product\Product as ProductEntity;
use Shop\Models\Product\ProductQuery;
use Shop\Contracts\CatalogFilterInterface;
use Propel\Runtime\Util\PropelModelPager;

/**
 * Description of Bonus
 *
 * @author Dmitriy
 */
class Product extends PropelQueryAbstract implements CrudInterface, \Core\Repository\DropdownInreface
{

    public function buildQuery()
    {
        return ProductQuery::create()
                //->leftJoinProductSuperPrice("superPrice")
                //->leftJoinProductHitSale("hitSale")
                //->addAsColumn('superPrice', 'superPrice.Image')
                //->addAsColumn('hitSale', 'hitSale.Image')
                ;
    }

    public function buildEntity()
    {
        return new ProductEntity;
    }

    /**
     * Получить по бренду
     * @param type $brand_id
     * @return type
     */
    public function findProductByBrandId($brand_id, $page = 1, $maxPerPage = 10)
    {

        return $this->buildQuery()
                        ->filterByBrandId($brand_id)
                        ->paginate($page, $maxPerPage);
    }

    /**
     * @todo добавить фильтр по наличию
     * @param type $id
     * @return type
     */
    public function countByBrandId($id)
    {
        return $this->buildQuery()
                        ->filterByBrandId($id)
                        ->count();
    }

    /**
     * 
     * @param type $id
     * @return type
     */
    public function countByCategoryId(CatalogFilterInterface $catalogFilter)
    {

        return $this->buildQuery()
                        ->filterByCategoryId($catalogFilter->getCategoryId())
    
                            ->usePositionQuery()
                            ->_if($catalogFilter->getSale() > 0)
                                    ->filterBySaleId($catalogFilter->getSale())
                            ->_endif()
                            ->filterByRemain(0, Criteria::GREATER_THAN)
                            ->filterByPricelistSheetId($catalogFilter->getPriceListScheetIds())
                            
                            ->endUse()
                                        
                        ->_if($catalogFilter->getImgExit()===true)
                            ->filterByImg('', Criteria::GREATER_THAN)
                        ->_endif()
                        ->groupById()
                        ->count();
    }

    /**
     * 
     * @param type $shopId
     * @param type $categ_id
     * @param type $page
     * @param type $maxPerPage
     * @return type
     */
    public function findProductByCategoryId(CatalogFilterInterface $catalogFilter, $page = 1, $maxPerPage = 10,
                                            $sort = null)
    {
        
        $sizeTypes = (array) $catalogFilter->getSizeType();
        $sizeValues = [];
        foreach ($sizeTypes as $type) {
            $sizeValues = array_merge($catalogFilter->getSizeValues()[$type], $sizeValues);
        }
         
        $q = $this->buildMainCatalogQuery($catalogFilter)

                //positions
                ->usePositionQuery()
                ->_if($sort == "first-cheap")
                ->orderByPrice(Criteria::ASC)
                ->_endif()
                ->_if($sort == "first-roads")
                ->orderByPrice(Criteria::DESC)
                ->_endif()
                ->_if($catalogFilter && $catalogFilter->getSizeValues() && $catalogFilter->getSizeType())
                ->useShopPositionSizeQuery()
                ->filterBySizeTypeId($sizeTypes)
                ->filterByValue($sizeValues)
                ->endUse()
                ->_endif()
                ->_if($catalogFilter->getPriceMin() > 0)
                ->filterByPrice($catalogFilter->getPriceMin(), Criteria::GREATER_EQUAL)
                ->_endif()
                ->_if($catalogFilter->getPriceMax() > 0)
                ->filterByPrice($catalogFilter->getPriceMax(), Criteria::LESS_EQUAL)
                ->_endif()              
                ->endUse()
                //positions - end                
                ->_if($catalogFilter && count($catalogFilter->getBrands()) > 0)
                ->filterByBrandId($catalogFilter->getBrands())
                ->_endif()
                ->_if($catalogFilter && count($catalogFilter->getGroups()) > 0)
                ->useShopProductGroupsRelQuery()
                ->filterByGroupId($catalogFilter->getGroups())
                ->endUse()
                ->_endif()
                ->_if($sort == "news")
                ->orderBydateCreate(Criteria::DESC)
                ->_endif()
                ->_if($sort == "name-a-z")
                ->orderByTitle(Criteria::ASC)
                ->_endif()
                ->_if($sort == "name-z-a")
                ->orderByTitle(Criteria::DESC)
                ->_endif()
                ->groupById()

        ;
        //echo \Diamond\Helpers\Text::highlight_code($q->toString());
           //exit;
        return $q->paginate($page, $maxPerPage);
    }

    /**
     * 
     * @param type $shopId
     * @param type $categ_id
     */
    public function findBrandsByCategoryId(CatalogFilterInterface $catalogFilter)
    {
        $query1 = $this->buildMainCatalogQuery($catalogFilter)
                ->useBrandQuery()
                ->withColumn("shop_brands.name", "brand_name")
                ->endUse()
                ->select(["brand_name"])
                ->addSelfSelectColumns(true)
                ->groupById()
        ;

        $query2 = ProductQuery::create()
                ->addAsColumn('brand_name', 'prod.brand_name')
                ->addSelectQuery($query1, 'prod')
                ->addAsColumn('count', 'COUNT(prod.id)')
                ->groupByBrandId()
                ->orderBy("prod.brand_name")
        ;

        return $query2->find();
    }

    /**
     * 
     * @param CatalogFilterInterface $catalogFilter
     * @return type
     */
    private function buildMainCatalogQuery(CatalogFilterInterface $catalogFilter)
    {

        return $this->buildQuery()
                        ->_if($catalogFilter->getNew() > 0)
                        //->filterBydateCreate("DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)",Criteria::GREATER_EQUAL)
                        ->filterBy("dateCreate", sprintf( "cdate >= DATE_SUB(CURRENT_DATE, INTERVAL %s DAY)",$catalogFilter->getNew() ), Criteria::CUSTOM)
                        ->_endif()                 
                        ->usePositionQuery()
                            ->filterByRemain(0, Criteria::GREATER_THAN)
                            ->_if(count($catalogFilter->getPriceListScheetIds())>0)
                            ->filterByPricelistSheetId($catalogFilter->getPriceListScheetIds())
                            ->_endif() 
                            ->_if($catalogFilter->getSale()>0)
                                ->filterBySaleId($catalogFilter->getSale())
                            ->_endif() 
                        ->endUse()
                        ->_if($catalogFilter->getImgExit())
                            ->filterByImg('', Criteria::GREATER_THAN)
                        ->_endIf()
                        ->_if($catalogFilter->getCategoryId())
                        ->filterByCategoryId($catalogFilter->getCategoryId())
                        ->_endIf()
                        //parent cat
                        ->_if($catalogFilter->getParentCategoryId())
                        ->useCategoryQuery()
                        ->filterByParentId($catalogFilter->getParentCategoryId())
                        ->endUse()
                        ->_endIf()
                        //parent cats
                        ->_if(count($catalogFilter->getParentCategories()))
                        ->useCategoryQuery()
                        ->filterByParentId($catalogFilter->getParentCategories())
                        ->endUse()
                        ->_endIf()
                        //parent cat-end
                        ->_if($catalogFilter->getProductName())
                        ->filterByTitle($catalogFilter->getProductName()."%",Criteria::LIKE)
                        ->_endIf()
                        ->_if($catalogFilter->getArticle())
                        ->filterByArticle($catalogFilter->getArticle()."%",Criteria::LIKE)
                        ->_endIf()
                       
                        ->useBrandQuery()
                        ->_if(count($catalogFilter->getBrands())>0)
                        ->filterByPrimaryKeys($catalogFilter->getBrands())
                        ->_endIf()
                        ->_if($catalogFilter->getBrandMain()>0)
                        ->filterByPrimaryKey($catalogFilter->getBrandMain())
                        ->_endIf()                
                        ->_if($catalogFilter->getBrandName())
                        ->filterByName($catalogFilter->getBrandName()."%",Criteria::LIKE)
                        ->_endIf()
                        ->endUse()
                        
                        ->_if(count($catalogFilter->getProducts()))
                        ->filterByPrimaryKeys($catalogFilter->getProducts())
                        ->_endIf()
                        
        ;
    }

    /**
     * Получение товаров с группировкой по сезонам
     * @param CatalogFilterInterface $catalogFilter
     * @return type
     */
    public function findSeazonsByCategoryId(CatalogFilterInterface $catalogFilter,array $groups)
    {
        return $this->buildMainCatalogQuery($catalogFilter)
                        ->useShopProductGroupsRelQuery()
                        ->_if(count($groups))
                        ->filterByGroupId($groups)
                        ->_endif()
                        ->groupByGroupId()
                        ->endUse()
                        ->find()
        ;
    }

    /**
     * 
     * @param CatalogFilterInterface $catalogFilter
     * @return type
     */
    public function findSizesByCategoryIdAndTypeId(CatalogFilterInterface $catalogFilter)
    {
        return $this->buildMainCatalogQuery($catalogFilter)
                        ->usePositionQuery()
                        ->useShopPositionSizeQuery()
                        ->groupByValue()
                        ->useShopPositionSizeTypeQuery()
                        ->filterById($catalogFilter->getSizeType())
                        ->endUse()
                        ->endUse()
                        ->endUse()
                        ->withColumn("shop_position_sizes.value", "color_name")
                        ->select('color_name')
                        ->find()
        ;
    }

    /**
     * 
     * @param CatalogFilterInterface $catalogFilter
     * @return type
     */
    public function findMinMaxPricesByCategoryId(CatalogFilterInterface $catalogFilter)
    {

        $customer = \Core\Application\Loader::getInstance()
                ->load("DI")
                ->get(\Shop\Services\Customer::class)
                ->buildCurrentCustomer()
                ;
        
        $query1 = $this->buildMainCatalogQuery($catalogFilter)
                ->usePositionQuery()
                ->addSelfSelectColumns(true)
                ->addAsColumn('rate', sprintf("( %s /100+1)",\Shop\Models\Position\PositionQuery::getComplexRateQuery($customer)))
                ->endUse()
                ;
 
        $query2 = ProductQuery::create()
                ->select('max_price')
                ->addAsColumn('max_price', 'MAX(prod.price * prod.rate)')
                ->select('min_price')
                ->addAsColumn('min_price', 'MIN(prod.price * prod.rate)')
                ->addSelectQuery($query1, 'prod')
        ;
      
        return $query2->findOne();
    }
    
    
    /**
     * 
     * @param CatalogFilterInterface $catalogFilter
     * @return type
     */
    public function findMinMaxPricesByFilter(CatalogFilterInterface $catalogFilter)
    {

        $customer = \Core\Application\Loader::getInstance()
                ->load("DI")
                ->get(\Shop\Services\Customer::class)
                ->buildCurrentCustomer()
                ;
        
        $query1 = $this->buildMainCatalogQuery($catalogFilter)
               // ->usePositionQuery()
               // ->addSelfSelectColumns(true)
               // ->addAsColumn('rate', sprintf("( %s /100+1)",\Shop\Models\Position\PositionQuery::getComplexRateQuery($customer)))
               // ->endUse()
                ;
 
        $query2 = ProductQuery::create()
                ->select('max_price')
                ->addAsColumn('max_price', 'MAX(prod.price * 1)')
                ->select('min_price')
                ->addAsColumn('min_price', 'MIN(prod.price * 1)')
                ->addSelectQuery($query1, 'prod')
        ;
      
        return $query2->findOne();
    }
        
    

    /**
     * 
     * @return ObjectCollection
     */
    public function findAll(): ObjectCollection
    {
        return $this->buildQuery()
                        ->find();
    }

    /**
     * 
     * @param \Shop\Repositories\Product\ProductCriteria $criteria
     */
    public function findByCriteria(Product\ProductCriteria $criteria):PropelModelPager{
      //  dump($criteria);
        return $this
                ->buildQuery()

                ->_if($criteria->getFilterByActive()!==null)
                    ->filterByActive($criteria->getFilterByActive() === true ?"Y":"N")
                ->_endif()

                ->_if($criteria->getFilterBySpecial()!==null)
                    ->filterBySpecial($criteria->getFilterBySpecial()===true?"Y":"N")
                ->_endif()

                //признак новинки
                ->addAsColumn('is_new',$criteria->getNewGoodDays()>0 ? sprintf( "udate >= DATE_SUB(CURRENT_DATE, INTERVAL %s DAY)",$criteria->getNewGoodDays() ):"0")

                ->_if(count($criteria->getFilterByBrandNames())>0)
                ->useBrandQuery()
                ->filterByName($criteria->getFilterByBrandNames())
                ->endUse()
                ->_endif()
                
                ->usePositionQuery()
                    //remains
                    ->_if($criteria->getFilterByRemains()===true)
                    ->filterByRemain(0, Criteria::GREATER_THAN)
                    ->filterByPrice(0, Criteria::GREATER_THAN)
                    ->_endif()
                    //price cheets
                    ->_if($criteria->getFilterByPriceListScheetIds() !== null)
                    ->filterByPricelistSheetId($criteria->getFilterByPriceListScheetIds())
                    ->_endif()
                ->endUse()   
                //image
                ->_if($criteria->getFilterByImageExist() === true)
                ->filterByImg('', Criteria::GREATER_THAN)
                ->_endif()
                //category
                ->_if($criteria->getFilterByCategoryId())
                ->filterByCategoryId($criteria->getFilterByCategoryId())
                ->_endif()
                //id
                ->_if($criteria->getFilterById())
                ->filterById($criteria->getFilterById())
                ->_endif()
                //ids
                ->_if($criteria->getFilterByIds())
                ->filterById($criteria->getFilterByIds())
                ->_endif()
                
                //filter by date create
                ->_if($criteria->getFilterByDateCreate())
                ->filterBydateCreate([
                    "min" => $criteria->getFilterByDateCreate()
                 ])
                ->_endif()
                ->_if($criteria->getFilterByDateUpdate())
                ->filterBydateUpdate([
                    "min" => $criteria->getFilterByDateUpdate()
                ])
                ->_endif()    
                ->_if($criteria->getFilterByNewGoodDays()===true)
                //->filterBydateCreate(sprintf( "cdate >= DATE_SUB(CURRENT_DATE, INTERVAL %s DAY)",$criteria->getNewGoodDays()))
                ->filterBy("dateUpdate",sprintf( "udate >= DATE_SUB(CURRENT_DATE, INTERVAL %s DAY)",$criteria->getNewGoodDays()), Criteria::CUSTOM)
                //->orderBydateUpdate(Criteria::DESC)
                ->_endif()
                
                //sorted by date create
                ->_if($criteria->getSortedByDateCreate())
                ->orderBydateCreate($criteria->getSortedByDateCreate())
                ->_endif()

                //sorted by date create
                ->_if($criteria->getSortedByDateUpdate())
                ->orderBydateCreate($criteria->getSortedByDateUpdate())
                ->_endif()

                //search by name
                ->_if($criteria->getSearchByName())
                ->filterByTitle( "%" . $criteria->getSearchByName() . "%", Criteria::LIKE)
                    ->_or()
                      ->useBrandQuery()
                        ->filterByName("%" . $criteria->getSearchByName() . "%", Criteria::LIKE)
                      ->endUse()
                ->_endif()    
                        
                //randomsort
                ->_if($criteria->getSortedRandom()===true)
                ->addAscendingOrderByColumn('rand()')
                ->_endif()    
                
                //group                
                ->groupById()
                ->paginate($criteria->getPage(), $criteria->getRowsLimit())
                ;
    }

    

    /**
     * 
     * @param type $page
     * @param type $maxPerPage
     * @return PropelModelPager
     */
    public function findAllByPaginate($page = 1, $maxPerPage = 10): PropelModelPager
    {
        return $this->buildQuery()
                        ->paginate($page, $maxPerPage);
    }

    /**
     * Получение акционных по лимиту
     * @return type
     */
    public function findProductsSales($limit = 10, $categoryId = null): ObjectCollection
    {

        return $this->buildQuery()
                        ->filterBySpecial("Y")
                        ->limit($limit)
                        ->addAscendingOrderByColumn('rand()')
                        ->find();
    }

    /**
     * Получение новинок продуктов для раздела
     * 
     * @param type $categoryId
     * @param type $limit
     * @param type $minDate
     * @return ObjectCollection
     */
    public function findNewsProductsByParentId(CatalogFilterInterface $catalogFilter,$parentId, $limit = 10, $daysLimit = 30): ObjectCollection
    {
        return $this->buildMainCatalogQuery($catalogFilter)
                        ->useCategoryQuery()
                        ->filterByParentId($parentId)
                        ->endUse()
                        ->limit($limit)
                        ->addAscendingOrderByColumn('rand()')
                        ->filterBydateCreate([
                            "min" => (new DateTime(sprintf("today -%s days", $daysLimit)))
                        ])
                        ->groupById()
                        ->find();
    }

    /**
     * Получение скидочных товаров по разделам
     * @param ObjectCollection $category
     * @param type $limit
     * @return ObjectCollection
     */
    public function findSalesProductsByCategories(CatalogFilterInterface $catalogFilter, $limit = 10): ObjectCollection
    {
        return $this->buildQuery()
                        ->join('Position')
                        ->useCategoryQuery()
                        ->filterByParentCategory($catalogFilter->getCategoryId())
                        ->endUse()
                        ->usePositionQuery()
                            ->filterByPricelistSheetId($catalogFilter->getPriceListScheetIds())
                            ->filterByRemain(0, Criteria::GREATER_THAN)
                        ->endUse()
                        ->limit($limit)
                        ->addAscendingOrderByColumn('rand()')
                        ->filterByImg('', Criteria::GREATER_THAN)
                        ->groupById()
                        ->find();
    }

    /**
     * 
     * @param CatalogFilterInterface $catalogFilter
     * @param type $limit
     * @return type
     */
    public function findSimilarByCategoryId(CatalogFilterInterface $catalogFilter, $limit = 10)
    {
        return $this->buildMainCatalogQuery($catalogFilter)
                        ->limit($limit)
                        ->addAscendingOrderByColumn('rand()')
                        ->groupById()
                        ->find();
    }

    /**
     * 
     * @param type $param
     */
    public function findByName($title, CatalogFilterInterface $catalogFilter)
    {
        return $this->buildQuery()
                        ->filterByTitle("{$title}%", Criteria::LIKE)
                        ->usePositionQuery()
                            ->filterByRemain(0, Criteria::GREATER_THAN)
                            ->filterByPricelistSheetId($catalogFilter->getPriceListScheetIds())
                            ->_if($catalogFilter->getSale() > 0)
                                ->filterBySaleId($catalogFilter->getSale())
                            ->_endif() 
                        ->endUse()
                        ->filterByImg('', Criteria::GREATER_THAN)
                        ->orderByTitle()
                        ->groupByTitle()
                        ->limit(10)
                        ->find();
    }

    /**
     * 
     * @param type $title
     * @return type
     */
    public function findByArticle($title,CatalogFilterInterface $catalogFilter)
    {
        return $this->buildQuery()
                        ->usePositionQuery()
                            ->filterByRemain(0, Criteria::GREATER_THAN)
                            ->filterByPricelistSheetId($catalogFilter->getPriceListScheetIds())
                            ->_if($catalogFilter->getSale() === true)
                                ->filterBySaleId(1)
                            ->_endif() 
                        ->endUse()
                        ->filterByImg('', Criteria::GREATER_THAN)                
                        ->filterByArticle("{$title}%", Criteria::LIKE)
                        ->orderByArticle()
                        ->groupByArticle()
                        ->limit(10)
                        ->find();
    }
    
    /**
     * 
     * @param int $id
     * @return \Shop\Models\Product\Product
     */
    public function findById($id){
	   return $this->buildQuery()
                   ->joinWithProductSuperPrice(Criteria::LEFT_JOIN)
                   ->findPk($id);
    }
    
    /**
     * получение списка
     * @return type
     */
    public function getDropdownList(){
	return $this->buildQuery()
		->orderByTitle()
		->find()
		->toKeyValue('id', 'TitleWithArticleBrand');
    }        
}