<?php

declare(strict_types=1);

namespace KupShop\OrderingBundle\Tests\OrderList;

use KupShop\OrderingBundle\Entity\Order\OrderItem;
use KupShop\OrderingBundle\OrderList\OrderCollection;
use KupShop\OrderingBundle\OrderList\OrderList;
use Query\Operator;

class OrderListTest extends \DatabaseTestCase
{
    /** @var OrderList */
    private $orderList;

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

        $this->orderList = $this->get(OrderList::class);
    }

    public function testGetOrders(): void
    {
        $orders = $this->getOrderList()->getOrders($totalCount);

        $this->assertInstanceOf(OrderCollection::class, $orders);
        $this->assertCount(3, $orders);
        $this->assertEquals($orders->count(), $totalCount);
    }

    public function testGetOrdersWithItems(): void
    {
        $orders = $this->getOrderList()
            ->fetchItems()
            ->getOrders();

        foreach ($orders as $order) {
            $this->assertNotEmpty($order->items);
            $this->assertNotEmpty($order->total_price_array);
            $this->assertNotEmpty($order->vats);
        }
    }

    /**
     * Otestuje, ze pri pouziti order listu vickrat za sebou nacte spravne produkty (ProductCollection). Byl byg, ze
     * se do product listu dostala andSpec z predesleho nacteni, takze v prvni objednavce byla ProductCollection spravne
     * ale v druhe objednavce uz byl AND where z predesleho a tak se nenacetly produkty.
     */
    public function testGetOrdersBugIncorrectProductList(): void
    {
        $ordersCollection1 = $this->getOrderList()
            ->fetchItems()
            ->andSpec(Operator::equals(['o.id' => 1]))
            ->getOrders();

        $ordersCollection2 = $this->getOrderList()
            ->fetchItems()
            ->andSpec(Operator::equals(['o.id' => 2]))
            ->getOrders();

        $order1 = $ordersCollection1->first();
        $order2 = $ordersCollection2->first();

        $this->assertNotEmpty($order1->productList->toArray());
        $this->assertNotEmpty($order2->productList->toArray());
    }

    public function testOrderVsOrderListOrder(): void
    {
        $order = new \Order();
        $order->createFromDB(3);

        $orders = $this->getOrderList()
            ->andSpec(Operator::equals(['id' => 3]))
            ->getOrders();

        $this->assertEquals($order, $orders->current(), 'Porovnat, ze objednavka pres OrderList je stejna jako pres createFromDB');
    }

    public function testOrderFetchItemsVsMultiFetchItems(): void
    {
        $order = new \Order();
        $order->createFromDB(3);
        $order->fetchItems();

        $orders = $this->getOrderList()
            ->fetchItems()
            ->andSpec(Operator::equals(['id' => 3]))
            ->getOrders();

        $orderListOrder = $orders->current();

        $this->assertEquals($order->productList, $orderListOrder->productList, 'Zkontrolovat, ze je vytvoreny productList na objednavce');

        foreach ($orderListOrder->fetchItems() as $itemId => $item) {
            $this->assertInstanceOf(OrderItem::class, $item);
            $this->assertEquals($order->fetchItems()[$itemId], $item->getItem());
        }
    }

    public function testOrderItemArrayAccess(): void
    {
        $orders = $this->getOrderList()
            ->fetchItems()
            ->andSpec(Operator::equals(['id' => 3]))
            ->getOrders();

        $order = $orders->current();

        $items = $order->fetchItems();
        /** @var OrderItem $item */
        $item = reset($items);

        // test backward compatibility array access
        $this->assertEquals($item->getDescr(), $item['descr']);
        $this->assertNotEmpty($item['piece_price']);
        // test array access on getters
        $this->assertEquals($item->getPiecePrice(), $item['piecePrice']);
    }

    private function getOrderList(): OrderList
    {
        return clone $this->orderList;
    }
}
