<?php

/**
 * Created by PhpStorm.
 * User: ondra
 * Date: 23.11.17
 * Time: 8:08.
 */

namespace KupShop\QuantityDiscountBundle\Tests;

use KupShop\DevelopmentBundle\Util\Tests\CartTestTrait;
use KupShop\QuantityDiscountBundle\Context\QuantityDiscountContext;
use KupShop\QuantityDiscountBundle\Util\QuantityDiscountPrice;
use KupShop\QuantityDiscountBundle\Util\QuantityDiscountUtil;

class QuantityDiscountTest extends \DatabaseTestCase
{
    use CartTestTrait;

    private QuantityDiscountUtil $quantityDiscountUtil;
    private QuantityDiscountPrice $quantityDiscountPrice;
    private QuantityDiscountContext $quantityDiscountContext;

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

        $this->quantityDiscountUtil = $this->get(QuantityDiscountUtil::class);
        $this->quantityDiscountPrice = $this->get(QuantityDiscountPrice::class);
        $this->quantityDiscountContext = $this->get(QuantityDiscountContext::class);
    }

    /** @dataProvider data_testAddQuantityDiscount */
    public function testAddQuantityDiscount(int $productId, int $pieces, \Decimal $value, string $type, string $expectedType): void
    {
        $this->quantityDiscountUtil->addQuantityDiscount($productId, null, $pieces, $value, type: $type);

        $discount = $this->quantityDiscountPrice->getDiscount($productId, toDecimal($pieces));

        $this->assertEquals($value, $discount['discount']);
        $this->assertEquals($expectedType, $discount['discount_type']);
    }

    public function data_testAddQuantityDiscount(): iterable
    {
        yield 'Add perc quantity discount' => [1, 10, toDecimal(10), QuantityDiscountUtil::DISCOUNT_TYPE_PERC, QuantityDiscountUtil::DISCOUNT_TYPE_PERC];
        yield 'Add EUR quantity discount' => [1, 10, toDecimal(10), 'EUR', 'EUR'];
        yield 'Add deprecated amount quantity discount (inserted with default currency)' => [1, 10, toDecimal(10), QuantityDiscountUtil::DISCOUNT_TYPE_AMOUNT, 'CZK'];
    }

    public function testGetDiscountWithGroupId(): void
    {
        $this->quantityDiscountContext->setActive(1);

        $discount = $this->quantityDiscountPrice->getDiscount(3, toDecimal(3));
        $this->assertEquals(10, $discount['discount']);
        $this->assertEquals(QuantityDiscountUtil::DISCOUNT_TYPE_PERC, $discount['discount_type']);

        $discount = $this->quantityDiscountPrice->getDiscount(3, toDecimal(20));
        $this->assertEquals(100, $discount['discount']);
        $this->assertEquals('CZK', $discount['discount_type']);
    }

    public function testGetVariationPrice()
    {
        $this->assertEquals('2400', $this->quantityDiscountPrice->getPrice(6, toDecimal(3), 17)->getPriceWithVat()->asFloat());
        $this->assertEquals('2250', $this->quantityDiscountPrice->getPrice(6, toDecimal(3), 19)->getPriceWithVat()->asFloat());
        $this->assertEquals('2940', $this->quantityDiscountPrice->getPrice(6, toDecimal(10), 19)->getPriceWithVat()->asFloat());
    }

    public function testGetPrice()
    {
        $this->assertEquals('800', $this->quantityDiscountPrice->getPrice(3, toDecimal(1))->getPriceWithVat()->asFloat());
        $this->assertEquals('760', $this->quantityDiscountPrice->getPrice(3, toDecimal(3))->getPriceWithVat()->asFloat());
        $this->assertEquals('720', $this->quantityDiscountPrice->getPrice(3, toDecimal(5))->getPriceWithVat()->asFloat());
        $this->assertEquals('720', $this->quantityDiscountPrice->getPrice(3, toDecimal(8))->getPriceWithVat()->asFloat());
        $this->assertEquals('640', $this->quantityDiscountPrice->getPrice(3, toDecimal(10))->getPriceWithVat()->asFloat());
        $this->assertEquals('640', $this->quantityDiscountPrice->getPrice(3, toDecimal(20))->getPriceWithVat()->asFloat());
        $this->assertEquals('679', $this->quantityDiscountPrice->getPrice(3, toDecimal(25))->getPriceWithVat()->asFloat());
        $this->assertEquals('611', $this->quantityDiscountPrice->getPrice(3, toDecimal(50))->getPriceWithVat()->asFloat(), 'Discount in EUR - 6 EUR (without vat) * 26 = 156 CZK discount, 188.76 with vat');

        $this->quantityDiscountContext->setActive(1);
        $this->assertEquals('679', $this->quantityDiscountPrice->getPrice(3, toDecimal(20))->getPriceWithVat()->asFloat());
    }

    public function testGetDiscount()
    {
        $this->assertEquals(null, $this->quantityDiscountPrice->getDiscount(3, toDecimal(1)));
        $this->assertEquals(5, $this->quantityDiscountPrice->getDiscount(3, toDecimal(4))['discount']);
        $this->assertEquals(10, $this->quantityDiscountPrice->getDiscount(3, toDecimal(5))['discount']);
        $this->assertEquals(10, $this->quantityDiscountPrice->getDiscount(3, toDecimal(9))['discount']);
        $this->assertEquals(20, $this->quantityDiscountPrice->getDiscount(3, toDecimal(10))['discount']);
        $this->assertEquals(20, $this->quantityDiscountPrice->getDiscount(3, toDecimal(20))['discount']);
        $this->assertEquals(QuantityDiscountUtil::DISCOUNT_TYPE_PERC, $this->quantityDiscountPrice->getDiscount(3, toDecimal(20))['discount_type']);

        $this->assertEquals(100, $this->quantityDiscountPrice->getDiscount(3, toDecimal(25))['discount']);
        $this->assertEquals('CZK', $this->quantityDiscountPrice->getDiscount(3, toDecimal(25))['discount_type']);

        $this->assertEquals(6, $this->quantityDiscountPrice->getDiscount(3, toDecimal(50))['discount']);
        $this->assertEquals('EUR', $this->quantityDiscountPrice->getDiscount(3, toDecimal(50))['discount_type']);
    }

    /*
        public function testGetPriceForDealer()
        {
            $user = \User::createFromId(1);
            $user->activateUser();
            // user has B2B price level
            // quantity discount should not apply
            $this->assertEquals('0', $this->quantityDiscountPrice->getDiscountPercent(3, 1)->asFloat());
            $this->assertEquals('0', $this->quantityDiscountPrice->getDiscountPercent(3, 4)->asFloat());
            $this->assertEquals('0', $this->quantityDiscountPrice->getDiscountPercent(3, 5)->asFloat());
            $this->assertEquals('0', $this->quantityDiscountPrice->getDiscountPercent(3, 9)->asFloat());
            $this->assertEquals('0', $this->quantityDiscountPrice->getDiscountPercent(3, 10)->asFloat());
            $this->assertEquals('0', $this->quantityDiscountPrice->getDiscountPercent(3, 20)->asFloat());
            $this->assertEquals('800', $this->quantityDiscountPrice->getPrice(3, 1)->getPriceWithVat()->asFloat());
            $this->assertEquals('800', $this->quantityDiscountPrice->getPrice(3, 3)->getPriceWithVat()->asFloat());
            $this->assertEquals('800', $this->quantityDiscountPrice->getPrice(3, 5)->getPriceWithVat()->asFloat());
            $this->assertEquals('800', $this->quantityDiscountPrice->getPrice(3, 8)->getPriceWithVat()->asFloat());
            $this->assertEquals('800', $this->quantityDiscountPrice->getPrice(3, 10)->getPriceWithVat()->asFloat());
            $this->assertEquals('800', $this->quantityDiscountPrice->getPrice(3, 20)->getPriceWithVat()->asFloat());
        }
    */

    public function testCartPriceForDealer()
    {
        $user = \User::createFromId(1);
        $user->activateUser();
        $cart = $this->addToCart(3, null, 10);
        // 10 pcs => 20% discount => 6400
        // B2B price level => 50% discount => 3200
        $this->assertEquals('3200', $cart->totalPricePay);
    }

    /** @dataProvider data_cartPrice */
    public function testCartPrice(int $productId, ?int $variationId, int $pieces, float $expectedTotalPrice): void
    {
        $cart = $this->addToCart($productId, $variationId, $pieces);

        $this->assertEquals($expectedTotalPrice, $cart->totalPricePay->asFloat());
    }

    public function data_cartPrice(): array
    {
        return [
            // aplikuje se sleva 10%
            [3, null, 10, 6400],
            // aplikuje se sleva 5%
            [3, null, 6, 4320],
            // neaplikuje se sleva
            [6, 19, 2, 6000],
            // aplikuje se sleva 25%
            [6, 19, 3, 6750],
            [6, 19, 4, 9000],
            // aplikuje se sleva 20%
            [6, 17, 4, 9600],
            // aplikuje se sleva 6 EUR - cena produktu 611 Kc * 50
            [3, null, 50, 30550],
        ];
    }

    private function addToCart($id_product, $id_variation = null, $pieces = 1): \Cart
    {
        $this->createCart();
        $cart = $this->cart;

        $item = [
            'id_product' => $id_product,
            'id_variation' => $id_variation,
            'pieces' => $pieces,
        ];
        $cart->addItem($item);
        $cart->save();
        $cart->load();
        $cart->createFromDB();

        return $cart;
    }

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