<?php

namespace KupShop\WarehouseBundle\EventListener;

use KupShop\ProductsBatchesBundle\Util\ProductsBatchesUtil;
use KupShop\StoresBundle\Event\StoreEvent;
use KupShop\StoresBundle\Utils\StoresInStore;
use KupShop\WarehouseBundle\Entity\StoreItem;
use KupShop\WarehouseBundle\Util\StoreItemWorker;
use Query\Operator;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class StoreTransferListener implements EventSubscriberInterface
{
    /**
     * @var StoresInStore
     */
    protected $storeInStore;

    /**
     * @var ProductsBatchesUtil
     */
    protected $productsBatchesUtil;

    /**
     * @var StoreItemWorker
     */
    protected $storeItemWorker;

    public function __construct(StoreItemWorker $storeItemWorker)
    {
        $this->storeItemWorker = $storeItemWorker;
    }

    /**
     * @required
     */
    public function setStoreInStore(?StoresInStore $storeInStore = null): void
    {
        $this->storeInStore = $storeInStore;
    }

    /**
     * @required
     */
    public function setProductsBatchesUtil(?ProductsBatchesUtil $productsBatchesUtil): void
    {
        $this->productsBatchesUtil = $productsBatchesUtil;
    }

    public static function getSubscribedEvents()
    {
        return [
            StoreEvent::MOVE_PRODUCTS => [
                ['moveProducts', 200],
            ],
        ];
    }

    /**
     * @var StoreEvent
     *
     * @throws \Throwable
     */
    public function moveProducts(StoreEvent $event)
    {
        $object = $event->getStoreTransfer();

        /*
            Když se přenáší něco na komisní sklad, je třeba aby se to kompletně smazalo z warehouse pozic,
            ale ve stores se to přeneslo.
            Když se to pak přenáší zpátky z komise na hlavní sklad, mělo se by to vytvořit na stole.
        */

        $store_from = $this->storeInStore->getStores()[$object['id_store_from']];
        $store_to = $this->storeInStore->getStores()[$object['id_store_to']];

        if (($store_from['type'] == StoresInStore::TYPE_EXTERNAL_STORE)
            && ($store_to['type'] == StoresInStore::TYPE_EXTERNAL_STORE)) {
            // from EXTERNAL to EXTERNAL
            return;
        }

        $destinationTable = $store_to['id_base_position'];

        if ($store_from['type'] == StoresInStore::TYPE_EXTERNAL_STORE) {
            // Když se to pak přenáší zpátky z komise na hlavní sklad, mělo se by to vytvořit na stole.

            if (findModule(\Modules::PRODUCTS_BATCHES)) {
                $this->moveBatchesFromExternal($object);
            }

            $productsInBox = sqlQueryBuilder()->select('*, IF(id_variation=0, NULL, id_variation) AS id_variation')
                ->from('stores_transfers_items')
                ->where(Operator::equals(['id_stores_transfer' => $object['id']]))
                ->execute()
                ->fetchAll();

            sqlGetConnection()->transactional(
                function () use ($productsInBox, $destinationTable, $object) {
                    foreach ($productsInBox as $product) {
                        $product['id_product_batch'] = $object['itemsBatches'][$product['id']]['id'] ?? null;
                        $this->storeItemWorker->createStoreItem(new StoreItem($product), $product['quantity'], $destinationTable, null, true);
                    }
                }
            );

            return;
        }

        if ($store_to['type'] == StoresInStore::TYPE_EXTERNAL_STORE && findModule(\Modules::PRODUCTS_BATCHES)) {
            $this->moveBatchesToExternal($object);
        }

        sqlQueryBuilder()
            ->update('stores_transfers')
            ->set('id_position', 'NULL')
            ->where(Operator::equals(['id' => $object['id']]))
            ->execute();

        if ($store_to['type'] != StoresInStore::TYPE_EXTERNAL_STORE) {
            // 2 neexterni sklady - moveBetweenPositions
            $productsInBox = sqlQueryBuilder()->select('*')
                ->from('warehouse_products')
                ->where(Operator::equals(['id_position' => $object['id_position']]))
                ->execute()
                ->fetchAll();
            foreach ($productsInBox as $product) {
                if (findModule(\Modules::PRODUCTS_BATCHES)) {
                    $where = [
                        'id_stores_transfer' => $object['id'],
                        'id_product' => $product['id_product'],
                        'id_variation' => $product['id_variation'],
                    ];

                    $this->productsBatchesUtil->addBatchesToCustomData('stores_transfers_items',
                        $where,
                        [$product['id_product_batch'] => $product['pieces']]);
                }
                $this->storeItemWorker->moveBetweenPositions(new StoreItem($product), $product['pieces'], $object['id_position'], $destinationTable);
            }
        }

        $this->storeItemWorker->cleanCompletedBox($object['id_position']);
    }

    protected function moveBatchesToExternal($storeTransfer)
    {
        $items = sqlQueryBuilder()->select('*')
            ->from('stores_transfers', 'st')
            ->innerJoin('st', 'warehouse_products', 'wp', 'wp.id_position = st.id_position')
            ->where(Operator::equals(['st.id' => $storeTransfer['id']]))
            ->execute();

        foreach ($items as $item) {
            $this->productsBatchesUtil->addBatchesToCustomData('stores_transfers_items', [
                'id_stores_transfer' => $storeTransfer['id'],
                'id_product' => $item['id_product'],
                'id_variation' => $item['id_variation'],
            ], [$item['id_product_batch'] => $item['pieces']]);

            $this->productsBatchesUtil->addBatchesToCustomData('stores_items', [
                'id_store' => $storeTransfer['id_store_to'],
                'id_product' => $item['id_product'],
                'id_variation' => $item['id_variation'],
            ], [$item['id_product_batch'] => $item['pieces']]);
        }
    }

    protected function moveBatchesFromExternal($storeTransfer)
    {
        foreach ($storeTransfer['itemsBatches'] ?? [] as $item) {
            $this->productsBatchesUtil->addBatchesToCustomData('stores_transfers_items', [
                'id_stores_transfer' => $storeTransfer['id'],
                'id_product' => $item['id_product'],
                'id_variation' => $item['id_variation'],
            ], [$item['id'] => $item['checked']]);

            $this->productsBatchesUtil->addBatchesToCustomData('stores_items', [
                'id_store' => $storeTransfer['id_store_from'],
                'id_product' => $item['id_product'],
                'id_variation' => $item['id_variation'],
            ], [$item['id'] => -$item['checked']]);
        }
    }
}
