<?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\QueryBuilder\PlainSqlQueryComponent;
use Shopware\Plugins\ViisonPickwareMobile\Components\QueryComponentArrayCoding\FieldDescriptorQueryComponentArrayCoder;
use Shopware\Plugins\ViisonPickwareMobile\Components\QueryComponentArrayCoding\QueryComponentArrayDecodingPreprocessor;

class OrderItemCountConditionQueryComponentArrayDecodingPreprocessor implements QueryComponentArrayDecodingPreprocessor
{
    /**
     * @var string
     */
    const ORDER_ITEM_COUNTS_TABLE_REFERENCE = 'order_item_counts';

    /**
     * @var string
     */
    const FIELD_NAME_DISTINCT_PRODUCT_COUNT = '__distinct_product_count';

    /**
     * @var string
     */
    const FIELD_NAME_TOTAL_ITEM_QUANTITY = '__total_item_quantity';

    /**
     * @var array
     */
    const ORDER_ITEM_COUNT_QUERIES = [
        self::FIELD_NAME_DISTINCT_PRODUCT_COUNT => 'COUNT(DISTINCT `s_order_details`.`articleordernumber`)',
        self::FIELD_NAME_TOTAL_ITEM_QUANTITY => 'SUM(
            GREATEST(0, (
                `s_order_details`.`quantity`
                 + IFNULL(`derived__cancelled_returned_quantities`.`cancelledReturned`, 0)
                 - `s_order_details`.`shipped` 
                 - IFNULL(`s_order_details_attributes`.`pickware_picked_quantity`, 0)
            ))
        )',
    ];

    /**
     * @var array
     */
    protected $processedConditions = [];

    /**
     * {@inheritdoc}
     *
     * Matches any field descriptor components that select one of the supported order item counts from the `s_order`
     * table and changes the component data to select the value from the computed order item conditions table instead.
     */
    public function process(array $arrayData)
    {
        $componentDataMatches = (
            isset($arrayData['type'])
            && $arrayData['type'] === FieldDescriptorQueryComponentArrayCoder::CODABLE_TYPE
            && $arrayData['tableName'] === 's_order'
            // Note: Prior to PHP 7 `isset()` cannot be used with a const array access expression, which is why we need
            // to use `!== null` instead!
            && self::ORDER_ITEM_COUNT_QUERIES[$arrayData['fieldName']] !== null
        );
        if ($componentDataMatches) {
            $this->processedConditions[$arrayData['fieldName']] = true;
            $arrayData['tableName'] = OrderFilterConditionQueryComponent::ORDER_ITEM_CONDITIONS_TABLE_ALIAS;
            $arrayData['fieldName'] = self::ORDER_ITEM_COUNTS_TABLE_REFERENCE . $arrayData['fieldName'];
        }

        return $arrayData;
    }

    /**
     * @return array An associtive array using the resolved order item cound conditions as keys and the respective SQL
     *         queries for calculating those conditions as values.
     */
    public function createConditionQueryComponents()
    {
        return array_combine(
            // Prefix the keys with `order_item_counts` to make them *unique*
            array_map(
                function ($conditionKey) {
                    return self::ORDER_ITEM_COUNTS_TABLE_REFERENCE . $conditionKey;
                },
                array_keys($this->processedConditions)
            ),
            // Use plain SQL components to calculate the item counts
            array_map(
                function ($conditionKey) {
                    return new PlainSqlQueryComponent(
                        self::ORDER_ITEM_COUNT_QUERIES[$conditionKey],
                        [
                            's_order_details',
                            's_order_details_attributes',
                            'derived__cancelled_returned_quantities',
                        ]
                    );
                },
                array_keys($this->processedConditions)
            )
        );
    }
}
