<?php

namespace KupShop\GraphQLBundle\Tests\ApiPos;

use KupShop\CatalogBundle\ProductList\ProductList;
use KupShop\GraphQLBundle\Tests\GraphQLTestCase;
use KupShop\KupShopBundle\Context\PosContext;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\WarehouseBundle\Util\StoreItemWorker;
use PHPUnit\DbUnit\DataSet\ArrayDataSet;
use PHPUnit\DbUnit\DataSet\DefaultDataSet;
use Query\Operator;
use Query\QueryBuilder;

class PosStoresOrderTest extends GraphQLTestCase
{
    private StoreItemWorker $storeItemWorker;

    protected function setEnvironment(): void
    {
        $this->storeItemWorker = $this->get(StoreItemWorker::class);
    }

    public function testCreateOrderAndCheckStoresAndWarehouse()
    {
        $this->setEnvironment();

        $product = $this->getLoadedProduct();

        // 1. Konrola WEB počet kusů
        $this->assertEquals(167, $product->inStore);

        // 2. Konrola STORES počet kusů
        $this->assertEquals(158, $product->storesInStore[1]['in_store']); // Hlavní sklad
        $this->assertEquals(9, $product->storesInStore[2]['in_store']); // Praha - prodejna

        // 3. Konrola počtu kusů na pozicích WAREHOUSE
        $positions = $this->storeItemWorker->checkProductByEanAndLocation('4046719303137')['positions'];
        $this->assertEquals(158, array_values(array_filter($positions, fn ($x) => $x['id_position'] == '10425'))[0]['pieces']);
        $this->assertEquals(9, array_values(array_filter($positions, fn ($x) => $x['id_position'] == '10818'))[0]['pieces']);
        $this->assertEquals(0, array_values(array_filter($positions, fn ($x) => $x['id_position'] == '6626'))[0]['pieces']);
        $this->assertEquals(0, array_values(array_filter($positions, fn ($x) => $x['id_position'] == '11817'))[0]['pieces']);

        // Objednávka na jeden kus produktu s ID: 23607
        $response = $this->posRequest($this->gqlQueryCreateOrder('81', 'INVOICE', 'null', $purchase = 'true', $save = 'true'), 2);
        $idOrder = $response['data']['posOrderUpdateAndRecalculate']['orderInfo']['idOrder'];
        $this->assertEquals(-1, $response['data']['posOrderUpdateAndRecalculate']['orderInfo']['status']); // Nová objednávka
        $this->assertNull($response['data']['posOrderUpdateAndRecalculate']['orderInfo']['uuidPayment']);

        // Potvrzení platby (provede přesuny, ale není vytvořená platba, proto uuid je UNDEFINED)
        $response = $this->posRequest(PosQueryUtils::confirmPayment($idOrder, 'UNDEFINED', '81', 'INVOICE'), 2);
        $this->assertTrue($response['data']['confirmPayment']['saved']);
        $this->assertFalse($response['data']['confirmPayment']['orderInfo']['isPaid']);

        // Dokončení a přesun mezi do virt boxu a zase ven (kontrola pohybu ve skladu)
        $response = $this->posRequest(PosQueryUtils::finishOrder($idOrder), 2);
        $this->assertEquals($idOrder, $response['data']['posOrderFinish']['idOrder']);
        $this->assertNull($response['data']['posOrderFinish']['exception']);

        $logs = sqlQueryBuilder()
            ->select('*')
            ->from('warehouse_log')
            ->execute()
            ->fetchAllAssociative();

        $this->assertCount(2, $logs); // Objednávka na 1 kus (2 přesuny - ze staré pozice do VIRTBOX, vysypání VIRTBOX)

        // Z staré pozice do VIRTBOX (1 kus)
        $this->assertEquals(10818, $logs[0]['old_id_position']);
        $this->assertEquals(7232, $logs[0]['new_id_position']);
        $this->assertEquals(1, $logs[0]['pieces']);

        // Vysypání VIRTBOX
        $this->assertEquals(7232, $logs[1]['old_id_position']);
        $this->assertEquals(null, $logs[1]['new_id_position']);

        // Konrola počtu kusů ve virtuálním boxu (po updatu proběhne přesun v rámci dokončení a tedy virt box musí být prázdný)
        $box = $this->storeItemWorker->getProductPositions(Operator::equals(['wpos.id' => '7232']));
        $this->assertEquals(0, array_sum(array_column($box, 'pieces')));

        $product = $this->getLoadedProduct();
        // 1. Konrola WEB počet kusů
        $this->assertEquals(166, $product->inStore);

        // 2. Konrola STORES počet kusů
        $this->assertEquals(158, $product->storesInStore[1]['in_store']); // Hlavní sklad
        $this->assertEquals(8, $product->storesInStore[2]['in_store']); // Praha - prodejna

        // 3. Konrola počtu kusů na pozicích WAREHOUSE
        $positions = $this->storeItemWorker->checkProductByEanAndLocation('4046719303137')['positions'];
        $this->assertEquals(158, array_values(array_filter($positions, fn ($x) => $x['id_position'] == '10425'))[0]['pieces']);
        $this->assertEquals(8, array_values(array_filter($positions, fn ($x) => $x['id_position'] == '10818'))[0]['pieces']);
        $this->assertEquals(0, array_values(array_filter($positions, fn ($x) => $x['id_position'] == '6626'))[0]['pieces']);
        $this->assertEquals(0, array_values(array_filter($positions, fn ($x) => $x['id_position'] == '11817'))[0]['pieces']);
    }

    private function getLoadedProduct(): \Product
    {
        $productList = new ProductList();
        $productList->andSpec(function (QueryBuilder $qb) {
            $qb->andWhere(Operator::equals(['p.id' => 23607]));
        });
        $productList->fetchStoresInStore();

        return $productList->getProducts()->get(23607);
    }

    private function gqlQueryCreateOrder($paidPrice, $method = 'CASH', $idOrder = 'null', $purchase = 'false', $save = 'false')
    {
        $items = '[{
            idProduct: 23607
            uuid: "889474d8-b701-40e6-a34c-4b6ad97eea89"
            title: "3M 8822 Respirátor s výdechovým ventilem FFP2"
            pieces: 1
            vat: "0"
            priceWithoutVat: "81.0000"
          }
        ]';

        return PosQueryUtils::posUpdateAndRecalculate($idOrder, $items, 'null', $method, $paidPrice, $save, $purchase);
    }

    private function posRequest($request, $idPos)
    {
        $posContext = Contexts::get(PosContext::class);

        return json_decode(
            $this->doAdminRequest(
                $request,
                [],
                true,
                '/admin/pos/graphql/',
                [
                    'HTTP_Wpj-Id-Pos-Entity' => $idPos,
                    'HTTP_Wpj-Version-Pos' => $posContext->getApiVersion(),
                ]
            )->getContent(),
            true
        );
    }

    public function getDataSet(): ArrayDataSet|DefaultDataSet
    {
        return $this->getJsonDataSetFromFile();
    }
}
