<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonPickwareMobile\Components\PickingOrderFilter\OrderFilterConditionQueryComponent;

use Shopware\Plugins\ViisonPickwareMobile\Components\QueryComponentArrayCoding\QueryComponentArrayCodingService;
use Shopware\Plugins\ViisonPickwareMobile\Components\QueryComponentArrayCoding\QueryComponentArrayDecodingPreprocessor;

class OrderFilterConditionQueryComponentFactoryService
{
    /**
     * @var QueryComponentArrayCodingService
     */
    protected $queryComponentArrayCodingService;

    /**
     * @var QueryComponentArrayDecodingPreprocessor[]
     */
    protected $defaultDecodingPreprocessors;

    /**
     * @param QueryComponentArrayCodingService $queryComponentArrayCodingService
     */
    public function __construct(QueryComponentArrayCodingService $queryComponentArrayCodingService)
    {
        $this->queryComponentArrayCodingService = $queryComponentArrayCodingService;
        $this->defaultDecodingPreprocessors = [
            new AttributeFieldQueryComponentArrayDecodingPreprocessor(),
            new DateOperatorQueryComponentArrayDecodingPreprocessor($this->queryComponentArrayCodingService),
            new IsEmptyQueryComponentArrayDecodingProprocessor($this->queryComponentArrayCodingService),
            new LikeOperatorQueryComponentArrayDecodingPreprocessor(),
        ];
    }

    /**
     * Decodes the passed `$encodedQueryComponent` and returns a new {@link OrderFilterConditionQueryComponent} instance
     * containing the decoding result.
     *
     * @param array $encodedQueryComponent
     * @return OrderFilterConditionQueryComponent
     */
    public function createWithArrayEncodedQueryComponent(array $encodedQueryComponent)
    {
        $categoryConditionPreprocessor = new OrderItemCategoryConditionQueryComponentArrayDecodingPreprocessor(
            $this->queryComponentArrayCodingService
        );
        $groupingConstraintPreprocessor = new GroupingConstraintQueryComponentArrayDecodingPreprocessor(
            $this->queryComponentArrayCodingService
        );
        $countConditionPreprocessor = new OrderItemCountConditionQueryComponentArrayDecodingPreprocessor();
        $rootQueryComponent = $this->queryComponentArrayCodingService->decode(
            $encodedQueryComponent,
            array_merge(
                $this->defaultDecodingPreprocessors,
                [
                    // The category condition preprocessor must be added BEFORE the grouping constraint preprocessor
                    // since the latter needs to process the modified category conditions
                    $categoryConditionPreprocessor,
                    $groupingConstraintPreprocessor,
                    $countConditionPreprocessor,
                ]
            )
        );

        // Collect extra joins needed for the order item conditions
        $extraOrderItemConditionJoinQueryComponents = [];
        $categoryConditionJoinQueryComponent = $categoryConditionPreprocessor->createCategorySubqueryJoinQueryComponent();
        if ($categoryConditionJoinQueryComponent) {
            $extraOrderItemConditionJoinQueryComponents[] = $categoryConditionJoinQueryComponent;
        }

        return new OrderFilterConditionQueryComponent(
            $rootQueryComponent,
            array_merge(
                $groupingConstraintPreprocessor->createConditionQueryComponents($this->defaultDecodingPreprocessors),
                $countConditionPreprocessor->createConditionQueryComponents()
            ),
            $extraOrderItemConditionJoinQueryComponents
        );
    }
}
