<?php

namespace KupShop\GraphQLBundle\ApiPublic\Controller;

use GraphQL\Type\Definition\ResolveInfo;
use KupShop\GraphQLBundle\ApiAdmin\Annotation\Module;
use KupShop\GraphQLBundle\ApiPublic\Types\Cart\Cart;
use KupShop\GraphQLBundle\ApiPublic\Types\Payload\CartUpdatePayload;
use KupShop\GraphQLBundle\ApiPublic\Util\CartUtil;
use KupShop\GraphQLBundle\ApiShared\Types\Enums\PhotoSizeEnum;
use KupShop\GraphQLBundle\ApiShared\Types\Result;
use KupShop\GraphQLBundle\ApiShared\Util\GraphQLUtil;
use KupShop\GraphQLBundle\Exception\CartPreconditionFailedException;
use KupShop\OrderingBundle\Exception\CartValidationException;
use TheCodingMachine\GraphQLite\Annotations\Mutation;
use TheCodingMachine\GraphQLite\Annotations\Query;
use TheCodingMachine\GraphQLite\Annotations\UseInputType;

class CartController
{
    /** @var CartUtil */
    private $cartUtil;

    /** @var GraphQLUtil */
    private $graphQLUtil;

    /**
     * @required
     */
    public function setCartUtil(CartUtil $cartUtil): void
    {
        $this->cartUtil = $cartUtil;
    }

    /**
     * @required
     */
    public function setGraphQLUtil(GraphQLUtil $graphQLUtil): void
    {
        $this->graphQLUtil = $graphQLUtil;
    }

    #[Query]
    #[Module(\Modules::JS_SHOP)]
    public function cart(ResolveInfo $resolveInfo, bool $invalidateCache = false): Cart
    {
        return $this->cartUtil->getCart(
            $invalidateCache
        );
    }

    /**
     * @Mutation()
     *
     * @UseInputType(for="$items", inputType="[CartItemInput!]!")
     */
    #[Module(\Modules::JS_SHOP)]
    public function cartUpdate(ResolveInfo $resolveInfo, array $items, ?\DateTimeInterface $lastUpdated): CartUpdatePayload
    {
        try {
            $this->cartUtil->updateCart($items, $lastUpdated);
        } catch (CartPreconditionFailedException $e) {
            $this->cartUtil->invalidatePurchaseState();
            $result = new Result(false, 'Precondition failed: The cart content has been modified in the meantime', 412);
        }

        return $this->getCartUpdateResponse($resolveInfo, $result ?? new Result(true));
    }

    #[Query]
    #[Module(\Modules::JS_SHOP)]
    public function alsoBought(ResolveInfo $resolveInfo1, int $limit = 7): string
    {
        $products = $this->cartUtil->getAlsoBought($limit);

        $smarty = createSmarty(false, true);
        $smarty->assign('products', $products);
        $html = $smarty->fetch('block.products.cart-box.alsobought.tpl');

        return $html;
    }

    #[Mutation]
    #[Module(\Modules::JS_SHOP)]
    public function addCoupon(ResolveInfo $resolveInfo, string $couponCode): CartUpdatePayload
    {
        try {
            if (!$this->cartUtil->addCoupon($couponCode)) {
                throw new CartValidationException(translate('error', 'order')['false_coupon']);
            }
        } catch (CartValidationException $e) {
            return $this->getCartUpdateResponse($resolveInfo, new Result(false, $e->getMessage()));
        }

        return $this->getCartUpdateResponse($resolveInfo, new Result(true));
    }

    private function getCartUpdateResponse(ResolveInfo $resolveInfo, Result $result): CartUpdatePayload
    {
        $payload = new CartUpdatePayload($result);

        // pokud si o kosik nerikam, tak ho zbytecne nenacitam
        if ($resolveInfo->getFieldSelection()['cart'] ?? false) {
            $payload->setCart(
                $this->cartUtil->getCart()
            );
        }

        return $payload;
    }

    private function getFetchOptions(ResolveInfo $resolveInfo, array $pathPrefix = []): array
    {
        $fetchOptions = [];

        $fieldSelection = $resolveInfo->getFieldSelection(3);
        foreach ($pathPrefix as $prefix) {
            $fieldSelection = $fieldSelection[$prefix];
        }

        if ($fieldSelection['items']['product']['photos'] ?? false) {
            $field = $this->graphQLUtil->lookAhead($resolveInfo, array_merge($pathPrefix, ['items', 'product', 'photos']));
            $fetchOptions['photos'] = $field['args']['size'] ?? PhotoSizeEnum::PHOTO_DETAIL;
        }

        if ($fieldSelection['items']['product']['photo'] ?? false) {
            $fetchOptions['publicPhoto'] = true;
        }

        if ($fieldSelection['items']['product']['variations'] ?? false || ($fieldSelection['items']['gtmActions'] ?? false)) {
            $fetchOptions['variations'] = true;
        }

        if ($fieldSelection['items']['product']['stores'] ?? false) {
            $fetchOptions['stores'] = true;
        }

        if ($fieldSelection['items']['product']['inStoreSuppliers'] ?? false) {
            $fetchOptions['inStoreSuppliers'] = true;
        }

        return $fetchOptions;
    }
}
