<?php

namespace KupShop\WarehouseBundle\Controller;

use KupShop\AdminBundle\Util\LegacyAdminCredentials;
use KupShop\WarehouseBundle\Util\InventoryWorker;
use KupShop\WarehouseBundle\Util\StoreItemWorker;
use KupShop\WarehouseBundle\Util\StoreTransferWorker;
use Query\Operator;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Routing\Annotation\Route;
use Violet\StreamingJsonEncoder\StreamJsonEncoder;

class StoreAppController extends AbstractController
{
    /**
     * @var StoreItemWorker
     */
    private $storeItemWorker;
    /**
     * @var StoreTransferWorker
     */
    private $storeTransferWorker;
    /**
     * @var InventoryWorker
     */
    private $inventoryWorker;
    /**
     * @var LegacyAdminCredentials
     */
    private $legacyAdminCredentials;

    public function __construct(StoreItemWorker $storeItemWorker, StoreTransferWorker $storeTransferWorker, InventoryWorker $inventoryWorker, LegacyAdminCredentials $legacyAdminCredentials)
    {
        $this->storeItemWorker = $storeItemWorker;
        $this->storeTransferWorker = $storeTransferWorker;
        $this->inventoryWorker = $inventoryWorker;
        $this->legacyAdminCredentials = $legacyAdminCredentials;
    }

    /**
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @Route("/_warehouse/store-app/login")
     *
     * @throws \Exception
     */
    public function loginAction(Request $request)
    {
        $jsonResponse = json_decode($request->getContent());

        $user = $this->legacyAdminCredentials->loginByHash($jsonResponse->hash ?? '');

        if (empty($user)) {
            return new JsonResponse($this->storeItemWorker->returnError('Nepodařilo se přihlásit!'));
        }

        // Remember login
        $request->getSession()->set('warehouse_store_logged', $user['id']);

        return new JsonResponse([
            'result' => true,
            'user' => $user,
        ]);
    }

    /**
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @Route("/_warehouse/store-app/loadItem")
     */
    public function loadItemAction(Request $request)
    {
        $jsonResponse = json_decode($request->getContent());

        $batchId = ($jsonResponse->productBatch ?? false) ? $jsonResponse->productBatch->id ?? null : false;

        $product = $this->storeItemWorker->checkProductByEanAndLocation($jsonResponse->ean, $jsonResponse->location ?? null, $jsonResponse->position ?? null, $batchId);

        if (!$product) {
            $responseData = $this->storeItemWorker->returnError('Produkt nenalezen!');
        } else {
            $where = Operator::equalsNullable(['p.id' => $product['id_product'], 'pv.id' => $product['id_variation']]);
            if (!($jsonResponse->showBox ?? false)) {
                $where = Operator::andX(
                    $where,
                    Operator::not(Operator::inIntArray([StoreItemWorker::LOCATION_BOX], 'wpos.id_location'))
                );
            }

            $responseData = [
                'ean' => $jsonResponse->ean,
                'product' => $product,
                'positions' => $this->storeItemWorker->getProductPositions($where),
                'result' => !empty($product),
            ];
        }

        return new JsonResponse($responseData);
    }

    /**
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @Route("/_warehouse/store-app/loadItemWithVariations")
     */
    public function loadItemWithVariationsAction(Request $request)
    {
        $json = $this->loadItemAction($request)->getContent();
        $data = json_decode($json, true);
        $pvEANs = sqlQueryBuilder()
                ->select('pv.ean')
                ->from('products_variations', 'pv')
                ->where(Operator::equals(['pv.id_product' => $data['product']['id_product']]))
                ->execute();
        $variations = [];
        foreach ($pvEANs as $ean) {
            $variation = $this->storeItemWorker->checkProductByEanAndLocation($ean['ean']);
            if ($variation) {
                $variations[] = $variation;
            }
        }
        $data['variations'] = $variations;

        return new JsonResponse($data);
    }

    /**
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @throws \Throwable
     *
     * @Route("/_warehouse/store-app/storeInItem")
     */
    public function storeInItemAction(Request $request)
    {
        $jsonResponse = json_decode($request->getContent());

        $batchId = ($jsonResponse->productBatch ?? false) ? $jsonResponse->productBatch->id ?? null : false;

        $result = $this->storeItemWorker->storeItemFromTable($jsonResponse->ean, $jsonResponse->quantity, $jsonResponse->positionFrom, $jsonResponse->positionTo, $jsonResponse->overSupply, $batchId);

        $responseData = [
            'message' => $result,
            'result' => $result === true,
        ];

        return new JsonResponse($responseData);
    }

