<?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\Classes;

use DateTime;
use Doctrine\DBAL\Connection as DbalConnection;
use Shopware\CustomModels\ViisonPickwareMobile\PickProfile\PickProfile;

class PickingOrderSorter
{
    /**
     * @var PickProfile
     */
    private $pickProfile;

    /**
     * @var DbalConnection
     */
    private $dbalConnection;

    /**
     * @param PickProfile $pickProfile
     * @param DbalConnection $dbalConnection
     */
    public function __construct(PickProfile $pickProfile, DbalConnection $dbalConnection)
    {
        $this->pickProfile = $pickProfile;
        $this->dbalConnection = $dbalConnection;
    }

    /**
     * Sorts the given orders in their priority for picking.
     *
     * @param int[] $orderIds
     * @return int[]
     */
    public function sort(array $orderIds)
    {
        $orderValues = $this->dbalConnection->fetchAll(
            'SELECT `id`, `ordertime`, `dispatchID`, `paymentID`
            FROM `s_order`
            WHERE `id` IN (:orderIds)',
            ['orderIds' => $orderIds],
            ['orderIds' => DbalConnection::PARAM_INT_ARRAY]
        );

        // Prepare the orders for sorting
        $sortableOrderValues = [];
        foreach ($orderValues as $order) {
            // Convert order values to format needed for sorting
            $sortableOrderValues[] = [
                'id' => $order['id'],
                'orderTime' => new DateTime($order['ordertime']),
                'prioritizedDispatchMethod' => $this->pickProfile->prioritizesDispatchMethodWithId(
                    $order['dispatchID']
                ),
                'prioritizedPaymentMethod' => $this->pickProfile->prioritizesPaymentMethodWithId(
                    $order['paymentID']
                ),
            ];
        }

        return array_column($this->sortOrderArrays($sortableOrderValues), 'id');
    }

    /**
     * Sorts the given order data by the following criteria:
     *  1. The dispatch method is (not) prioritized, descending (true first)
     *  2. The payment method is (not) prioritized, descending (true first)
     *  3. The timestamp of the order, ascending
     *  4. The ID of the order, ascending
     *
     * @param array $orders
     * @param array
     */
    private function sortOrderArrays(array $orders)
    {
        usort($orders, function ($lhs, $rhs) {
            // Compare dispatch privileges
            if ($lhs['prioritizedDispatchMethod'] && !$rhs['prioritizedDispatchMethod']) {
                return -1;
            } elseif (!$lhs['prioritizedDispatchMethod'] && $rhs['prioritizedDispatchMethod']) {
                return 1;
            }

            // Neither or both have prioritized dispatch, hence compare payment privileges
            if ($lhs['prioritizedPaymentMethod'] && !$rhs['prioritizedPaymentMethod']) {
                return -1;
            } elseif (!$lhs['prioritizedPaymentMethod'] && $rhs['prioritizedPaymentMethod']) {
                return 1;
            }

            // Neither or both are prioritized in any way, hence sort by their creation time
            if ($lhs['orderTime'] < $rhs['orderTime']) {
                return -1;
            } elseif ($lhs['orderTime'] > $rhs['orderTime']) {
                return 1;
            }

            // All criteria match, hence just sort by ID
            if ($lhs['id'] < $rhs['id']) {
                return -1;
            } elseif ($lhs['id'] > $rhs['id']) {
                return 1;
            }

            return 0;
        });

        return $orders;
    }
}
