<?php

namespace Shopware\Plugins\ViisonSetArticles\Components;

use Shopware\Bundle\SearchBundle\Criteria;
use Shopware\Bundle\SearchBundleDBAL\ConditionHandler\ImmediateDeliveryConditionHandler;
use Shopware\Bundle\SearchBundleDBAL\QueryBuilder;
use Shopware\Bundle\SearchBundleDBAL\QueryBuilderFactoryInterface;
use Shopware\Bundle\StoreFrontBundle\Struct\ShopContextInterface;
use Shopware\Plugins\ViisonCommon\Classes\Util\Util as CommonUtil;

class QueryBuilderFactoryDecorator implements QueryBuilderFactoryInterface
{
    /**
     * @var QueryBuilderFactoryInterface
     */
    private $decoratedInstance;

    /**
     * @param QueryBuilderFactoryInterface $decoratedInstance
     */
    public function __construct(QueryBuilderFactoryInterface $decoratedInstance)
    {
        $this->decoratedInstance = $decoratedInstance;
    }

    /**
     * @inheritdoc
     */
    public function createQueryWithSorting(Criteria $criteria, ShopContextInterface $context)
    {
        return $this->decoratedInstance->createQueryWithSorting($criteria, $context);
    }

    /**
     * @inheritdoc
     *
     * Replace the condition that checks if the product is available for immediate delivery which is not set article
     * compatible with a condition that calculates the stock of a set article and uses this value to check its
     * availability.
     */
    public function createProductQuery(Criteria $criteria, ShopContextInterface $context)
    {
        /** @var QueryBuilder $query */
        $query = $this->decoratedInstance->createProductQuery($criteria, $context);

        // Since the condition to check instock is within a join prior to SW 5.3 this fix only works for SW >= 5.3
        if (CommonUtil::assertMinimumShopwareVersion('5.3.0')
            && $query->hasState(ImmediateDeliveryConditionHandler::STATE_INCLUDES_IMMEDIATE_DELIVERY_VARIANTS)
        ) {
            $sql = $query->getQueryPart('where')->__toString();

            $sql = str_replace(
                'allVariants.instock >= allVariants.minpurchase',
                'IF(productAttribute.viison_setarticle_active,

                (
                    SELECT MIN(articleDetails.instock DIV setArticle.quantity) as instock
                    FROM s_articles_details as articleDetails
                    LEFT JOIN s_articles_viison_setarticles as setArticle ON articleDetails.id = setArticle.articledetailid
                    WHERE setArticle.setid = allVariants.id
                ),

                allVariants.instock

                ) >= allVariants.minpurchase',
                $sql
            );

            // Shopware uses a different query when a filter that expands variants is used
            // This option to add variant filters only exists since SW 5.4
            if (CommonUtil::assertMinimumShopwareVersion('5.4.0')
            ) {
                $sql = str_replace(
                    'variant.instock >= variant.minpurchase',
                    'IF(productAttribute.viison_setarticle_active,

                    (
                        SELECT MIN(articleDetails.instock DIV setArticle.quantity) as instock
                        FROM s_articles_details as articleDetails
                        LEFT JOIN s_articles_viison_setarticles as setArticle ON articleDetails.id = setArticle.articledetailid
                        WHERE setArticle.setid = variant.id
                    ),

                    variant.instock

                    ) >= variant.minpurchase',
                    $sql
                );
            }

            $query->where($sql);
        }

        return $query;
    }

    /**
     * @inheritdoc
     */
    public function createQuery(Criteria $criteria, ShopContextInterface $context)
    {
        return $this->decoratedInstance->createQuery($criteria, $context);
    }

    /**
     * @inheritdoc
     */
    public function createQueryBuilder()
    {
        return $this->decoratedInstance->createQueryBuilder();
    }
}
