<?php


namespace Shop\Application\Shopping\MergeProviderOrders;

use Shop\Application\Shopping\Exceptions\ProviderOrderNotFoundException;
use Shop\Domain\ProviderOrder\Contracts\ProviderOrderEntityInterface;
use Shop\Infrastructure\Repositories\CustomerOrder\CustomerOrderCriteria;
use Shop\Infrastructure\Repositories\ProviderOrder\ProviderOrderRepository;
use Shop\Infrastructure\Repositories\ProviderOrderItem\ProviderOrderItemCriteria;
use Shop\Infrastructure\Repositories\ProviderOrderItem\ProviderOrderItemRepository;

/**
 * Class MergeProviderOrdersHandler
 * @package Shop\Application\Shopping\MergeProviderOrders
 */
class MergeProviderOrdersHandler
{

    protected $providerOrderRepository;
    protected $providerOrderItemRepository;

    /**
     * MergeProviderOrdersHandler constructor.
     * @param ProviderOrderRepository $providerOrderRepository
     * @param ProviderOrderItemRepository $providerOrderItemRepository
     */
    public function __construct(ProviderOrderRepository $providerOrderRepository,
                                ProviderOrderItemRepository $providerOrderItemRepository)
    {
        $this->providerOrderRepository = $providerOrderRepository;
        $this->providerOrderItemRepository = $providerOrderItemRepository;
    }

    /**
     * @param MergeProviderOrdersCommand $command
     */
    public function handle(MergeProviderOrdersCommand $command): void
    {

        $ids = $command->getIds();

        if (count($ids) < 2) {
            throw new MergeCountOrdersException('counts order for merge < 2');
        }

        /**
         * @var ProviderOrderEntityInterface $order
         * @var ProviderOrderEntityInterface $newOrder
         * @var ProviderOrderEntityInterface|Order $oldOrder
         */

        $orders = $this->providerOrderRepository->findByCriteria(
            CustomerOrderCriteria::create()->setFilterByIds($ids)
        );

        $clients_arr = $contractor_arr = [];

        foreach ($orders as $order) {
            $clients_arr[$order->getCustomerId()] = $order->getId();
            $contractor_arr[$order->getContractorId()] = $order->getId();
        }

        if (count($clients_arr) > 1) {
            throw new MergeOrdersFoundSomeCustomerException('found some customers, it should be one');
        }

        if (count($contractor_arr) > 1) {
            throw new MergeOrdersFoundSomeContractorsException('found some contractors, it should be one');
        }



        $newOrderId = max($ids);
        $otherOrderIds = $ids;
        unset($otherOrderIds[array_search($newOrderId, $otherOrderIds, false)]);


        if (!$newOrder = $this->providerOrderRepository->findById($newOrderId)) {
            throw new ProviderOrderNotFoundException(sprintf(
                'new order id %s not found', $newOrderId
            ));
        }

        //меняем заказ у позиций---------------------------
        $items = $this->providerOrderItemRepository->findByCriteria(
            ProviderOrderItemCriteria::create()->setFilterByOrderIds($otherOrderIds)
        );


        //меняем заказ у позиций
        foreach ($items as $newOrderItem) {
            $newOrderItem->setOrderId($newOrderId);
            $this->providerOrderItemRepository->save($newOrderItem);
        }

        //удаляем старые заказы-------------------------------
        foreach ($otherOrderIds as $oldOrderId) {
            if (!$oldOrder = $this->providerOrderRepository->findById($oldOrderId)) {
                continue;
            }

            if ($oldOrder->getOrderItems()->count() === 0) {
                $this->providerOrderRepository->delete($oldOrder);
            }

        }

        $command->getResult()->setOrderId($newOrder->getId());
    }

}