<?php

declare(strict_types=1);

namespace Dedi\SyliusTheme\Twig;

use Dedi\SyliusTheme\Specification\IsVariantStockAvailableSpecification;
use Dedi\SyliusTheme\Specification\IsVariantStockTrackedSpecification;
use Sylius\Component\Core\Model\ProductVariantInterface;
use Sylius\Component\Product\Model\ProductInterface;
use Sylius\Component\Product\Repository\ProductRepositoryInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

class ProductStockAvailableExtension extends AbstractExtension
{
    public function __construct(private readonly ProductRepositoryInterface $productRepository)
    {
    }

    public function getFunctions(): array
    {
        return [
            new TwigFunction('product_stock_available', [$this, 'isProductStockAvailable']),
            new TwigFunction('simple_product_stock_is_available_and_tracked', [$this, 'isProductSimpleStockAvailableAndTracked']),
        ];
    }

    public function isProductStockAvailable(string $productCode): bool
    {
        $product = $this->productRepository->findOneBy([
            'code' => $productCode,
        ]);

        if (!$product instanceof ProductInterface) {
            return false;
        }

        return $this->productHasAtLeastOneAvailableVariant($product);
    }

    public function isProductSimpleStockAvailableAndTracked(ProductInterface $product): bool
    {
        //Only used for simple products as data must be updated at each variant selection for configurable products
        if ($product->isSimple()) {
            return $this->isSimpleProductStockIsAvailableAndTracked($product);
        }

        return false;
    }

    private function productHasAtLeastOneAvailableVariant(ProductInterface $product): bool
    {
        $variants = $product->getEnabledVariants();

        /** @var ProductVariantInterface $variant */
        foreach ($variants as $variant) {
            if (IsVariantStockAvailableSpecification::isSatisfiedBy($variant)) {
                return true;
            }
        }

        return false;
    }

    private function isSimpleProductStockIsAvailableAndTracked(ProductInterface $product): bool
    {
        /** @var ProductVariantInterface $variant */
        $variant = $product->getEnabledVariants()[0];

        return IsVariantStockAvailableSpecification::isSatisfiedBy($variant) &&
            IsVariantStockTrackedSpecification::isSatisfiedBy($variant);
    }
}
