<?php

namespace Lc\CaracoleBundle\Repository\Product;

use Lc\CaracoleBundle\Model\Product\ProductCategoryInterface;
use Lc\CaracoleBundle\Model\Product\ProductFamilyInterface;
use Lc\CaracoleBundle\Model\Reduction\ReductionCatalogInterface;
use Lc\CaracoleBundle\Repository\SectionStoreTrait;
use Lc\CaracoleBundle\Solver\Price\PriceSolver;
use Lc\SovBundle\Model\User\UserInterface;
use Lc\SovBundle\Repository\AbstractStore;
use Lc\SovBundle\Repository\RepositoryQueryInterface;

class ProductFamilyStore extends AbstractStore
{
    use SectionStoreTrait;

    protected ProductFamilyRepositoryQuery $query;
    protected PriceSolver $priceSolver;

    public function __construct(ProductFamilyRepositoryQuery $query, PriceSolver $priceSolver)
    {
        $this->query = $query;
        $this->priceSolver = $priceSolver;
    }

    public function orderByDefault(RepositoryQueryInterface $query): RepositoryQueryInterface
    {
        $query->orderBy('position');
        return $query;
    }

    public function filtersDefault(RepositoryQueryInterface $query): RepositoryQueryInterface

    {
        $query->filterBySection($this->section);
        return $query;
    }

    public function relationsDefault($query): RepositoryQueryInterface
    {
        $query->joinProductCategories();
        $query->joinProducts();
        return $query;
    }

    // getProductFamiliesByCategory
    public function getByCategory(ProductCategoryInterface $productCategory, $query = null)
    {
        $query = $this->createDefaultQuery($query);

        $query
                ->filterIsOnline()
                ->filterByProductCategory($productCategory);

        return $query->find();
    }

    // getProductFamiliesNovelties
    public function getNovelty($user = null, $organizeByParentCategory = true, $query = null)
    {
        $query = $this->createDefaultQuery($query);

        $query
                ->filterByPropertyNoveltyExpirationDate()
                ->filterIsOnline();

        $results = $query->find();

        return $this->getWithReductions($results, $user, false, $organizeByParentCategory);
    }

    // getProductFamiliesOrganics
    public function getOrganic($user = null, $organizeByParentCategory = true, $query = null)
    {
        $query = $this->createDefaultQuery($query);

        $query
                ->filterIsOrganicLabel()
                ->filterIsOnline();

        $results = $query->find();

        return $this->getWithReductions($results, $user, false, $organizeByParentCategory);
    }

    // getProductFamiliesOnDiscount
    public function getDiscount($user = null, $organizeByParentCategory = true, $query = null)
    {
        return $this->getWithReductions($this->getOnline($query), $user, false, $organizeByParentCategory);
    }

    // getProductFamiliesFavorites
    public function getFavorite($user = null, $organizeByParentCategory = true, $query = null)
    {
        if ($user) {
            return $this->getWithReductions($user->getFavoriteProductFamilies(), $user, false, $organizeByParentCategory);
        }

        return [];
    }

    // findByTerms
    public function getByTerms($terms, $maxResults = false, $query = null)
    {
        $query = $this->createDefaultQuery($query);

        $query->filterIsOnline();
        $query->groupBy('id');

        if($maxResults) {
            $query->limit($maxResults);
        }

        return $query->find();
    }

    public function getBestReductionCatalog(
            ProductFamilyInterface $productFamily,
            ReductionCatalogInterface $reductionCatalog1,
            ReductionCatalogInterface $reductionCatalog2
    ) {
        $price1 = $this->priceSolver->applyReductionCatalog(
                $productFamily,
                $this->priceSolver->getPrice($productFamily),
                $this->priceSolver->getPriceWithTax($productFamily),
                1,
                $reductionCatalog1
        );

        $price2 = $this->priceSolver->applyReductionCatalog(
                $productFamily,
                $this->priceSolver->getPrice($productFamily),
                $this->priceSolver->getPriceWithTax($productFamily),
                1,
                $reductionCatalog2
        );

        if ($price1 > $price2) {
            return $reductionCatalog2;
        } else {
            return $reductionCatalog1;
        }
    }

    // setReductionForProductFamilies
    public function getWithReductions(
            $productFamilies,
            UserInterface $user = null,
            $organizeByCategory = false,
            $organizeByParentCategory = false,
            $onlyOnDiscount = false
    ) {
        $conditions = [
                'ids' => [],
                'categories' => [],
        ];
        foreach ($productFamilies as $productFamily) {
            $conditions['ids'][] = $productFamily->getId();
            $conditions['categories'] = array_merge(
                    $conditions['categories'],
                    $productFamily->getProductCategories()->toArray()
            );
        }

        if ($productFamilies) {
            $reductionCatalogs = $this->reductionCatalogStore->getByProductFamiliesConditions(
                    $conditions,
                    $user
            );
        }

        $productFamiliesToReturn = array();
        foreach ($productFamilies as $productFamily) {
            foreach ($reductionCatalogs as $reductionCatalog) {
                $conditionProductFamilies = $conditionProductFamily = $conditionProductCategory = false;

                if ($reductionCatalog->getProductFamilies()->contains(
                                $productFamily
                        ) || $reductionCatalog->getProductFamilies()->isEmpty()) {
                    $conditionProductFamilies = true;
                }

                if ($reductionCatalog->getProductFamily() == $productFamily || $reductionCatalog->getProductFamily(
                        ) === null) {
                    $conditionProductFamily = true;
                }

                foreach ($productFamily->getProductCategories() as $productCategory) {
                    if ($reductionCatalog->getProductCategories()->contains(
                                    $productCategory
                            ) || $reductionCatalog->getProductCategories()->isEmpty()) {
                        $conditionProductCategory = true;
                    }
                }

                if ($conditionProductFamilies && $conditionProductFamily && $conditionProductCategory) {
                    if ($productFamily->getReductionCatalog()) {
                        $productFamily->setReductionCatalog(
                                $this->getBestReductionCatalog(
                                        $productFamily,
                                        $reductionCatalog,
                                        $productFamily->getReductionCatalog()
                                )
                        );
                    } else {
                        $productFamily->setReductionCatalog($reductionCatalog);
                    }
                }
            }

            if (($onlyOnDiscount && $productFamily->getReductionCatalog()) || !$onlyOnDiscount) {
                if ($organizeByParentCategory) {
                    $productCategories = $productFamily->getProductCategories();
                    if ($productCategories && count($productCategories) > 0) {
                        $parentCategory = $productCategories[0]->getParentCategory();
                        if ($this->productCategorySolver->isDisplay($parentCategory, $user)) {
                            if (!isset($productFamiliesToReturn[$parentCategory->getId()])) {
                                $productFamiliesToReturn[$parentCategory->getId()] = [
                                        'category' => $parentCategory,
                                        'products' => []
                                ];
                            }
                            $productFamiliesToReturn[$parentCategory->getId()]['products'][] = $productFamily;
                        }
                    }
                } elseif ($organizeByCategory) {
                    foreach ($productFamily->getProductCategories() as $productCategory) {
                        if ($this->isDisplay($productFamily)) {
                            $productFamiliesToReturn[$productCategory->getId()][] = $productFamily;
                        }
                    }
                } else {
                    if ($this->isDisplay($productFamily)) {
                        $productFamiliesToReturn[] = $productFamily;
                    }
                }
            }
        }

        if ($organizeByParentCategory) {
            uasort($productFamiliesToReturn, array($this, 'compMethodSortProductFamiliesByParentCategory'));
        }

        return $productFamiliesToReturn;
    }

}