<?php

declare(strict_types=1);

namespace KupShop\PreordersBundle\Tests\Services;

use KupShop\DevelopmentBundle\Util\Tests\CartTestTrait;
use KupShop\PreordersBundle\Entity\UserPreorder;
use KupShop\PreordersBundle\Service\DynamicPrices;
use KupShop\PreordersBundle\Service\PreorderItemsUpdater;
use KupShop\PreordersBundle\Service\PreorderUtil;
use KupShop\PreordersBundle\Tests\PreordersTestHelper;
use Query\Operator;
use Query\QueryBuilder;

class DynamicPriceTest extends \DatabaseTestCase
{
    use PreordersTestHelper;
    use CartTestTrait;

    private PreorderItemsUpdater $itemsUpdater;
    private DynamicPrices $dynamicPriceService;

    protected function setUp(): void
    {
        parent::setUp();

        $this->itemsUpdater = $this->get(PreorderItemsUpdater::class);
        $this->dynamicPriceService = $this->get(DynamicPrices::class);
    }

    public function testDynamicPriceService()
    {
        $userPreorder = $this->createTestUserPreorder();

        $productList = $this->get(PreorderUtil::class)->getPreorderProductList(
            $userPreorder->getItems(true),
            false,
        );

        $products = $productList->getProducts();
        $refProductList = (new \ProductList(true))
            ->andSpec(function (QueryBuilder $qb) use ($products) {
                $qb->andWhere(Operator::inIntArray($products->getProductIds(), 'p.id'));
            });

        $this->dynamicPriceService->inject(
            $products,
            $refProductList,
            $userPreorder->getPreorder(),
        );

        $dynamicPrices = [];
        foreach ($products as $id => /* @var $p \Product */ $p) {
            if (empty($p->variations)) {
                $this->assertCount(
                    expectedCount: 4,
                    haystack: $p['dynamic_prices'] ?? [],
                    message: 'Chyba v dynamických cenách na produktu.',
                );

                $dynamicPrices[$id] = $p['dynamic_prices'];
                continue;
            }

            $this->assertTrue(!isset($p['dynamic_prices']));

            foreach ($p->variations as $idVar => $variation) {
                $this->assertCount(
                    expectedCount: 4,
                    haystack: $variation['dynamic_prices'] ?? [],
                    message: 'Chyba v dynamických cenách na variantě.',
                );

                $dynamicPrices[$id.'/'.$idVar] = $variation['dynamic_prices'];
            }
        }

        array_walk_recursive($dynamicPrices, function (&$price) {
            $price = [
                'price' => $price->getPriceWithoutVat(),
                'currency' => $price->getCurrency()->getId(),
                'vat' => $price->getVat(),
            ];
        });

        $expected = [
            '4/1' => [
                0 => [
                    'price' => [
                        'price' => \Decimal::create('4132.23140496', 8),
                        'currency' => 'CZK',
                        'vat' => \Decimal::create('21', 16),
                    ],
                ],
                1 => [
                    'price' => [
                        'price' => \Decimal::create('3801.65289256', 8),
                        'currency' => 'CZK',
                        'vat' => \Decimal::create('21', 16),
                    ],
                ],
                2 => [
                    'price' => [
                        'price' => \Decimal::create('3636.36363636', 8),
                        'currency' => 'CZK',
                        'vat' => \Decimal::create('21', 16),
                    ],
                ],
                3 => [
                    'price' => [
                        'price' => \Decimal::create('3471.07438017', 8),
                        'currency' => 'CZK',
                        'vat' => \Decimal::create('21', 16),
                    ],
                ],
            ],
            '4/2' => [
                0 => [
                    'price' => [
                        'price' => \Decimal::create('4132.23140496', 8),
                        'currency' => 'CZK',
                        'vat' => \Decimal::create('21', 16),
                    ],
                ],
                1 => [
                    'price' => [
                        'price' => \Decimal::create('3801.65289256', 8),
                        'currency' => 'CZK',
                        'vat' => \Decimal::create('21', 16),
                    ],
                ],
                2 => [
                    'price' => [
                        'price' => \Decimal::create('3636.36363636', 8),
                        'currency' => 'CZK',
                        'vat' => \Decimal::create('21', 16),
                    ],
                ],
                3 => [
                    'price' => [
                        'price' => \Decimal::create('3471.07438017', 8),
                        'currency' => 'CZK',
                        'vat' => \Decimal::create('21', 16),
                    ],
                ],
            ],
            '10' => [
                0 => [
                    'price' => [
                        'price' => \Decimal::create('1748.69565217', 8),
                        'currency' => 'CZK',
                        'vat' => \Decimal::create('15', 16),
                    ],
                ],
                1 => [
                    'price' => [
                        'price' => \Decimal::create('1608.69565217', 8),
                        'currency' => 'CZK',
                        'vat' => \Decimal::create('15', 16),
                    ],
                ],
                2 => [
                    'price' => [
                        'price' => \Decimal::create('1539.13043478', 8),
                        'currency' => 'CZK',
                        'vat' => \Decimal::create('15', 16),
                    ],
                ],
                3 => [
                    'price' => [
                        'price' => \Decimal::create('1468.69565217', 8),
                        'currency' => 'CZK',
                        'vat' => \Decimal::create('15', 16),
                    ],
                ],
            ],
        ];

        $this->assertEquals($expected, $dynamicPrices);
    }

    public function testUpdatePiecePrice()
    {
        $userId = 1;
        $this->loginUser($userId);
        $dateId = $this->createDate(1);

        $userPreorder = new UserPreorder($userId, $dateId);

        $userPreorder->setItem(
            idProduct: 4,
            idVariation: 1,
            count: 1,
            // piecePrice: toDecimal('123456789'),
        );
        $this->itemsUpdater->recalculatePiecePrices($userPreorder);

        $expectedPrice = '3801.6529';
        $this->assertEquals(
            $expectedPrice,
            $userPreorder->getItems(true)[0]['piece_price'],
        );

        $userPreorder->setItem(
            idProduct: 4,
            idVariation: 2,
            count: 3,
            // piecePrice: toDecimal('123456789'),
        );
        $this->itemsUpdater->recalculatePiecePrices($userPreorder);

        $expectedPrice = '3636.3636';
        $this->assertEquals(
            $expectedPrice,
            $userPreorder->getItems(true)[1]['piece_price'],
        );

        $this->assertEquals(
            $expectedPrice,
            $userPreorder->getItems(true)[0]['piece_price'],
        );

        $userPreorder->setItem(
            idProduct: 10,
            count: 10,
            // piecePrice: toDecimal('123456789'),
        );
        $this->itemsUpdater->recalculatePiecePrices($userPreorder);

        $expectedPrice = '3471.0744';
        $this->assertEquals(
            $expectedPrice,
            $userPreorder->getItems(true)[2]['piece_price'],
        );

        $this->assertEquals(
            $expectedPrice,
            $userPreorder->getItems(true)[1]['piece_price'],
        );

        $expectedPrice = '1468.6957';
        $this->assertEquals(
            $expectedPrice,
            $userPreorder->getItems(true)[0]['piece_price'],
        );
    }
}