    /**
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @Route("/_warehouse/store-app/getItemsOnTable")
     *
     * @throws \Exception
     */
    public function getItemsOnTableAction(Request $request)
    {
        $jsonResponse = json_decode($request->getContent());
        if (!empty($jsonResponse->table)) {
            $positions = [$this->storeItemWorker->getPositionIdByCode($jsonResponse->table)];
        } else {
            $positions = $this->storeItemWorker->findTablePositions();
        }

        $result = $this->storeItemWorker->getProductsOnPositions($positions);

        $responseData = [
            'products' => $result,
            'result' => true,
        ];

        return new JsonResponse($responseData);
    }

    /**
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @Route("/_warehouse/store-app/getItemsOnPosition")
     *
     * @throws \Exception
     */
    public function getItemsOnPositionAction(Request $request)
    {
        $jsonResponse = json_decode($request->getContent());

        $result = $this->storeItemWorker->getProductsOnPositions([$this->storeItemWorker->getPositionIdByCode($jsonResponse->position_code)]);

        $responseData = [
            'position' => $jsonResponse->position_code,
            'products' => $result,
            'result' => true,
        ];

        return new JsonResponse($responseData);
    }

    /**
     * @Route("/_warehouse/store-app/getAllTables")
     *
     * @return JsonResponse
     */
    public function getAllTablesAction(Request $request)
    {
        $result = $this->storeItemWorker->getAllTables();

        $responseData = [
            'tables' => $result,
            'result' => true,
        ];

        return new JsonResponse($responseData);
    }

    /**
     * @Route("/_warehouse/store-app/startOrderCheckout")
     *
     * @return JsonResponse
     *
     * @throws \Exception
     */
    public function startOrderCheckoutAction(Request $request)
    {
        $parameters = json_decode($request->getContent());

        $responseData = $this->getWorker($parameters->order_no)->startCheckout($parameters->order_no, $parameters->box);

        return new JsonResponse($responseData);
    }

    /**
     * @Route("/_warehouse/store-app/startOrderMassCheckout")
     *
     * @return JsonResponse
     *
     * @throws \Exception
     */
    public function startOrderMassCheckoutAction(Request $request)
    {
        $parameters = json_decode($request->getContent());

        $responseData = $this->storeItemWorker->startMassCheckout($parameters);

        return new JsonResponse($responseData);
    }

    /**
     * @return JsonResponse
     *
     * @throws \Exception
     * @throws \Throwable
     *
     * @Route("/_warehouse/store-app/saveOrderCheckout")
     */
    public function saveOrderCheckoutAction(Request $request)
    {
        $parameters = json_decode($request->getContent());

        $responseData = $this->getWorker($parameters->id_warehouse)->commit($parameters->id_warehouse, $parameters->state);

        return new JsonResponse($responseData);
    }

    /**
     * @return JsonResponse
     *
     * @throws \Exception
     * @throws \Throwable
     *
     * @Route("/_warehouse/store-app/saveOrderMassCheckout")
     */
    public function saveOrderMassCheckoutAction(Request $request)
    {
        $parameters = json_decode($request->getContent());

        $responseData = $this->storeItemWorker->commitMass($parameters->state);
        $this->storeItemWorker->finishCompletedOrders($parameters->orders);

        return new JsonResponse($responseData);
    }

    /**
     * @return JsonResponse
     *
     * @throws \Exception
     * @throws \Throwable
     *
     * @Route("/_warehouse/store-app/asyncSaveOrderCheckoutAction")
     */
    public function asyncSaveOrderCheckoutAction(Request $request)
    {
        $parameters = json_decode($request->getContent());

        $responseData = $this->getWorker($parameters->id_warehouse)->commit($parameters->id_warehouse, $parameters->state);

        list($responseData['store']['checkouts'], $responseData['store']['items']) = $this->getWorker($parameters->id_warehouse)->loadOrderStoreItems($parameters->id_warehouse);

        return new JsonResponse($responseData);
    }

