<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonSetArticles\Components;

use Shopware\Bundle\StoreFrontBundle\Service\ProductNumberServiceInterface;
use Shopware\Bundle\StoreFrontBundle\Struct\ShopContextInterface;
use Shopware\Components\Model\ModelManager;
use Shopware\CustomModels\ViisonSetArticles\Repository as SetArticleRepository;
use Shopware\Models\Article\Detail as ArticleDetail;
use Shopware\Plugins\ViisonSetArticles\Util;

class ProductNumberServiceDecorator implements ProductNumberServiceInterface
{
    /**
     * @var ProductNumberServiceInterface
     */
    private $decoratedInstance;

    /**
     * @var ModelManager
     */
    private $entityManager;

    /**
     * @param ProductNumberServiceInterface $decoratedInstance
     * @param ModelManager $entityManager
     */
    public function __construct(
        ProductNumberServiceInterface $decoratedInstance,
        ModelManager $entityManager
    ) {
        $this->decoratedInstance = $decoratedInstance;
        $this->entityManager = $entityManager;
    }

    /**
     * @inheritdoc
     *
     * Checks if the article detail (given by number) is available and returns it's number. If the variant is not
     * available, the fallback number of the main variant is returned instead. Since set articles have no last stock,
     * this availability check is always true for set articles (may contain false-positives). So we have to do an
     * additional check here and may return the main variant number, if the manipulated set article variant is in fact
     * not available.
     */
    public function getAvailableNumber($number, ShopContextInterface $context, $selection = [])
    {
        $availableNumber = $this->decoratedInstance->getAvailableNumber($number, $context, $selection);

        // Since we only need to consider false-positives, a negative result can be passed without further checks.
        if ($availableNumber !== $number) {
            return $availableNumber;
        }

        /** @var ArticleDetail|null $articleDetail */
        $articleDetail = $this->entityManager->getRepository('Shopware\\Models\\Article\\Detail')->findOneBy([
            'number' => $number,
        ]);
        if (!$articleDetail || !Util::isSetArticleByArticle($articleDetail->getArticle())) {
            return $availableNumber;
        }

        /** @var SetArticleRepository $setArticleRepository */
        $setArticleRepository = $this->entityManager->getRepository('Shopware\\CustomModels\\ViisonSetArticles\\SetArticle');
        $setArticleAvailability = $setArticleRepository->getCombinedSetArticleDetailsData($articleDetail->getId());

        if (!$setArticleAvailability['available']) {
            return $articleDetail->getArticle()->getMainDetail()->getNumber();
        }

        return $availableNumber;
    }

    /**
     * @inheritdoc
     */
    public function getMainProductNumberById($productId)
    {
        return $this->decoratedInstance->getMainProductNumberById($productId);
    }
}
