<?php

namespace FiloBlu\Flow\Model\From\Entity;

use Exception;
use FiloBlu\Flow\Helper\LoggerProvider;
use Magento\Catalog\Model\Product\Action;
use Magento\Catalog\Model\ProductFactory;
use Magento\CatalogUrlRewrite\Block\UrlKeyRenderer;
use Magento\CatalogUrlRewrite\Model\ProductScopeRewriteGenerator;
use Magento\Eav\Model\Entity\Attribute\Source\BooleanFactory;
use Magento\Eav\Model\Entity\AttributeFactory;
use Magento\Eav\Model\Entity\TypeFactory;
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\ObjectManagerInterface;
use Magento\Framework\Registry;
use Magento\Store\Model\ScopeInterface;
use Magento\UrlRewrite\Model\Storage\DbStorage;
use Magento\UrlRewrite\Model\UrlPersistInterface;
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite;
use RuntimeException;
use function in_array;
use function sprintf;

/**
 * Class Product
 * @package FiloBlu\Flow\Model\From\Entity
 */
class Product extends AbstractEntity
{
    /**
     * @var Action
     */
    protected $productAction;

    /**
     * @var array
     */
    protected $attributeMappedByValue;


    /**
     * Product constructor.
     * @param Registry $registry
     * @param ProductFactory $productFactory
     * @param \FiloBlu\Flow\Helper\Product $helperProduct
     * @param \FiloBlu\Flow\Helper\Attribute $helperAttribute
     * @param LoggerProvider $loggerProvider
     * @param AttributeFactory $attributeFactory
     * @param CollectionFactory $attributeOptionCollectionFactory
     * @param ObjectManagerInterface $objectManager
     * @param TypeFactory $entityTypeFactory
     * @param Action $productAction
     * @param BooleanFactory $booleanFactory
     * @param array $attributeMappedByValue
     * @param array $data
     */
    public function __construct(
        Registry $registry,
        ProductFactory                 $productFactory,
        \FiloBlu\Flow\Helper\Product   $helperProduct,
        \FiloBlu\Flow\Helper\Attribute $helperAttribute,
        LoggerProvider                 $loggerProvider,
        AttributeFactory               $attributeFactory,
        CollectionFactory              $attributeOptionCollectionFactory,
        ObjectManagerInterface         $objectManager,
        TypeFactory                    $entityTypeFactory,
        Action                         $productAction,
        BooleanFactory                 $booleanFactory,
        array                          $attributeMappedByValue = [],
        array                          $data = []
    ) {
        $this->productAction = $productAction;
        $this->attributeMappedByValue = $attributeMappedByValue;

        parent::__construct($registry,
            $productFactory,
            $helperProduct,
            $helperAttribute,
            $loggerProvider,
            $attributeFactory,
            $attributeOptionCollectionFactory,
            $objectManager,
            $entityTypeFactory,
            $booleanFactory,
            $data);
    }

    /**
     * @return void
     * @throws Exception
     */
    protected function setObjectAttributeValue()
    {
        if (!$this->getObjectId()) {
            throw new RuntimeException(sprintf('No id found for model %s with given identifier %s', $this->getEntityModel(), $this->entityIdentifier));
        }

        $attributeCode = $this->getAttribute()->getAttributeCode();

        $pIds = [$this->getObjectId()];

        $fatherProductsIds = $this->helperProduct->getParentProductsIds($pIds);
        $attributesToCopy = $this->registry->registry('attribute_configurable_copy');
        if (!empty($fatherProductsIds) && in_array($attributeCode, $attributesToCopy, false)) {
            $pIds = array_merge($pIds, $fatherProductsIds);
        }

        $parentGrouped = $this->helperProduct->getGroupedIdByChildId($this->getObjectId());
        if($parentGrouped) {
            $parentGroupedId = [$parentGrouped->getId()];
            $attributesCopyToGrouped = $this->helperProduct->getSimpleAttributesSyncToGrouped();
            if(in_array($attributeCode, $attributesCopyToGrouped, false)) {
                $pIds = array_merge($pIds, $parentGroupedId);
            }
        }

        $attributeValue = $this->getAttributeValue();
        $attributesData = [$attributeCode => $attributeValue];

        if($attributeCode === 'url_key'){
            $this->updateUrls($attributeValue);
            return;
        }

        if ($attributeCode !== 'sku') {
            $this->productAction->updateAttributes($pIds, $attributesData, $this->storeId);
        }
    }

    /**
     * @return bool|mixed|null
     * @throws Exception
     */
    public function getObjectId()
    {
        if ($this->_objectEntityId === null) {
            $this->_objectEntityId = ObjectManager::getInstance()->create($this->getEntityModel())->getIdBySku($this->entityIdentifier);
            if (empty($this->_objectEntityId)) {
                $this->_objectEntityId = false;
            }
        }

        return $this->_objectEntityId;
    }

    /**
     * @return \Magento\Catalog\Model\Product|null
     * @throws Exception
     */
    protected function getObject()
    {
        if ($this->objectEntity === null) {
            if (!$this->getObjectId()) {
                throw new RuntimeException('No id found for model ' . $this->getEntityModel() . ' with given identifier ' . $this->entityIdentifier);
            }
            $sku = $this->productFactory->create()->getIdBySku($this->entityIdentifier);
            $this->objectEntity = $this->productFactory->create()->setStoreId($this->storeId)->load($sku);
            if (!$this->objectEntity->getId()) {
                throw new RuntimeException('No instance found for model ' . $this->getEntityModel() . ' with id ' . $this->getObjectId());
            }
        }
        return $this->objectEntity;
    }

    /**
     * @throws Exception
     */
    public function updateUrls(string $attributeValue): void
    {
        $generator = $this->objectManager->get(ProductScopeRewriteGenerator::class);
        $urlPersist = $this->objectManager->get(UrlPersistInterface::class);
        $product = $this->getObject();
        $product->setUrlKey($attributeValue);
        $product->addAttributeUpdate('url_key', $attributeValue, $product->getStoreId());

        if ($this->helperProduct->getScopeConfig()->isSetFlag(
            UrlKeyRenderer::XML_PATH_SEO_SAVE_HISTORY,
            ScopeInterface::SCOPE_STORE,
            $product->getStoreId())) {
            $product->setData('save_rewrites_history', 1);
        }

        $urls = $generator->generateForSpecificStoreView($product->getStoreId(), [], $product);

        $urlPersist->deleteByData([
            UrlRewrite::ENTITY_ID => $product->getId(),
            UrlRewrite::ENTITY_TYPE => 'product',
            UrlRewrite::REDIRECT_TYPE => 0,
            UrlRewrite::STORE_ID => $product->getStoreId()
        ]);

        $urlPersist->replace($urls);
    }
}
