<?php

declare(strict_types=1);

namespace KupShop\WarehouseBundle\Tests;

use KupShop\KupShopBundle\Util\StringUtil;
use KupShop\WarehouseBundle\Util\ExpiringProductUtil;
use Query\Operator;

class ExpiringProductActionTest extends \DatabaseTestCase
{
    protected ExpiringProductUtil $expiringProductUtil;

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

        $this->expiringProductUtil = $this->get(ExpiringProductUtil::class);
    }

    public function testExpiringProductNoVariationsNoBatch()
    {
        $result = $this->expiringProductUtil->createFromPosition(124014, null, 27277, 'TEST');

        $this->expiringProductUtil->addDiscountToProduct($result['oldIdProduct'],
            $result['oldIdVariation'],
            $result['idProduct'],
            $result['idVariation'],
            20);

        $this->assertEquals(2, $result['movedPieces']);

        $resultP = $this->getProduct($result['idProduct'], null);

        $this->assertEquals(2, $resultP['p_in_store']);
        $this->assertEquals(20, $resultP['p_discount']);
        $this->assertEquals(2, $resultP['wp_pieces']);
        $this->assertNotEmpty($resultP['p_ean']);
        $this->assertTrue(StringUtil::startsWith($resultP['p_title'], 'TEST '));
    }

    public function testExpiringProductVariationsNoBatch()
    {
        $result = $this->expiringProductUtil->createFromPosition(110222, 1743255, 12880, 'TEST');

        $this->expiringProductUtil->addDiscountToProduct($result['oldIdProduct'],
            $result['oldIdVariation'],
            $result['idProduct'],
            $result['idVariation'],
            10);

        $this->assertEquals(3, $result['movedPieces']);

        $resultP = $this->getProduct($result['idProduct'], $result['idVariation']);

        $this->assertEquals(3, $resultP['p_in_store']);
        $this->assertEquals(3, $resultP['pv_in_store']);
        $this->assertEquals(0, $resultP['p_discount']);
        $this->assertEquals(3, $resultP['wp_pieces']);
        $this->assertEquals($resultP['pv_price'], $resultP['pv_price_for_discount'] * 0.9, delta: 0.01);
        $this->assertEmpty($resultP['p_ean']);
        $this->assertNotEmpty($resultP['pv_ean']);
        $this->assertTrue(StringUtil::startsWith($resultP['p_title'], 'TEST '));

        $result2 = $this->expiringProductUtil->createFromPosition(110222, 1743255, null, 'TEST 2');

        $this->assertEquals(6, $result2['movedPieces']);

        $resultP2 = $this->getProduct($result2['idProduct'], $result2['idVariation']);

        $this->assertEquals(9, $resultP2['p_in_store']);
        $this->assertEquals(9, $resultP2['pv_in_store']);
        $this->assertEquals(0, $resultP2['p_discount']);
        $this->assertEquals(9, $resultP2['wp_pieces']);
        $this->assertEquals($resultP2['pv_price'], $resultP2['pv_price_for_discount'] * 0.9, delta: 0.01);
        $this->assertTrue(StringUtil::startsWith($resultP2['p_title'], 'TEST '));

        $result3 = $this->expiringProductUtil->createFromPosition(110222, 1752161, null, 'TEST 3');

        $this->expiringProductUtil->addDiscountToProduct($result['oldIdProduct'],
            $result3['oldIdVariation'],
            $result3['idProduct'],
            $result3['idVariation'],
            20);

        $this->assertEquals(5, $result3['movedPieces']);

        $resultP3 = $this->getProduct($result3['idProduct'], $result3['idVariation']);

        $this->assertEquals(14, $resultP3['p_in_store']);
        $this->assertEquals(5, $resultP3['pv_in_store']);
        $this->assertEquals(0, $resultP3['p_discount']);
        $this->assertEquals(5, $resultP3['wp_pieces']);
        $this->assertEmpty($resultP3['p_ean']);
        $this->assertNotEmpty($resultP3['pv_ean']);
        $this->assertEquals($resultP3['pv_price'], $resultP3['pv_price_for_discount'] * 0.8, delta: 0.01);

        $this->assertTrue(StringUtil::startsWith($resultP3['p_title'], 'TEST '));

        $this->assertTrue($resultP['p_id'] == $resultP2['p_id'] && $resultP2['p_id'] == $resultP3['p_id']);
        $this->assertTrue($resultP['pv_id'] == $resultP2['pv_id'] && $resultP2['pv_id'] != $resultP3['pv_id']);
    }

    public function testExpiringProductVariationsBatch()
    {
        $resultEmptyPos = $this->expiringProductUtil->createFromBatch(90576, 2466, 13747, 'TEST');

        $this->assertTrue(empty($resultEmptyPos['movedPieces']), 'No pieces should be transfered, the batch is not on the position');

        $result = $this->expiringProductUtil->createFromBatch(90576, 2466, 13746, 'TEST');

        $resultP = $this->getProduct($result['idProduct'], $result['idVariation']);

        $this->assertEquals(14, $result['movedPieces']);

        $this->assertEquals(14, $resultP['p_in_store']);
        $this->assertEquals(14, $resultP['pv_in_store']);
        $this->assertEquals(14, $resultP['wp_pieces']);
        $this->assertTrue(StringUtil::startsWith($resultP['p_title'], 'TEST '));

        $newBatches = $this->getProductBatches($result['idProduct'], $result['idVariation']);

        $this->assertEquals('2025-01-28 00:00:00', $newBatches[0]['date_expiry'], 'Batch was not transfered to the new product');

        $result = $this->expiringProductUtil->createFromBatch(90576, 2450, null, 'TEST');

        $this->expiringProductUtil->addDiscountToProduct($result['oldIdProduct'],
            $result['oldIdVariation'],
            $result['idProduct'],
            $result['idVariation'],
            50);

        $resultP2 = $this->getProduct($result['idProduct'], $result['idVariation']);

        $this->assertEquals(14 + 12, $resultP2['p_in_store']);
        $this->assertEquals(12, $resultP2['pv_in_store']);
        $this->assertEquals(12, $resultP2['wp_pieces']);
        $this->assertEquals(0, $resultP2['p_discount']);
        $this->assertEmpty($resultP2['p_ean']);
        $this->assertNotEmpty($resultP2['pv_ean']);
        $this->assertEquals($resultP2['pv_price'], $resultP2['pv_price_for_discount'] * 0.5, delta: 0.01);

        $newBatches = $this->getProductBatches($result['idProduct'], $result['idVariation']);

        $this->assertEquals('2024-09-24 00:00:00', $newBatches[0]['date_expiry'], 'Batch was not transfered to the new product');
    }

    protected function getDataSet()
    {
        return $this->getJsonDataSetFromFile();
    }

    protected function getProduct($idP, $idV)
    {
        return sqlQueryBuilder()->select('p.id p_id, p.in_store p_in_store, p.discount p_discount, p.title p_title, p.ean p_ean,
        pv.id pv_id, pv.in_store pv_in_store, pv.price pv_price, pv.price_for_discount pv_price_for_discount, pv.ean pv_ean,
        COALESCE(SUM(COALESCE(wp.pieces, 0)),0) wp_pieces')
            ->from('products', 'p')->leftJoin('p', 'products_variations', 'pv', 'pv.id_product = p.id')
            ->leftJoin('pv', 'warehouse_products', 'wp', 'p.id = wp.id_product AND pv.id <=> wp.id_variation')
            ->where(Operator::equalsNullable([
                'p.id' => $idP,
                'pv.id' => $idV,
            ]))->execute()->fetchAssociative();
    }

    protected function getProductBatches($idP, $idV)
    {
        return sqlQueryBuilder()->select('pb.*')
            ->from('warehouse_products', 'wp')
            ->leftJoin('wp', 'products_batches', 'pb', 'wp.id_product = pb.id_product AND wp.id_variation <=> pb.id_variation')
            ->where(Operator::equalsNullable([
                'wp.id_product' => $idP,
                'wp.id_variation' => $idV,
            ]))->execute()->fetchAllAssociative();
    }
}
