<?php
declare(strict_types=1);

namespace FiloBlu\Refilo\Observer;

use Exception;
use Magento\Catalog\Api\Data\CategoryInterface;
use Magento\Catalog\Model\Category;
use Magento\Eav\Api\AttributeRepositoryInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Serialize\SerializerInterface;

/**
 * @class CategorySaveAfterObserverAvoidStoreviewDuplicate
 * @package FiloBlu\Refilo\Observer
 */
class CategorySaveAfterObserverAvoidStoreviewDuplicate implements ObserverInterface
{

    /** @var string */
    const EMOTIONAL_PRODUCTS_KEY = 'emotional_products';
    const CORE_CONFIG_DATA_TABLE = 'core_config_data';

    /** @var AttributeRepositoryInterface */
    protected $attributeRepository;

    /** @var ResourceConnection */
    protected $resourceConnection;

    /** @var MetadataPool */
    private $metadataPool;

    /** @var RequestInterface */
    private $request;

    /** @var SerializerInterface  */
    private $serializer;

    /**
     * @param AttributeRepositoryInterface $attributeRepository
     * @param ResourceConnection $resourceConnection
     * @param MetadataPool $metadataPool
     * @param RequestInterface $request
     * @param SerializerInterface $serializer
     */
    public function __construct(
        AttributeRepositoryInterface $attributeRepository,
        ResourceConnection           $resourceConnection,
        MetadataPool                 $metadataPool,
        RequestInterface             $request,
        SerializerInterface          $serializer
    ) {
        $this->attributeRepository = $attributeRepository;
        $this->resourceConnection = $resourceConnection;
        $this->metadataPool = $metadataPool;
        $this->request = $request;
        $this->serializer = $serializer;
    }

    /**
     * @param Observer $observer
     * @return void|null
     * @throws Exception
     */
    public function execute(Observer $observer)
    {
        $post = $this->request->getPost();
        if ($post['emotional_products'] == null || (int)$post['store_id'] == 0) {
            return;
        }

        try {
            $attributeId = $this->attributeRepository->get(
                Category::ENTITY,
                self::EMOTIONAL_PRODUCTS_KEY
            )->getAttributeId();
        } catch (NoSuchEntityException $noSuchEntityException) {
            return;
        }

        $linkField = $this->metadataPool->getMetadata(CategoryInterface::class)->getLinkField();
        $linkFieldId = $post[$linkField] ?? '';
        if (!isset($linkField, $linkFieldId, $attributeId)) {
            return;
        }

        $emotionalProductsDefault = $this->getEmotionalProductsDefault($linkField, (int)$linkFieldId, (int)$attributeId);
        $filteredEmotionalProducts = $this->filterEmotionalProductsData($post['emotional_products']);
        $emotionalProductsPost = $this->serializer->serialize($filteredEmotionalProducts);

        if ($emotionalProductsDefault !== $emotionalProductsPost) {
            return;
        }

        $storeId = $post['store_id'];
        try {
            $connection = $this->getConnection();
            $connection->delete('catalog_category_entity_text',
                [
                    "$linkField = ?" => $linkFieldId,
                    'attribute_id = ?' => $attributeId,
                    'store_id = ?' => $storeId
                ]
            );
        } catch (Exception $exception) {
            return;
        }
    }

    /**
     * @param string $linkField
     * @param int $linkFieldId
     * @param int $attributeId
     * @return string
     */
    public function getEmotionalProductsDefault(string $linkField, int $linkFieldId, int $attributeId)
    {
        $connection = $this->getConnection();
        $table = $connection->getTableName('catalog_category_entity_text');
        $select = $connection
            ->select()
            ->from($table, ['value'])
            ->where($linkField . " = ?", $linkFieldId)
            ->where('attribute_id = ?', $attributeId)
            ->where('store_id = ?', 0);

        return $this->getConnection()->fetchOne($select);
    }

    /**
     * @return AdapterInterface
     */
    protected function getConnection()
    {
        if (!isset($this->connection)) {
            $this->connection = $this->resourceConnection->getConnection();
        }

        return $this->connection;
    }

    /**
     * @param $emotionalProductsPost
     * @return array|array[]
     */
    public function filterEmotionalProductsData($emotionalProductsPost)
    {
        $filteredEmotionalProducts = [];
        $keyToRemove = ['ep_page', 'ep_position', 'ep_column_spacing', 'ep_row_spacing'];
        $filteredEmotionalProducts['emotional_products'] = array_map(function($item) use ($keyToRemove) {
            return array_intersect_key($item, array_flip($keyToRemove));
        }, $emotionalProductsPost['emotional_products']);

        return $filteredEmotionalProducts;
    }
}
