<?php

namespace KupShop\GraphQLBundle\ApiPublic\Types\Cart;

use KupShop\BonusProgramBundle\Utils\BonusComputer;
use KupShop\GraphQLBundle\ApiAdmin\Annotation\Module;
use KupShop\GraphQLBundle\ApiPublic\Types\Cart\ShippingInfo\ShippingInfo;
use KupShop\GraphQLBundle\ApiShared\ApiUtil;
use KupShop\GraphQLBundle\ApiShared\Types\Price\TotalPrice;
use KupShop\I18nBundle\Util\PriceConverter;
use KupShop\KupShopBundle\Context\CurrencyContext;
use KupShop\KupShopBundle\Context\UserContext;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\OrderingBundle\Entity\Purchase\PurchaseState;
use KupShop\OrderingBundle\Util\Purchase\PurchaseUtil;
use TheCodingMachine\GraphQLite\Annotations\Field;
use TheCodingMachine\GraphQLite\Annotations\Type;

/**
 * @Type()
 */
class Cart
{
    /**
     * @var PurchaseState
     */
    private $purchaseState;

    private $purchaseUtil;

    public function __construct(PurchaseUtil $purchaseUtil, PurchaseState $purchaseState)
    {
        $this->purchaseState = $purchaseState;
        $this->purchaseUtil = $purchaseUtil;
    }

    /**
     * @Field()
     */
    public function getUrl(): string
    {
        return path('kupshop_content_cart_cart_1');
    }

    /**
     * @Field
     */
    public function getTotalPrice(): TotalPrice
    {
        // getTotalPriceForDiscounts is getTotalPrice without delivery/payment price
        return new TotalPrice(
            $this->purchaseState->getTotalPriceForDiscounts()
        );
    }

    /**
     * @Field
     *
     * @return CartItem[]
     */
    public function getItems(): array
    {
        $items = [];
        foreach ($this->purchaseState->getProducts() as $item) {
            $items[] = new CartItem($item, $this->purchaseState->createProductCollection());
        }

        return $items;
    }

    /**
     * @Field()
     */
    public function getSavings(): TotalPrice
    {
        return new TotalPrice(
            $this->purchaseUtil->getPurchaseStateSavings()
        );
    }

    /**
     * @Field()
     */
    public function getCharges(): TotalPrice
    {
        return new TotalPrice(
            $this->purchaseUtil->getPurchaseStateCharges()
        );
    }

    /**
     * @Field()
     */
    public function getShippingInfo(): ShippingInfo
    {
        return new ShippingInfo(
            $this->purchaseState,
            $this->purchaseUtil->getShippingInfo($this->purchaseState)
        );
    }

    /**
     * @Field
     */
    public function freeDeliveryFrom(): ?float
    {
        $freeDelivery = $this->purchaseUtil->getFreeDeliveryFrom();
        $userContext = Contexts::get(UserContext::class);

        $freeDeliveryFrom = $userContext->getActive() ? $freeDelivery['registered'] ?? null : $freeDelivery['unregistered'] ?? null;

        if ($freeDeliveryFrom) {
            $converter = ServiceContainer::getService(PriceConverter::class);
            $currencyContext = Contexts::get(CurrencyContext::class);
            $result = $converter->convert($freeDeliveryFrom->getCurrency(),
                $currencyContext->getActive(),
                $freeDeliveryFrom->getValue())->asFloat();
        }

        return $result ?? null;
    }

    /**
     * @Field
     *
     * @return Coupon[]
     */
    public function getActiveCoupons(): array
    {
        $items = [];
        foreach ($this->purchaseState->getActiveCoupons() as $item) {
            $items[] = new Coupon($item);
        }

        return $items;
    }

    #[Field(description: 'Body za nákup.')]
    #[Module(\Modules::BONUS_PROGRAM)]
    public function getBonusPoints(): float
    {
        return ServiceContainer::getService(BonusComputer::class)->countBonusPoints(
            $this->purchaseState
        )->asFloat();
    }

    #[Field]
    public function getLastUpdated(): ?\DateTimeInterface
    {
        $maxDate = null;
        foreach ($this->purchaseState->getProducts() as $item) {
            $date = !empty($item->getDate()) ? ApiUtil::prepareDateTimeFromDB($item->getDate()) : null;
            if ($date && $date > $maxDate) {
                $maxDate = $date;
            }
        }

        return $maxDate;
    }

    #[Field]
    public function getAvailability(): int
    {
        return $this->purchaseUtil->getCart()->getAvailability();
    }
}
