<?php

namespace KupShop\StoresBundle\Utils;

use KupShop\CheckAppBundle\Util\WorkerUtil;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\LoggingContext;
use KupShop\ProductsBatchesBundle\Util\ProductsBatchesUtil;
use KupShop\WarehouseBundle\Util\Logger;
use Query\Operator;
use Symfony\Contracts\Service\Attribute\Required;

class StoreTransferCheckoutWorker
{
    /**
     * @var StoresInStore
     */
    private $storesInStore;

    /**
     * @var StoresTransfers
     */
    private $storesTransfers;

    #[Required]
    public LoggingContext $loggingContext;

    /**
     * @required
     */
    public function setStoresInStore(StoresInStore $storesInStore): void
    {
        $this->storesInStore = $storesInStore;
    }

    /**
     * @required
     */
    public function setStoresTransfers(StoresTransfers $storesTransfers): void
    {
        $this->storesTransfers = $storesTransfers;
    }

    public function getStoreTransferCheckData($id_store_transfer)
    {
        $data = [];
        foreach ($this->storesTransfers->getTransferItems($id_store_transfer) as $item) {
            $product = new \Product();
            $product->createFromDB($item['id_product']);

            $additionalData = ServiceContainer::getService(WorkerUtil::class)->getProductAdditionalData($item['id_product'], $item['id_variation']);

            $productData = sqlQueryBuilder()
                ->select('COALESCE(pv.ean, p.ean) ean, COALESCE(pv.code, p.code) code, CONCAT_WS(" ", p.title, pv.title) title')
                ->from('products', 'p')
                ->joinVariationsOnProducts()
                ->where(Operator::equalsNullable([
                    'p.id' => $item['id_product'],
                    'pv.id' => $item['id_variation'],
                ]))
                ->addSelect(\Query\Product::withProductPhotoId(true))
                ->execute()->fetch();

            $data[] = [
                'id' => $item['id'],
                'title' => $productData['title'],
                'quantity' => (int) $item['quantity'],
                'code' => ($productData['code'] ?? ''),
                'ean' => formatEAN($productData['ean']),
                'batch_number_require' => $additionalData['batch_number_require'] ?? '',
                'batches_numbers' => $additionalData['batches_numbers'] ?? [],
                'id_product' => $item['id_product'],
                'id_variation' => $item['id_variation'],
                'note' => $product->note_ ?? '',
                'serial_number_require' => $additionalData['serial_number_require'] ?? '',
                'image' => getImage($productData['id_photo'], null, null, 3)['src'] ?? '',
                'positions' => $additionalData['positions'] ?? '',
                'supplier_eans' => explode(';', $additionalData['supplier_eans'] ?? ''),
                'supplier_codes' => explode(';', $additionalData['supplier_codes'] ?? ''),
                'figure' => $product->visible,
            ];
        }

        usort($data, function ($a, $b) {
            return empty($b['ean']) <=> empty($a['ean']);
        });

        $index = 0;
        foreach ($data as &$item) {
            $item['index'] = $index++;
        }

        return $data;
    }

