<?php

namespace FiloBlu\Flow\Model\Actions\From;

use Exception;
use FiloBlu\Flow\Helper\Product;
use Magento\Catalog\Model\ProductFactory;
use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator;
use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\ConfigurableFactory;
use Magento\Eav\Model\ResourceModel\Entity\Attribute;
use Magento\Framework\App\ProductMetadataInterface;
use Magento\Framework\App\ResourceConnection;
use Magento\UrlRewrite\Model\UrlPersistInterface;
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite;
use function is_array;

/**
 * Class Name
 * @package FiloBlu\Flow\Model\Actions\From
 */
class Name
{
    /**
     * @var string
     */
    CONST ENTITY_TYPE_CODE = 'catalog_product';

    /**
     * @var Product
     */
    protected $_helper_product;

    /**
     * @var ProductFactory
     */
    protected $productFactory;
    /**
     * @var ResourceConnection
     */
    protected $connection;

    /**
     * @var ProductMetadataInterface
     */
    protected $_productMetadata;

    /**
     * @var Attribute
     */
    protected $_eavAttributeModel;

    /**
     * @var ProductUrlRewriteGenerator
     */
    protected $productUrlRewriteGenerator;

    /**
     * @var UrlPersistInterface
     */
    protected $urlPersist;

    /**
     * @var ConfigurableFactory
     */
    protected $configurableFactory;

    /**
     * Name constructor.
     * @param ProductFactory $productFactory
     * @param Product $helper_product
     * @param ProductUrlRewriteGenerator $productUrlRewriteGenerator
     * @param UrlPersistInterface $urlPersist
     * @param ResourceConnection $connection
     * @param ProductMetadataInterface $_productMetadata
     * @param Attribute $_eavAttributeModel
     * @param ConfigurableFactory $configurableFactory
     */
    public function __construct(
        ProductFactory $productFactory,
        Product $helper_product,
        ProductUrlRewriteGenerator $productUrlRewriteGenerator,
        UrlPersistInterface $urlPersist,
        ResourceConnection $connection,
        ProductMetadataInterface $_productMetadata,
        Attribute $_eavAttributeModel,
        ConfigurableFactory $configurableFactory

    )
    {
        $this->_helper_product = $helper_product;
        $this->productFactory = $productFactory;
        $this->productUrlRewriteGenerator = $productUrlRewriteGenerator;
        $this->urlPersist = $urlPersist;
        $this->_productMetadata = $_productMetadata;
        $this->_eavAttributeModel = $_eavAttributeModel;
        $this->configurableFactory = $configurableFactory;
        $this->connection = $connection;
    }

    /**
     * @param $product
     * @param $value
     * @param $storeId
     * @throws Exception
     */
    public function process($product, $value, $storeId)
    {
        if (empty($value)) {
            throw new Exception("Invalid value supplied '{$value}'");
        }

        $parentProductIds = $this->configurableFactory->create()->getParentIdsByChild($product->getId());

        if (isset($parentProductIds[0])) {

            $fatherProduct = $this->productFactory->create()->setStoreId($storeId)->load($parentProductIds[0]);

            if ($fatherProduct->getUrlKey() !== $fatherProduct->formatUrlKey($value)) {
                $this->setProductName($fatherProduct, $value, $storeId);
            }
        }

        $this->setProductName($product, $value, $storeId);
    }

    /**
     * @param $product
     * @param $name
     * @param $storeId
     * @throws Exception
     */
    protected function setProductName($product, $name, $storeId)
    {
        $urlKey = $product->formatUrlKey($name);
        $urlKey = $this->checkDuplicated($product, $urlKey, $storeId);

        $attributesData = ['name' => $name, 'url_key' => $urlKey];

        foreach($attributesData as $attrCode => $attrValue) {
            $product->addAttributeUpdate($attrCode, $attrValue, $storeId);
        }
        $product->setData('url_key', $urlKey);

        $urls = $this->productUrlRewriteGenerator->generate($product);

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

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

    /**
     * @param $product
     * @param $urlKey
     * @param $storeId
     * @return string
     */
    protected function checkDuplicated($product, $urlKey, $storeId)
    {

        $connection = $this->connection->getConnection();

        $productId = $product->getId();
        $entityField = $this->getEntityField();
        $attributeId = $this->_eavAttributeModel->getIdByCode('catalog_product', 'url_key');

        $table = $connection->getTableName('catalog_product_entity_varchar');

        if ($productId) {
            $result = $connection->fetchRow("SELECT * FROM {$table} WHERE `attribute_id` = ? AND `store_id` = ? AND `value` = ? AND `{$entityField}` <> ?", [
                $attributeId,
                $storeId,
                $urlKey,
                $productId
            ]);
        } else {
            $result = $connection->fetchRow("SELECT * FROM {$table} WHERE `attribute_id` = ? AND `store_id` = ? AND `value` = ?", [
                $attributeId,
                $storeId,
                $urlKey
            ]);

        }

        if (is_array($result)) {
            return "$urlKey-$productId";
        }

        return $urlKey;
    }

    /**
     * @return string
     */
    protected function getEntityField()
    {
        $edition = $this->_productMetadata->getEdition();
        return ($edition === 'Enterprise' || $edition === 'B2B') ? 'row_id' : 'entity_id';
    }

}