    /**
     * @return JsonResponse
     *
     * @throws \Exception
     * @throws \Throwable
     *
     * @Route("/_warehouse/store-app/asyncSaveOrderMassCheckoutAction")
     */
    public function asyncSaveOrderMassCheckoutAction(Request $request)
    {
        $parameters = json_decode($request->getContent());

        $responseData = $this->storeItemWorker->commitMass($parameters->state);

        list($responseData['store']['checkouts'], $responseData['store']['items']) = $this->storeItemWorker->loadOrderStoreMassItems($parameters->orders);

        return new JsonResponse($responseData);
    }

    /**
     * @Route("/_warehouse/store-app/submitOrderCheckout")
     *
     * @return JsonResponse
     *
     * @throws \Exception
     * @throws \Throwable
     */
    public function submitOrderCheckoutAction(Request $request)
    {
        $parameters = json_decode($request->getContent());

        $responseData = $this->getWorker($parameters->id_warehouse)->finish($parameters->id_warehouse, $parameters->state);

        return new JsonResponse($responseData);
    }

    /**
     * @Route("/_warehouse/store-app/submitOrderMassCheckout")
     *
     * @return JsonResponse
     *
     * @throws \Exception
     * @throws \Throwable
     */
    public function submitOrderMassCheckoutAction(Request $request)
    {
        $parameters = json_decode($request->getContent());

        $responseData = $this->storeItemWorker->finishMass($parameters->orders, $parameters->state);

        return new JsonResponse($responseData);
    }

    /**
     * @Route("/_warehouse/store-app/moveProduct")
     *
     * @return JsonResponse
     *
     * @throws \Exception
     * @throws \Throwable
     */
    public function moveProductAction(Request $request)
    {
        $parameters = json_decode($request->getContent());

        $batchId = ($parameters->productBatch ?? false) ? $parameters->productBatch->id ?? null : false;

        $responseData = $this->storeItemWorker->moveProduct($parameters->ean, $parameters->pieces, $parameters->positionFrom, $parameters->positionTo, $parameters->overSupply ?? false, $batchId);

        return new JsonResponse($responseData);
    }

    /**
     * @Route("/_warehouse/store-app/stats/")
     *
     * @return JsonResponse
     */
    public function getUserScore(Request $request)
    {
        $parameters = json_decode($request->getContent());

        if (empty($parameters->user->id)) {
            $responseData = [
                'result' => false,
                'message' => 'Nepřihlášený uživatel.',
            ];
        } else {
            $responseData = $this->storeItemWorker->getStats($parameters->user);
        }

        return new JsonResponse($responseData);
    }

    /**
     * @return StoreItemWorker|StoreTransferWorker
     */
    private function getWorker($order_no)
    {
        return strpos($order_no, 'TR') === false ? $this->storeItemWorker : $this->storeTransferWorker;
    }

    /**
     * @return JsonResponse
     *
     * @throws \Exception
     * @throws \Throwable
     *
     * @Route("/_warehouse/store-app/submitInventory")
     */
    public function submitInventoryAction(Request $request)
    {
        $parameters = json_decode($request->getContent());

        $positionId = $this->storeItemWorker->getPositionIdByCode($parameters->position_code);

        $result = $this->inventoryWorker->submitInventory($positionId, $parameters->products, $parameters->position_code);

        return new JsonResponse($result);
    }

    /**
     * @return StreamedResponse
     *
     * @throws \Exception
     * @throws \Throwable
     *
     * @Route("/_warehouse/store-app/loadAllProducts")
     */
    public function loadInventoryProducts(Request $request)
    {
        $result = [
            'products' => $this->inventoryWorker->loadProductsCache(),
            'productsEANs' => $this->inventoryWorker->loadProductsEans(),
            'productsSuppliersEANs' => $this->inventoryWorker->loadProductsSuppliersEans(),
            'result' => true,
        ];

        return new StreamedResponse(function () use ($result) {
            $encoder = new StreamJsonEncoder($result);
            $encoder->encode();
        }, 200, ['Content-Type' => 'application/json']);
    }

    /**
     * @Route("/_warehouse/store-app/getProductBatches")
     */
    public function getProductBatches(Request $request)
    {
        $parameters = json_decode($request->getContent());

        if ($parameters->ean ?? false) {
            $result = [
                'batches' => $this->inventoryWorker->productBatches($parameters->ean),
                'result' => true,
            ];

            return new JsonResponse($result);
        }

        return new JsonResponse(['result' => false]);
    }
}