    public function checkoutStoreTransfer($id_transfer, $items, $action = null): array
    {
        if ($error = ServiceContainer::getService(WorkerUtil::class)->checkIfAnyItemChecked($items)) {
            return [
                'result' => false,
                'keepState' => true,
                'message' => $error,
            ];
        }

        $currentStatus = sqlQueryBuilder()->select('state')->from('stores_transfers')
            ->where(Operator::equals(['id' => $id_transfer]))
            ->execute()->fetchOne();

        // Odeslat jde jen otevřenou převodku
        if ($action == 'send' && $currentStatus != 'O') {
            return [
                'result' => false,
                'keepState' => true,
                'message' => 'Převodka není ve stavu otevřená.',
            ];
        }

        // Přijmout jde jen odeslanou převodku
        if ($action == 'accept' && $currentStatus != 'S') {
            return [
                'result' => false,
                'keepState' => true,
                'message' => 'Převodka není ve stavu odeslaná.',
            ];
        }

        $transferItems = $this->storesTransfers->getTransferItems($id_transfer);

        if (findModule(\Modules::STORES, \Modules::SUB_ON_THE_FLY_STORE) && $action != 'send') {
            // Zkontroluji, že mám napípaný všechny produkty, protože tím že mám mezisklad,
            // tak nemůžu změnit převodku při příjmu. Zboží by mi totiž zůstalo viset na meziskladu
            $uncheckedItems = array_filter($transferItems, function ($transferItem) use ($items) {
                $item = current(array_filter($items, function ($item) use ($transferItem) {
                    return $item->id == $transferItem['id'];
                }));

                if (!$item) {
                    return true;
                }

                return $item->checked != $transferItem['quantity'];
            });
            if ($uncheckedItems) {
                return [
                    'result' => false,
                    'keepState' => true,
                    'message' => 'Nebyly zkontrolovány všechny položky. Není možné příjmout převodku z meziskladu.',
                ];
            }
        }

        if (findModule(\Modules::WAREHOUSE)) {
            ServiceContainer::getService(Logger::class)->setIdTransfer($id_transfer);
        }

        return sqlGetConnection()->transactional(function () use ($transferItems, $id_transfer, $items, $action) {
            // Goes through all transfer items and changes their quantity to the amount checked in the check app
            foreach ($transferItems as $transferItem) {
                $transferItemChecked = current(array_filter($items, function ($item) use ($transferItem) {
                    return $item->id == $transferItem['id'];
                }))->checked ?? 0;

                if ($transferItemChecked != $transferItem['quantity']) {
                    sqlQueryBuilder()->update('stores_transfers_items', 'sti')
                        ->where(Operator::equals(['sti.id' => $transferItem['id']]))
                        ->directValues(['quantity' => $transferItemChecked])
                        ->execute();
                }
            }

            $object = sqlQueryBuilder()->select('st.*')->from('stores_transfers', 'st')
                ->where(Operator::equals(['id' => $id_transfer]))->execute()->fetch();

            // Adds to the transfer object info about its batches numbers, so an event listener can after moving the store items assign correct batch numbers in the warehouse
            if (findModule(\Modules::PRODUCTS_BATCHES)) {
                $productsBatchesUtil = ServiceContainer::getService(ProductsBatchesUtil::class);
                $object['itemsBatches'] = [];
                foreach ($items as $item) {
                    if (($item->batch_number_require ?? 'N') == 'Y' && $item->quantity > 0) {
                        $batchNumber = null;
                        if ($item->batchNumber->id ?? false) {
                            $batchNumber = $productsBatchesUtil->getBatchNumber($item->batchNumber->id);
                        }
                        if (!$batchNumber) {
                            $batchNumber = $productsBatchesUtil->createBatchNumber([
                                'id_product' => $item->id_product,
                                'id_variation' => $item->id_variation ?? null,
                                'code' => $item->batchNumber->code,
                                'date_expiry' => $item->batchNumber->date_expiry,
                            ]);
                        }
                        $batchNumber['checked'] = $item->checked ?? 0;
                        $object['itemsBatches'][$item->id] = $batchNumber;
                    }
                }
            }

            try {
                $this->loggingContext->activateStoreTransfer(
                    $id_transfer, function () use ($object, $action) {
                        $this->storesInStore->transferMove($object, $action);
                    }
                );
            } catch (\Exception $e) {
                return $this->moveBetweenStoresError($e);
            } catch (\Throwable $e) {
                return $this->moveBetweenStoresError($e);
            }

            return [
                'result' => true,
                'message' => 'Převodka přijata',
            ];
        });
    }

    protected function moveBetweenStoresError($e)
    {
        $sentryLogger = ServiceContainer::getService(\KupShop\KupShopBundle\Util\Logging\SentryLogger::class);
        $sentryLogger->captureException($e);

        return [
            'result' => false,
            'keepState' => true,
            'message' => 'Chyba! '.$e->getMessage(),
        ];
    }
}
