<?php


namespace Shop\Application\Shopping\MergeCustomerOrders;


use Shop\Application\Shopping\Exceptions\CustomerOrderNotFoundException;
use Shop\Infrastructure\Repositories\CustomerOrder\CustomerOrderCriteria;
use Shop\Infrastructure\Repositories\CustomerOrder\CustomerOrderRepository;
use Shop\Infrastructure\Repositories\OrderItem\OrderItemCriteria;
use Shop\Infrastructure\Repositories\OrderItem\OrderItemRepository;

class MergeCustomerOrdersHandler
{
    protected $customerOrderRepository;
    protected $itemRepository;

    /**
     * MergeCustomerOrdersHandler constructor.
     * @param CustomerOrderRepository $customerOrderRepository
     * @param OrderItemRepository $itemRepository
     */
    public function __construct(CustomerOrderRepository $customerOrderRepository,
                                OrderItemRepository $itemRepository)
    {
        $this->customerOrderRepository = $customerOrderRepository;
        $this->itemRepository = $itemRepository;
    }

    /**
     * @param MergeCustomerOrdersCommand $command
     */
    public function handle(MergeCustomerOrdersCommand $command): void
    {
        $ids = $command->getIds();

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

        /**
         * @var CustomerOrderEntityInterface $order
         * @var CustomerOrderEntityInterface $newOrder
         */

        $orders = $this->customerOrderRepository->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->customerOrderRepository->findById($newOrderId)) {
            throw new CustomerOrderNotFoundException(sprintf(
                'new order id %s not found', $newOrderId
            ));
        }

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

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

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

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

}