<?php

/**
 * Created by PhpStorm.
 * User: filip
 * Date: 11/25/16
 * Time: 11:43 AM.
 */
class InsertProductsTypesTest extends DatabaseTestCase
{
    /** @var InsertProductsTypes */
    private $insertProductsTypes;

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

        $this->insertProductsTypes = new InsertProductsTypes();
    }

    public function testInsertProductsTypesUnknownType()
    {
        $this->expectException(InvalidArgumentException::class);

        $params = ['type' => 'nesmysl', 'count' => 1];
        $this->insertProductsTypes->getProducts($params);
    }

    public function testFollowsRandomParam()
    {
        //      It randomly fails - depends on current date, impossible to mock now
        //      $this->assertNotEquals(
        //         $this->insertProductsTypes->getProducts(['type' => 'newest_product']),
        //         $this->insertProductsTypes->getProducts(['type' => 'newest_product', 'random' => 1])
        //      );
    }

    public function testRandomIsRandomOneADay()
    {
        // Hope this tests won't run at midnight
        $params = ['type' => 'newest_product', 'random' => 1, 'count' => 1];
        $this->assertEquals(
            $this->insertProductsTypes->getProducts($params),
            $this->insertProductsTypes->getProducts($params)
        );
    }

    public function testVeryRandomIsRandomEveryTime()
    {
        $params = ['type' => 'newest_product', 'random' => 'very_random', 'count' => 1];
        srand(42);
        $this->assertNotEquals(
            $this->insertProductsTypes->getProducts($params),
            $this->insertProductsTypes->getProducts($params)
        );
    }

    /**
     * @expectedException \InvalidArgumentException
     */
    public function testThrowsOnMissingType()
    {
        $this->insertProductsTypes->getProducts(['type' => 'nonexistent', 'count' => 1, 'image' => 1]);
    }

    public function testTypeNewestProduct()
    {
        $result = $this->insertProductsTypes->getProducts(['type' => 'newest_product', 'count' => 1, 'image' => 1]);
        $this->assertEquals('7', $result->first()->id);
    }

    public function testTypeNewestProductWithPhoto()
    {
        $result = $this->insertProductsTypes->getProducts(['type' => 'newest_product', 'count' => 1, 'image' => 1, 'image_exists' => true]);
        $this->assertEquals('1', $result->first()->id);
    }

    public function testTypeCampaignProduct()
    {
        $result = $this->insertProductsTypes->getProducts(
            ['type' => 'campaign_product', 'count' => 10, 'image' => 1, 'campaign' => 'L']
        );

        $this->assertCount(7, $result);
    }

    public function testTypeCartProduct()
    {
        $result = $this->insertProductsTypes->getProducts(
            ['type' => 'cart_product', 'count' => 10, 'products' => [new Product(1)], 'order' => 'p.id']
        );

        $this->assertEquals([2, 10], $result->getKeys());
    }

    public function testTypeArticleProduct()
    {
        $result = $this->insertProductsTypes->getProducts(
            ['type' => 'article_product', 'count' => 10, 'image' => 1, 'article' => '2']
        );

        $this->assertCount(1, $result);
        $this->assertEquals(1, $result->first()['id']);
    }

    public function testTypeAlsoBought()
    {
        $result = $this->insertProductsTypes->getProducts(
            ['type' => 'also_bought', 'count' => 10, 'ID' => 1]
        );

        $result2 = $this->insertProductsTypes->getProducts(
            ['type' => 'also_buyed', 'count' => 10, 'ID' => 1]
        );

        $this->assertEquals([2, 10], $result->getKeys());
        $this->assertEquals([2, 10], $result2->getKeys());
    }

    public function testTypeBestsellingProduct()
    {
        $result = $this->insertProductsTypes->getProducts(
            ['type' => 'bestselling_product', 'count' => 3]
        );

        $this->assertEquals([11, 3, 10], $result->getKeys());
    }

    /**
     * @dataProvider dataSet_testAcceptsCountParam
     */
    public function testFollowsCountParam($params, $expectedCount)
    {
        $this->assertCount($expectedCount, $this->insertProductsTypes->getProducts($params));
    }

    public function dataSet_testAcceptsCountParam()
    {
        return [
            [['type' => 'newest_product', 'count' => 3], 3],
            [['type' => 'newest_product', 'count' => 4], 4],
        ];
    }

    /**
     * @dataProvider dataSet_testTypeCollectionProduct
     */
    public function testTypeCollectionProduct($id_product, $expectedIDs)
    {
        $result = $this->insertProductsTypes->getProducts(
            ['type' => 'collection_product', 'image' => 1, 'product' => $id_product]
        );

        $this->assertEquals($expectedIDs, array_keys(array_map(function ($x) {
            return $x->id;
        }, $result->toArray())));
    }

    public function dataSet_testTypeCollectionProduct()
    {
        return [
            [1, [1, 2, 3, 4]],
            [2, [1, 2, 3, 4]],
            [3, [1, 2, 3, 4]],
            [4, [1, 2, 3, 4, 5, 6]],
        ];
    }

    public function testTypeCollectionProductStillNotRecursive()
    {
        $result = $this->insertProductsTypes->getProducts(
            ['type' => 'collection_product', 'image' => 1, 'product' => 1]
        );

        $this->assertNotEquals([1, 2, 3, 4, 5, 6], [array_map(function ($x) {
            return $x->id;
        }, $result->toArray())],
            'Ha! Že by se rozchodily rekurzni kolekce? :-)');
    }

    public function testImageType()
    {
        $result = $this->insertProductsTypes->getProducts(
            ['type' => 'collection_product', 'count' => 1, 'product' => 1, 'image' => 1, 'image_kind' => 'O']
        );

        $this->assertEquals(3, $result[1]->photoId);

        $result = $this->insertProductsTypes->getProducts(
            ['type' => 'collection_product', 'count' => 1, 'product' => 1, 'image' => 1]
        );

        $this->assertEquals(1, $result[1]->photoId);
    }

    protected function getDataSet()
    {
        return parent::getJsonDataSetFromFile();
    }
}
