<?php

namespace FiloBlu\Flow\Model\Channel\In;

use Exception;
use FiloBlu\Flow\Helper\LoggerProvider;
use FiloBlu\Flow\Model\Channel\ConfigFactory;
use FiloBlu\Flow\Model\Manager\ProductImageManager;
use FiloBlu\Flow\Model\Videosflow;
use FiloBlu\Flow\Model\VideosflowFactory;
use Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface;
use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\ProductRepository;
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Collection;
use Magento\Framework\Api\Data\ImageContentInterface;
use Magento\Framework\Api\Data\ImageContentInterfaceFactory;
use Magento\Framework\Api\Data\VideoContentInterface;
use Magento\Framework\Api\ImageContentValidatorInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\ProductMetadataInterface;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DataObject;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\Event\Manager;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Exception\StateException;
use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\Directory\WriteInterface;
use Magento\Framework\Model\ResourceModel\Iterator;
use Magento\Framework\Model\ResourceModel\IteratorFactory;
use Magento\Framework\ObjectManagerInterface;
use Magento\MediaStorage\Model\File\Uploader;
use Magento\ProductVideo\Model\Product\Attribute\Media\ExternalVideoEntryConverter;
use Magento\Store\Model\StoreManagerInterface;
use Throwable;
use Zend_Db;
use Zend_Db_Expr;
use Zend_Db_Statement_Exception;

/**
 * Class Videos
 * @package FiloBlu\Flow\Model\Channel\In
 */
class Videos extends AbstractModel
{

    const IMAGE_DATA = 'iVBORw0KGgoAAAANSUhEUgAAASsAAACoCAMAAACPKThEAAAAe1BMVEUAAAC/v7/X19fd3d3f39+RkZHa2trh4eHW1tbCwsLFxcXLy8u4uLjS0tLl5eXOzs5tbW2qqqphYWGamppHR0d2dnZVVVU2NjaCgoIXFxdQUFAJCQksLCw+Pj6kpKQfHx8qKio7OzuAgICLi4tpaWkSEhKnp6cbGxvz8/Pg/xS6AAADiklEQVR4nO3b23LqOgwGYCIpsnNOoCmUYwulXe//hDusrt06kABXIVP/31Xd+EKjiTWyHSYTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALjf7mla1vX78/zRgYzcrtwWpCzGiJJND0+PDmi0lh/Kqiomb5jmT9Zk8fLoqMZombKSaLCtl2/r+WZ6SBOjxPbw6MBGZ7VlUgnKV/d/y1khlpPpo4Iap6eESarL8nSsCyGZPSCi0SqZTNBdyFcHJg4GjmfEakO86H36FgjHqwHDGbMmVbq8NmFrNB4qmHGbGspuNJ6hwTI8WRPx261JW2EU+MkkUnNHUxDQPbN+ub3w9nuw7p02Z5sNEc6YfZLNjt+jWdFbuBbC4SARjVeopnRGuelNSGL1c4iIRmtFNnGGoSZke+pSadTvrWHNUjvDkKIokXTXObfwvGKlpO6hS0hBEMSZ6XyBQuWrHesv9yKUuuO/uQqiRIuOrLzl6nOPNWUp3fFXrppsFaa6nJ1QNFRgIxRy3mqp/s9VsxAt1+ezK5XhQhudSovW+CdXzULk+Gzrs2feDBjcyETaKldurk4LMd+2ni4Ne7zPsdouS61cBVFM+u48XeeX69Ifou03p52r00I0zkJ8yaX/RPDXu5WrIKY/P33C0etcqX60xme5al6r1GlVd7nsBw5wRJJr9aopV+SWq8km51Y35pdU292lm6tmq3PWpr8bnzc5M+WjO/7JVdNeBecny83s1+FiG5s9m9ab8p2r2Mple5CSHSyy8dmwts72/uUqKuTjcvKRtWOT6I+MWhd/f3MVJZo8d8xtypXHreipBOXu1fwpV7E13V1UStJ9COiJJyF3tYUUF5J238fPz866/BOQOFc3oWjRtz3eqnStTI9MxS3Ysz+91w8bIe+v6VMyP69L2X+Z2lQrjxvRL6cL5Tu+CV0Y7WgjfLOXO9qmJVOBT7Amk4rPN34X5kqC77dPYr3xRejGkvH4hMG1itlUV9rMdybjdcfuWkWsWV9ftdsKUuWqxErVdaG1qjPVvs9BPLVXJa7OG/P1IhHLQX/X5ad5ykQmmU1f//UGn5t9qmw5w/q79NykhtRwnFZVlQZZ3ow4O+DHS502YULMp996NViUKnQKV8zLsIoKmyXpbPF8vD0fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL78BwNuIdnk18N/AAAAAElFTkSuQmCC';
    /**
     * @var string
     */
    const STATUS_RECEIVED = 'received';

    /**
     * @var string
     */
    const STATUS_PROCESSED = 'processed';

    /**
     * @var string
     */
    const STATUS_PARSED = 'parsed';

    /**
     * @var string
     */
    const STATUS_ERROR = 'error';

    /**
     * @var \FiloBlu\Flow\Helper\Videos
     */
    protected $_videosHelper;

    /**
     * @var ResourceConnection
     */
    protected $_resourceConnection;
    /**
     * @var AdapterInterface
     */
    protected $_connection;
    /**
     * @var ProductRepository
     */
    protected $_productRepository;
    /**
     * @var Filesystem
     */
    protected $_filesystem;
    /**
     * @var WriteInterface
     */
    protected $_mediaDirectory;
    /**
     * @var WriteInterface
     */
    protected $_varDirectory;

    /**
     * @var Product
     */
    protected $catalogModelProduct;
    /**
     * @var array
     */
    protected $_lookupAttributeSet = [];

    /**
     * @var
     */
    protected $channel_photo_config;
    /**
     * @var
     */
    protected $collection_of_videos_to_parse;
    /**
     * @var
     */
    protected $array_of_data_for_csv;
    /**
     * @var string
     */
    protected $filename_separator = '_';
    /**
     * @var string
     */
    protected $video_alt_separator = ' ';
    /**
     * @var Manager
     */
    protected $eventManager;

    /**
     * @var int
     */
    protected $_errorsProcessingVideos = 0;

    /**
     * @var int
     */
    protected $_videosToProcess = 0;

    /**
     * @var string
     */
    protected $unique_video_code_pattern = 'unq';

    /**
     * @var string
     */
    protected $cache_folder = BP . '/pub/media/catalog/product/cache/';

    /**
     * Product entity link field
     *
     * @var string
     */
    protected $productEntityLinkField;

    /**
     * @var VideosflowFactory
     */
    protected $_videosFlowFactory;

    /**
     * @var IteratorFactory
     */
    protected $iteratorFactory;

    /**
     * @var ProductMetadataInterface
     */
    protected $productMetadata;
    /**
     * @var string
     */
    protected $entityIdFieldName;
    /**
     * @var ImageContentInterface
     */
    private $imageContent;
    /**
     * @var ExternalVideoEntryConverter
     */
    private $externalVideoEntryConverter;
    /**
     * @var ImageContentValidatorInterface
     */
    private $contentValidator;
    /**
     * @var ImageContentInterfaceFactory
     */
    private $imageContentInterfaceFactory;
    /**
     * @var StoreManagerInterface
     */
    private $storeManager;
    

    /**
     * Videos constructor.
     * @param LoggerProvider $loggerProvider
     * @param ConfigFactory $channelConfigFactory
     * @param \FiloBlu\Flow\Helper\Videos $videosHelper
     * @param Manager $eventManager
     * @param ResourceConnection $resourceConnection
     * @param ProductRepository $productRepository
     * @param Filesystem $filesystem
     * @param Product $catalogModelProduct
     * @param VideosflowFactory $videosFlowFactory
     * @param IteratorFactory $iteratorFactory
     * @param ProductMetadataInterface $productMetadata
     * @param ObjectManagerInterface $objectManager
     * @param ImageContentInterface $imageContent
     * @param ExternalVideoEntryConverter $externalVideoEntryConverter
     * @param ImageContentValidatorInterface $contentValidator
     * @param ImageContentInterfaceFactory $imageContentInterfaceFactory
     * @param StoreManagerInterface $storeManager
     */
    public function __construct(
        LoggerProvider                 $loggerProvider,
        ConfigFactory                  $channelConfigFactory,
        \FiloBlu\Flow\Helper\Videos    $videosHelper,
        Manager                        $eventManager,
        ResourceConnection             $resourceConnection,
        ProductRepository              $productRepository,
        Filesystem                     $filesystem,
        Product                        $catalogModelProduct,
        VideosflowFactory              $videosFlowFactory,
        IteratorFactory                $iteratorFactory,
        ProductMetadataInterface       $productMetadata,
        ObjectManagerInterface         $objectManager,
        ImageContentInterface          $imageContent,
        ExternalVideoEntryConverter    $externalVideoEntryConverter,
        ImageContentValidatorInterface $contentValidator,
        ImageContentInterfaceFactory   $imageContentInterfaceFactory,
        StoreManagerInterface          $storeManager
    )
    {
        parent::__construct($loggerProvider, $channelConfigFactory, $objectManager);
        $this->_videosHelper = $videosHelper;
        $this->eventManager = $eventManager;
        $this->_resourceConnection = $resourceConnection;
        $this->_productRepository = $productRepository;
        $this->_filesystem = $filesystem;
        $this->_mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
        $this->_varDirectory = $filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
        $this->catalogModelProduct = $catalogModelProduct;
        $this->_videosFlowFactory = $videosFlowFactory;
        $this->iteratorFactory = $iteratorFactory;
        $this->productMetadata = $productMetadata;
        $this->loadLookupTables();
        $this->imageContent = $imageContent;
        $this->externalVideoEntryConverter = $externalVideoEntryConverter;
        $this->contentValidator = $contentValidator;
        $this->imageContentInterfaceFactory = $imageContentInterfaceFactory;
        $this->storeManager = $storeManager;
    }

    /**
     * Load the lookups tables to speed up the whole process
     */
    protected function loadLookupTables()
    {
        $stmt = $this->getConnection()->query('SELECT a.attribute_set_id, b.* FROM eav_attribute_set AS a LEFT JOIN eav_entity_type AS b ON b.entity_type_id = a.entity_type_id WHERE attribute_set_id IN ( SELECT DISTINCT attribute_set_id FROM catalog_product_entity )');

        $results = $stmt->fetchAll(Zend_Db::FETCH_OBJ);

        foreach ($results as $item) {
            $item->attributesSet = $this->getAttributeSet($item->entity_type_id);
            $this->_lookupAttributeSet[$item->attribute_set_id] = $item;
        }
    }

    /**
     * @return AdapterInterface
     */
    protected function getConnection()
    {
        if ($this->_connection) {
            return $this->_connection;
        }

        return ($this->_connection = $this->_resourceConnection->getConnection());
    }

    /**
     * Retrieve the attribute set available from the entity type
     *
     * @param $entity_type_id
     * @return array
     * @throws Zend_Db_Statement_Exception
     */
    protected function getAttributeSet($entity_type_id)
    {
        $attributeSet = [];

        $stmt = $this->getConnection()->query(
            'SELECT * FROM eav_attribute WHERE entity_type_id = ?',
            [$entity_type_id]
        );

        $results = $stmt->fetchAll(Zend_Db::FETCH_OBJ);

        foreach ($results as $item) {
            $attributeSet[$item->attribute_code] = $item;
        }

        return $attributeSet;
    }

    /**
     * @return int
     */
    public function getProcessedVideoErrorCount()
    {
        return $this->_errorsProcessingVideos;
    }

    /**
     * @return int
     */
    public function getVideoToProcessCount()
    {
        return $this->_videosToProcess;
    }

    /**
     * @param $file
     * @return bool
     */
    public function insertData($file)
    {
        $meta_file_id = $file->getId();

        /** @var Videosflow $model */
        $model = $this->_videosFlowFactory->create();

        $catalogProductEntity = $this->getConnection()->getTableName('catalog_product_entity');

        // Loading videos SKUs to process
        $collection = $model->getCollection();
        $collection->addFieldToSelect(['id', 'video_sku']);
        //$collection->addFieldToFilter('meta_processed', 0);
        $collection->addFieldToFilter('meta_file', $meta_file_id);
        $collection->addFieldToFilter('video_status', ['in' => [Videosflow::STATUS_PARSED, Videosflow::STATUS_ERROR]]);
        $collection->addFieldToFilter('video_sku', ['in' => new Zend_Db_Expr("SELECT sku FROM `{$catalogProductEntity}`")]);
        //$collection->getSelect()->group('image_sku');
        $collection->load();

        $this->_videosToProcess = $collection->count();

        /** @var Iterator $iterator */
        $iterator = $this->iteratorFactory->create();
        $iterator->walk($collection->getSelect(), [[$this, 'fastVideoProcess']], ['meta_file_id' => $meta_file_id]);

        return !($this->_errorsProcessingVideos > 0);
    }

    /**
     * Process video import directly query the db layer
     * @param $args
     * @return bool
     * @throws Zend_Db_Statement_Exception
     */
    public function fastVideoProcess($args)
    {

        // TODO : find best place
        /** @var ProductImageManager $imageManager */
        $imageManager = $this->objectManager->get(ProductImageManager::class);

        $entityIdFieldName = $this->getEntityField();

        /* Where Magento 2 looks for images */
        $catalogRootDirectory = $this->_mediaDirectory->getAbsolutePath();

        /* Retieve sku */
        $sku = $args['row']['video_sku'];
        $meta_file_id = $args['meta_file_id'];

        /* Find product by sku */

        $results = $this->getConnection()->query('SELECT * FROM catalog_product_entity WHERE sku = ?', [$sku]);

        $product = $results->fetch(Zend_Db::FETCH_OBJ);

        if ($product === null || $product === false) {
            $this->_logger->error("Unable to find product with SKU {$sku}");
            $this->_errorsProcessingVideos++;
            return true;
        }

        /* TODO : use direct query instead. See https://blackfire.io/profiles/0b7ca6a2-ac40-41c1-b41d-1bfee4e7a8ac/graph*/

        /* Find incoming product images */

        $model = $this->_videosFlowFactory->create();

        $collection = $model->getCollection();
        // $collection->addFieldToFilter('meta_processed', 0);
        $collection->addFieldToFilter('meta_file', $meta_file_id);
        $collection->addFieldToFilter('video_status', ['in' => [Videosflow::STATUS_PARSED, Videosflow::STATUS_ERROR]]);
        $collection->addFieldToFilter('video_sku', $sku);
        //$collection->setOrder('image_position', 'ASC');
        $collection->load();

        $incomingVideos = [];
        foreach ($collection as $videoFlow) {
            $incomingVideos[Uploader::getCorrectFileName($videoFlow->getVideoName())] = $videoFlow;
        }

        $id = (int)$product->attribute_set_id;
        $attributeSet = $this->_lookupAttributeSet[$id];

        $mediaGaleryAttribute = $attributeSet->attributesSet['media_gallery'];
        $mediaGaleryAttributeId = $mediaGaleryAttribute->attribute_id;

        /* Fix $catalogRootDirectory */

        $catalogRootDirectory .= str_replace('_', DIRECTORY_SEPARATOR, $attributeSet->entity_type_code);

        /* Find existing videos in gallery */
        $existingVideos = $this->getProductGalleryBySku($sku, $mediaGaleryAttributeId);

        foreach ($incomingVideos as $name => $videoFlow) {
            try {
                $relativePath = Uploader::getDispretionPath($name) . DIRECTORY_SEPARATOR . $name;
                $to = $catalogRootDirectory . $relativePath;
                $from = $this->getImportVideoPath($videoFlow);

                $folder = dirname($to) . DIRECTORY_SEPARATOR;

                if (false === is_dir($folder)) {
                    if (mkdir($folder, 0777, true) || is_dir($folder)) {
                        $this->_logger->error("Unable to create directory {$folder}");
                        $this->setProcecessedStatus($videoFlow, Videosflow::STATUS_ERROR, "Unable to create directory {$folder}");
                        $this->_errorsProcessingVideos++;
                        return true;
                    }
                }

                if (false === copy($from, $to)) {
                    $this->setProcecessedStatus($videoFlow, Videosflow::STATUS_ERROR, "Unable to move {$from} -> {$to}");
                    $this->_errorsProcessingVideos++;
                    continue;
                }

                /* ADD OR UPDATE VIDEO ENTRY */
                $this->addVideoToGallery($relativePath, $product, $mediaGaleryAttributeId, $videoFlow);

                try {
                    $imageManager->cleanCache($name);
                } catch (Throwable $throwable) {
                    $this->_logger->error($throwable->getMessage());
                }

                $this->setProcecessedStatus($videoFlow, Videosflow::STATUS_PROCESSED);
            } catch (Exception $e) {
                $this->_logger->info("Importing video {$name} for product with SKU {$sku} failed. : " . $e->getMessage() . PHP_EOL . $e->getTraceAsString());
                $this->setProcecessedStatus($videoFlow, Videosflow::STATUS_ERROR, $e->getMessage());
                $this->_errorsProcessingVideos++;
            }
        }

        return true;
    }

    /**
     * @return string
     */
    protected function getEntityField()
    {
        if ($this->entityIdFieldName) {
            return $this->entityIdFieldName;
        }

        $edition = $this->productMetadata->getEdition();
        $this->entityIdFieldName = ($edition === 'Enterprise' || $edition === 'B2B') ? 'row_id' : 'entity_id';

        return $this->entityIdFieldName;
    }

    /**
     * Retrieve the whole gallery for the given product sku
     * @param $sku
     * @param $media_gallery_attribute_id
     *
     * @return array
     * @throws Zend_Db_Statement_Exception
     */
    protected function getProductGalleryBySku($sku, $media_gallery_attribute_id)
    {
        $gallery = [];
        $entityIdFieldName = $this->getEntityField();

        $results = $this->getConnection()->query(
            "SELECT CPEMGON.*, CPEMGVTE.{$entityIdFieldName} FROM catalog_product_entity AS CPE
             LEFT JOIN catalog_product_entity_media_gallery_value_to_entity AS CPEMGVTE ON CPE.{$entityIdFieldName} = CPEMGVTE.{$entityIdFieldName}
             LEFT JOIN catalog_product_entity_media_gallery AS CPEMGON ON CPEMGVTE.value_id = CPEMGON.value_id
             WHERE CPE.sku = ? AND CPEMGON.attribute_id = ?",
            [$sku, $media_gallery_attribute_id]
        );

        $images = $results->fetchAll(Zend_Db::FETCH_OBJ);

        foreach ($images as $image) {
            /* Remove the dispersion prefix */
            $gallery[basename($image->value)] = $image;
        }

        return $gallery;
    }

    /**
     * @param Videosflow $videosflow
     * @return string
     */
    protected function getImportVideoPath(Videosflow $videosflow)
    {
        return $this->_varDirectory->getAbsolutePath() . DIRECTORY_SEPARATOR . $videosflow->getVideoPath() . DIRECTORY_SEPARATOR . $videosflow->getVideoName();
    }

    /**
     * @param Videosflow $video
     * @param string $status
     * @param string $reason
     */
    protected function setProcecessedStatus(Videosflow $video, $status = Videosflow::STATUS_PROCESSED, $reason = null)
    {
        $connection = $this->getConnection();
        $connection->update(
            $connection->getTableName('flow_videosflow'),
            [
                'video_process_time' => date('Y-m-d H:i:s'),
                'meta_processed'     => 1,
                'video_status'       => $status,
                'log'                => $reason
            ],
            $connection->quoteInto('id = ?', $video->getId())
        );
    }

    /**
     * @param $value
     * @param $product
     * @param $attribute_id
     * @param Videosflow $videoFlow
     * @throws InputException
     * @throws CouldNotSaveException
     * @throws LocalizedException
     * @throws NoSuchEntityException
     * @throws StateException
     */
    protected function addVideoToGallery($value, $product, $attribute_id, Videosflow $videoFlow)
    {
        $productArray = json_decode(json_encode($product), true);
        $productSku = $productArray['sku'];
        $productInstance = $this->_productRepository->get($productSku);
        $videoUrl = '/' . $this->storeManager->getStore()->getBaseMediaDir() . '/catalog/product' . $value;
        $videoUrl = str_replace("/pub", "", $videoUrl);
        //set thumbnail image

        /** @var ImageContentInterface $imageContent */
        $imageContent = $this->imageContentInterfaceFactory->create();
        $separator = $this->getVideoSeparator();

        $imageContent->setName($videoFlow->getVideoSku() . $separator . 'thumbnail.png')
            ->setType('image/png')
            ->setBase64EncodedData(self::IMAGE_DATA);


        // Build video data array for video entry converter
        $generalMediaEntryData = [
            ProductAttributeMediaGalleryEntryInterface::LABEL    => $videoFlow->getVideoSku() . '_video',
            ProductAttributeMediaGalleryEntryInterface::CONTENT  => $this->getThumbnailImageContent($videoFlow->getVideoSku(),$separator),
            ProductAttributeMediaGalleryEntryInterface::DISABLED => false,
            ProductAttributeMediaGalleryEntryInterface::TYPES    => []
        ];
        $videoData = array_merge($generalMediaEntryData, [
            VideoContentInterface::TITLE       => $videoFlow->getVideoSku() . ' video',
            VideoContentInterface::DESCRIPTION => 'Product Video',
            VideoContentInterface::PROVIDER    => 'custom',
            VideoContentInterface::METADATA    => null,
            VideoContentInterface::URL         => $videoUrl,
            VideoContentInterface::TYPE        => ExternalVideoEntryConverter::MEDIA_TYPE_CODE
        ]);

        $videoEntry = $this->externalVideoEntryConverter->convertTo($productInstance, $videoData);
        $videoEntry->setPosition($videoFlow->getVideoPosition());
        /** @var $entryContent ProductAttributeMediaGalleryEntryInterface */
        $entryContent = $videoEntry->getContent();
        if (!$this->contentValidator->isValid($entryContent)) {
            throw new InputException(__('The video image content is not valid.'));
        }

        $existingMediaGalleryEntries = $productInstance->getMediaGalleryEntries();
        $updated = false;

        // insert video into mediaGallery and shift
        // existing media according to video position
        $newMediaGallery = [];
        if ($existingMediaGalleryEntries == null) {
            $newMediaGallery = [$videoEntry];
        } else {
            foreach ($existingMediaGalleryEntries as $existingEntries) {
                if (!$updated && ($videoFlow->getVideoPosition() < $existingEntries->getPosition())) {
                    $updated = true;
                    $newMediaGallery[] = $videoEntry;
                }
                $newMediaGallery[] = $existingEntries;
                if (!$updated && ($videoFlow->getVideoPosition() == $existingEntries->getPosition())) {
                    $updated = true;
                    $newMediaGallery[] = $videoEntry;
                }
            }
            if (!$updated) {
                $newMediaGallery [] = $videoEntry;
            }
            //sort mediaGallery
            $pos = 0;
            foreach ($newMediaGallery as $existingEntries) {
                $existingEntries->setPosition($pos);
                $pos++;
            }
            $this->clearPreviousMedia($existingMediaGalleryEntries);
        }

        $productInstance->setMediaGalleryEntries($newMediaGallery);

        $this->_productRepository->save($productInstance);

        //Pezzotto
        $this->updateVideoInGalleryValues($productSku);
        //fine
    }

    
    /**
     * @param string $sku
     * @return ImageContentInterface
     */
    public function getThumbnailImageContent($sku,$separator)
    {
        /** @var ImageContentInterface $imageContent */
        $imageContent = $this->imageContentInterfaceFactory->create();
        $imageContent
            ->setName($sku . $separator . "thumbnail.png")
            ->setType('image/png')
            ->setBase64EncodedData(self::IMAGE_DATA);

        return $imageContent;
    }

    /**
     * @param $file
     * @return bool
     * @throws Exception
     */
    public function receiveFile($file)
    {
        if (!$this->_connector) {
            throw new Exception('no connector joined to channel');
        }

        $meta_file_id = $file->getId();

        $local_dir = $this->_connector->getLocalDir() . '/' . $meta_file_id;

        $this->_connector->setLocalDir($local_dir);

        $model = $this->_videosFlowFactory->create();

        $collection = $model->getCollection();
        $collection->addFieldToFilter('meta_processed', 0);
        $collection->addFieldToFilter('meta_file', $meta_file_id);
        $collection->addFieldToFilter('video_status', 'found');
        $collection->addFieldToFilter('video_queue_time', ['notnull' => true]);
        $collection->load();

        $result = true;

        foreach ($collection as $video) {
            try {

                // Is unique filename enabled?

                $unique_filename_pattern = "_{$this->unique_video_code_pattern}" . $video->getId();

                $received = $this->_connector->receiveResource($video->getData('video_name'), null, FTP_BINARY, true, $unique_filename_pattern);
                if ($received) {
                    $video->setData('video_receive_time', date('Y-m-d H:i:s'));
                    $video->setData('video_status', 'received');
                    if ($video->getData('video_name') !== $received) {
                        $log = $video->getData('log');
                        $log = trim("Video name fixed from '" . $video->getData('video_name') . "' to '{$received}'" . $log . "\n");
                        $video->setData('log', $log);
                        $video->setData('video_name', $received);
                    }
                    $video->save();
                } else {
                    $video->setData('video_status', 'found');
                    $log = $video->getData('log');
                    $log .= "Video not received\n";
                    $video->setData('log', $log);
                    $video->save();
                    $result = false;
                }
            } catch (Exception $e) {
                $log = $video->getData('log');
                $log .= $e->getMessage() . "\n";
                $video->setData('log', $log);
                $video->save();
                $result = false;
                //$this->_logger->log('FTP',$e->getMessage());
            }
        }

        //Can't close the connection or the next cycle will fail
        //$this->_connector->close();

        return $result;
    }

    /**
     * @param $file
     * @return bool
     * @throws Exception
     */
    public function parse($file)
    {
        if (!$this->_connector) {
            throw new Exception('no connector joined to channel');
        }

        $meta_file_id = $file->getId();

        //$local_dir = $this->_connector->getLocalDir().DIRECTORY_SEPARATOR.$meta_file_id;
        //$this->_connector->setLocalDir($local_dir);

        $channel_config = $this->_connector->getConfig();
        $local_dir = $channel_config['local_dir'] . DIRECTORY_SEPARATOR . $meta_file_id;

        //$this->directoryList->getPath('var');

        $csv_filename = $file->getName();
        $channel_name = $file->getChannel();
        $this->loadVideoChannelConfig($channel_name);
        $this->filename_separator = $this->getVideoSeparator();

        if (!$this->channel_photo_config) {
            throw new Exception('Wrong Video configuration');
        }

        $this->loadVideosListToParse($meta_file_id);

        foreach ($this->collection_of_videos_to_parse as $data) {
            $video_filename = $data->getVideoName();
            //  $image_filename_no_ext = $this->removeExtensionFromFilename($image_filename);
            $loaded_data = $this->loadDataBasedOnFilename($video_filename, $channel_name);

            if ($loaded_data['sku'] && count($loaded_data) > 0 && $this->productExists($loaded_data['sku'])) {
                $data->setData('video_sku', $loaded_data['sku']);

                //Handling not numeric "L1", "L2", "L3", "L4" special positions (pattern inside filename)
                //Giving custom high order (order is mandatory, numeric and unique)

                switch ($loaded_data['position']) {
                    case 'l1':
                    case 'L1':
                        $loaded_data['position'] = 999;
                        break;
                    case 'l2':
                    case 'L2':
                        $loaded_data['position'] = 998;
                        break;
                    case 'l3':
                    case 'L3':
                        $loaded_data['position'] = 997;
                        break;
                    case 'l4':
                    case 'L4':
                        $loaded_data['position'] = 996;
                        break;
                    default:
                        #nothing to do
                }

                $data->setData('video_position', (int)$loaded_data['position']);

                if (isset($loaded_data['alt']) && $loaded_data['alt']) {
                    $data->setData('video_alt', $loaded_data['alt']);
                }

                $data->setData('video_type', implode('|', array_unique($loaded_data['video_type'])));
                $data->setData('video_hide', $loaded_data['video_hide']);
                $data->setData('video_path', $local_dir);
                $data->setData('video_status', 'parsed');
                $data->save();
            } else {
                $data->setData('video_status', 'error');
                $data->save();
                $log = $file->getData('log');
                $log .= "Can't parse video filename {$video_filename} or SKU does not exists, wrong format! {$csv_filename}\n";
                $file->setData('log', $log);
                $file->save();
                continue;
            }
        }

        // Handling replicate images for same simple products
        $duplicate_video_super_attribute = 0;

        if (!empty($duplicate_video_super_attribute)) {

            // Reload Images
            $model = $this->_videFlowFactory->create();

            $collection = $model->getCollection();
            $collection->addFieldToFilter('meta_processed', 0);
            $collection->addFieldToFilter('meta_file', $meta_file_id);
            $collection->addFieldToFilter('video_status', 'parsed');
            $collection->load();

            // Rerunning the same collection
            foreach ($collection as $data) {
                if ($data->getData('video_status') === self::STATUS_PARSED) {
                    try {

                        /* TODO :  just a workaround */

                        $position = (int)$this->getFieldPosition($duplicate_video_super_attribute);
                        $image_filename_no_ext = $this->removeExtensionFromFilename($data->getImageName());
                        $filename_exploded = explode($this->filename_separator, $image_filename_no_ext);
                        $sku = $filename_exploded[$this->getFieldPosition('sku')];

                        //  $loaded_data = $this->loadDataBasedOnFilename($data->getImageName(), $channel_name);

                        /* END */

                        $sku_childs_array = $this->getSimpleFromConfigurableHavingAttribute($sku, $duplicate_video_super_attribute, $filename_exploded[$position]);

                        if ($sku_childs_array === false) {
                            continue;
                        }

                        if (isset($filename_exploded[$this->getFieldPosition('default')])) {
                            $data->setData('video_sku', $sku);
                            $data->setData('log', 'Video set as default');
                            $data->save();
                        }

                        // $sku_childs_array = $this->_imagesHelper->getAllChildsOfParentWithSameAttribute($data->getData('image_sku'), $duplicate_image_super_attribute);
                        // if (count($sku_childs_array) > 0) {
                        // For each children replicating the same image to be processed but on a different SKU

                        foreach ($sku_childs_array as $child_sku) {
                            $data->unsetData('id');
                            $data->setData('video_sku', $child_sku);
                            $data->setData('log', 'Video replicated');
                            $data->save();
                        }

                        // }
                    } catch (Exception $exception) {
                        $this->_logger->error('An error occurred while expanding: ' . $exception->getMessage());
                    }
                }
            }
        }

        return true;
    }

    /**
     * @param $channel_name
     */
    protected function loadVideoChannelConfig($channel_name)
    {
        $this->channel_photo_config = null;
        if ($this->_parser->loadMap($channel_name)) {
            $config_mapping = $this->_parser->map->getFullMappedData();
            $this->channel_photo_config = $config_mapping;
        }
    }

    /**
     * @return string
     */
    protected function getVideoSeparator()
    {
        $config = $this->getChannelConfig()->getConfigData();
        $separator = '_';
        
        if (isset($config['map']['options']['separator'])) {
            $separator = trim($config['map']['options']['separator']);
        }
        return $separator;
    }

    /**
     * @param $file_id
     */
    protected function loadVideosListToParse($file_id)
    {
        $model = $this->_videosFlowFactory->create();

        $collection = $model->getCollection();
        $collection->addFieldToFilter('meta_processed', 0);
        $collection->addFieldToFilter('meta_file', $file_id);
        $collection->addFieldToFilter('video_status', 'received');
        $collection->load();

        $this->collection_of_videos_to_parse = $collection;
    }

    /**
     * @param $video_filename
     * @param null $channel_name
     * @return mixed
     * @throws Exception
     */
    protected function loadDataBasedOnFilename($video_filename, $channel_name = null)
    {
        $alt = [];
        $original_filename = $video_filename;

        // Remove extension
        $video_filename = $this->removeExtensionFromFilename($video_filename);

        $filename_exploded = explode($this->filename_separator, $video_filename);

        $sku_position = $this->getSkuFilenamePosition();

        $sku = $filename_exploded[$sku_position] ?? '_unknown_';

        $video_position_position = $this->GetVideoPositionPosition();

        $position = $filename_exploded[$video_position_position] ?? 1;

        $video_alt_positions = $this->GetVideoAltPositions();

        if (count($video_alt_positions) > 0) {
            foreach ($video_alt_positions as $pos) {
                // If ALT of image is equal to $this->unique_image_code_pattern then we have an error in the naming and
                // we need to skip that ALT value

                if (isset($filename_exploded[$pos]) && strpos($filename_exploded[$pos], $this->unique_video_code_pattern) !== 0) {
                    $alt[] = $filename_exploded[$pos];
                }
            }
            if (count($alt) > 0) {
                $alt = implode($this->video_alt_separator, $alt);
            }
        }

        if (empty($alt)) {
            $alt = '';
        }

        if (false !== ($defaultListing = $this->getFieldPosition('default', false)) && isset($filename_exploded[$defaultListing])) {
            $video_type = $this->getVideoType($filename_exploded[$defaultListing]);
        } else {
            $video_type = $this->getVideoType($position);
        }

        $video_type = array_merge($video_type, $this->getVideoType($position));

        $video_hide = $this->getVideoHide($position);

        $this->array_of_data_for_csv[$sku][$position]['filename'] = $original_filename;
        $this->array_of_data_for_csv[$sku][$position]['path'] = $this->_connector->getLocalDir();
        $this->array_of_data_for_csv[$sku][$position]['position'] = $position;
        if ($alt) {
            $this->array_of_data_for_csv[$sku][$position]['alt'] = $alt;
        }
        $this->array_of_data_for_csv[$sku][$position]['video_type'] = $video_type;
        $this->array_of_data_for_csv[$sku][$position]['video_hide'] = $video_hide;
        $this->array_of_data_for_csv[$sku][$position]['sku'] = $sku;

        // Start dispatch event to handle change of this data if needed
        $event_dispatch_data = new DataObject();
        $event_dispatch_data->setData('channel_name', $channel_name);
        $event_dispatch_data->setData('video_filename', $original_filename);
        $event_dispatch_data->setData('video_filename_noext', $video_filename);
        $event_dispatch_data->setData('filename_separator', $this->filename_separator);
        $event_dispatch_data->setData('channel_mapping', $this->channel_photo_config);
        $event_dispatch_data->setData('loaded_data', $this->array_of_data_for_csv[$sku][$position]);
        $this->eventManager->dispatch('flow_video_parse_load_data_based_on_filename_after', ['event_dispatch_data' => $event_dispatch_data]);
        // If the value is changed then it will be updated here
        $this->array_of_data_for_csv[$sku][$position] = $event_dispatch_data->getData('loaded_data');
        // End dispatch event, the data may have been changed here

        return $this->array_of_data_for_csv[$sku][$position];
    }

    /**
     * @param $string
     * @return bool|string
     */
    public function removeExtensionFromFilename($string)
    {
        $p = strrpos($string, '.');
        if ($p !== false) {
            $string = substr($string, 0, $p);
        }

        return $string;
    }

    /**
     * @return int|string
     */
    protected function getSkuFilenamePosition()
    {
        $config = $this->channel_photo_config;
        foreach ($config['fields'] as $key => $value) {
            if ($value['type'] === 'sku') {
                return $key;
            }
        }

        //Handle error missing SKU on config here, block all flow
    }

    /**
     * @return int|string
     */
    protected function GetVideoPositionPosition()
    {
        $config = $this->channel_photo_config;
        foreach ($config['fields'] as $key => $value) {
            if ($value['type'] === 'position') {
                return $key;
            }
        }

        //Handle error missing SKU on config here, block all flow
    }

    /**
     * @return array
     */
    protected function GetVideoAltPositions()
    {
        $config = $this->channel_photo_config;
        $positions = [];
        foreach ($config['fields'] as $key => $value) {
            if ($value['type'] === 'alt') {
                $positions[] = $key;
            }
        }

        return $positions;

        //Handle error missing SKU on config here, block all flow
    }

    /**
     * @param $fieldName
     * @param bool $throw | integer
     * @return bool|int|string
     * @throws Exception
     */
    protected function getFieldPosition($fieldName, $throw = true)
    {
        $config = $this->channel_photo_config;
        foreach ($config['fields'] as $key => $value) {
            if ($value['type'] === $fieldName) {
                return $key;
            }
        }

        if ($throw) {
            throw new Exception("Mapped field '{$fieldName}' does not exist in channel map");
        }

        return false;
    }

    /**
     * This will look into the json config of the video channels
     * searching which type of video is, based on the $position key inside the "types" node of the json
     *
     * @param $position
     *
     * @return array
     */
    protected function getVideoType($position)
    {
        $position = trim($position);

        $config = $this->channel_photo_config;

        if (isset($config['types'][$position]['type'])) {
            return $config['types'][$position]['type'];
        }

        // Check if position is a number (can also be a string)
        // If is a number handle it as a number
        // This will handle positions as "001" "01" "1" (usually human errors)
        if ((int)$position > 0 && isset($config['types'][(int)$position]['type'])) {
            return $config['types'][(int)$position]['type'];
        }

        // Check again if maybe we have uppercases (usually human errors)
        $position = strtolower($position);
        return $config['types'][$position]['type'] ?? [];
    }

    /**
     * @param $position
     * @return int
     */
    protected function getVideoHide($position)
    {
        $config = $this->channel_photo_config;

        if (isset($config['types'][$position]['hide']) && $config['types'][$position]['hide'] == 'true') {
            return 1;
        }

        return 0;
    }

    /**
     * @param string $sku
     * @return bool
     */
    public function productExists($sku)
    {
        if ($this->catalogModelProduct->getIdBySku($sku)) {
            return true;
        }
        return false;
    }

    /**
     * @param $sku
     * @param $attributeId
     * @param $attributeValue
     * @return array|bool
     * @throws Exception
     */
    protected function getSimpleFromConfigurableHavingAttribute($sku, $attributeId, $attributeValue)
    {
        $connection = $this->getConnection();
        $entityIdFieldName = $this->getEntityField();

        $catalog = $connection->getTableName('catalog_product_entity');
        $superAttributesTable = $connection->getTableName('catalog_product_super_attribute');
        $eavAttributeTable = $connection->getTableName('eav_attribute');
        $eavAttributeOptionTable = $connection->getTableName('eav_attribute_option');
        $eavAttributeOptionValueTable = $connection->getTableName('eav_attribute_option_value');

        $superLinkTable = $connection->getTableName('catalog_product_super_link');

        /* 1] Find the configurable row_id */

        $configurables = $connection->fetchAll("SELECT {$entityIdFieldName} FROM {$catalog} WHERE sku = ? AND type_id = ?", [$sku, 'configurable'], Zend_Db::FETCH_OBJ);

        if (empty($configurables)) {
            return false;
        }

        $output = [];

        foreach ($configurables as $configurable) {
            $configurableId = $configurable->{$entityIdFieldName};

            /* 2] List super attributes */

            $superAttributes = [];
            $simpleIds = [];

            $attributes = $connection->fetchAll(
                "SELECT EA.attribute_id,EA.backend_type,EA.attribute_code
FROM {$superAttributesTable} AS CPSA
LEFT JOIN {$eavAttributeTable} AS EA ON EA.attribute_id = CPSA.attribute_id
WHERE CPSA.product_id = ?",
                [$configurableId],
                Zend_Db::FETCH_OBJ
            );

            foreach ($attributes as $attribute) {
                $superAttributes[] = $attribute->attribute_id;
            }

            /* 3] Find childs */

            $simples = $connection->fetchAll("SELECT {$entityIdFieldName}  FROM {$superLinkTable} AS CPSL LEFT JOIN {$catalog} AS CPE ON CPSL.product_id = CPE.entity_id WHERE CPSL.parent_id = ?", [$configurableId], Zend_Db::FETCH_OBJ);

            foreach ($simples as $simple) {
                $simpleIds[] = $simple->{$entityIdFieldName};
            }

            /* 4] Find childs matching attribute value */

            $sqlAttributesIds = implode(',', $superAttributes);
            $sqlSimpleIds = implode(',', $simpleIds);

            /**
             *
             * value_id |attribute_id |store_id |row_id |value |sku            |
             * ---------|-------------|---------|-------|------|---------------|
             * 6516450  |93           |0        |41888  |233   |BSC6A85ECG80TU |
             *
             */
            $sql = "SELECT CPEAV.{$entityIdFieldName}, CPEAV.attribute_id, CPE.sku
FROM catalog_product_entity_int AS CPEAV
LEFT JOIN {$catalog} AS CPE ON CPEAV.{$entityIdFieldName} = CPE.{$entityIdFieldName}
WHERE CPEAV.attribute_id IN ({$sqlAttributesIds}) AND CPEAV.`value` IN
(
    SELECT EAO.option_id FROM {$eavAttributeOptionTable} AS EAO
    LEFT JOIN {$eavAttributeOptionValueTable} AS EAOV ON EAOV.option_id = EAO.option_id
    WHERE EAO.attribute_id IN ({$sqlAttributesIds}) AND (EAOV.`value` = ?)
)
AND CPEAV.{$entityIdFieldName} IN ({$sqlSimpleIds})";

            $matchedSimpleProducts = $connection->fetchAll($sql, [$attributeValue], Zend_Db::FETCH_OBJ);

            /* 5] check that matched simple products are all with same same attribute */
            $currentAttributeId = null;

            foreach ($matchedSimpleProducts as $simpleProduct) {
                $output[] = $simpleProduct->sku;
                if ($currentAttributeId === null) {
                    $currentAttributeId = $simpleProduct->attribute_id;
                    continue;
                }

                if ($currentAttributeId !== $simpleProduct->attribute_id) {
                    throw new Exception("The configurable product with sku '{$sku}' has simple products ({$sqlSimpleIds}) with the same attribute value '{$attributeValue}' for attributes with id ({$sqlAttributesIds}). Unable to resolve the ambiguity.");
                }
            }
        }

        return $output;
    }

    /**
     * @return array
     */
    public function getAllCacheVideoMainPaths()
    {
        // Give me an array of all the folders inside the cache folder
        // Going deep 3
        $image_cache_paths_array = $this->_videosHelper->foldersMap($this->cache_folder, 3);

        // Transform the array paths into string path checking also the md5 of the last folder
        $array_of_builded_paths = [];
        $this->_videosHelper->collapse('', $image_cache_paths_array, $array_of_builded_paths);

        return $array_of_builded_paths;
    }

    /*
     * $filename is column 'value' from 'catalog_product_entity_media_gallery'
     */

    /**
     * @param $row_id
     * @param $value_id
     * @param Videosflow $videoFlow
     */
    protected function updateGalleryValues($row_id, $value_id, Videosflow $videoFlow)
    {
        $entityIdFieldName = $this->getEntityField();
        $connection = $this->getConnection();

        $valueTable = $connection->getTableName('catalog_product_entity_media_gallery_value');

        $where = $connection->quoteInto("value_id = ? AND {$entityIdFieldName} = ?", $value_id, $row_id);

        $connection->update(
            $valueTable,
            [
                'store_id' => 0,
                'label'    => $videoFlow->getVideoAlt(),
                'position' => $videoFlow->getVideoPosition(),
                'disabled' => $videoFlow->getVideoHide()
            ],
            $where
        );
    }

    /**
     *
     *
     * --  ________                          _____ _____
     * --  ___  __ \_____ __________________ __  /___  /_______
     * --  __  /_/ /_  _ \___  /___  /_  __ \_  __/_  __/_  __ \
     * --  _  ____/ /  __/__  /___  /_/ /_/ // /_  / /_  / /_/ /
     * --  /_/      \___/ _____/_____/\____/ \__/  \__/  \____/
     * --
     * Verifiche postume - I video devono stare negli store aventi store_id = 0 e senza /pub nell'url
     * @param $sku
     * @param Videosflow $videoFlow
     */
    protected function updateVideoInGalleryValues($sku)
    {
        $connection = $this->getConnection();

        $results = $this->getConnection()->query(
            "SELECT CPEMGV.row_id, CPEMGV.value_id, CPEMGV.store_id, CPEMGV.record_id from catalog_product_entity AS CPE
             LEFT JOIN catalog_product_entity_media_gallery_value AS CPEMGV ON CPEMGV.row_id=CPE.row_id
             where CPE.sku=? and CPEMGV.store_id!=0",
            [$sku]
        );

        $rows = $results->fetchAll(Zend_Db::FETCH_ASSOC);

        if($rows!=null && count($rows)>0){
            foreach ($rows as $row){
                $row_id = $row['row_id'];
                $value_id = $row['value_id'];

                $valueTable = $connection->getTableName('catalog_product_entity_media_gallery_value');
                $where = $connection->quoteInto("value_id = {$value_id} AND row_id = ? AND store_id!=0", $row_id);
                $connection->update(
                    $valueTable,
                    [
                        'store_id' => 0
                    ],
                    $where
                );

                $results = $this->getConnection()->query(
                    "SELECT CPEMGV.url from catalog_product_entity_media_gallery_value_video AS CPEMGV
                 where CPEMGV.value_id=?",
                    [$value_id]
                );
                $rows = $results->fetchAll(Zend_Db::FETCH_ASSOC);
                if(count($rows)===1){
                    $url = null;
                    foreach ($rows as $row){
                        $url = $row['url'];
                    }
                    if($url!=null && strpos($url, '/pub')===0){
                        $url = substr($url, 4);
                    }

                    $videoTable = $connection->getTableName('catalog_product_entity_media_gallery_value_video');
                    $where = $connection->quoteInto('value_id = ? AND store_id!=0', $value_id);
                    $connection->update(
                        $videoTable,
                        [
                            'store_id' => 0,
                            'url'      => $url
                        ],
                        $where
                    );
                }
            }
        }
    }

    /**
     * Update attributes. Allowed attributes to be set are defined in @param $row_id
     * @param $value
     * @param Videosflow $videoFlow
     * @param array $attributesSet
     * @throws Zend_Db_Statement_Exception
     * @see \FiloBlu\Flow\Model\Channel\In\Images::$_imageAttributeCodes
     *
     */
    protected function updateAttributes($row_id, $value, Videosflow $videoFlow, array $attributesSet)
    {
        $entityIdFieldName = $this->getEntityField();
        $connection = $this->getConnection();

        $assignableAttributes = explode('|', $videoFlow->getVideoType());

        if (empty($assignableAttributes)) {
            return;
        }

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

        $attributeIds = [];
        $toUpdate = [];
        $lookup = [];

        foreach ($assignableAttributes as $attributeCode) {
            if (!isset($attributesSet[$attributeCode])) {
                continue;
            }

            $id = $attributesSet[$attributeCode]->attribute_id;
            $attributeIds[] = (int)$id;
            $lookup[$id] = $attributeCode;
        }

        $stmt = $connection->query(
            $this->_connection
                ->select()
                ->from($attributesTable)
                ->where("{$entityIdFieldName} = ?", $row_id)
                ->where('store_id = ?', 0)
                ->where('attribute_id IN (?)', $attributeIds)
        );

        $existingAttributes = $stmt->fetchAll(Zend_Db::FETCH_OBJ);

        /* Find attributes to update and attributes to insert */

        foreach ($existingAttributes as $attribute) {
            $id = $attribute->attribute_id;
            $toUpdate[] = $lookup[$id];

            $where = $connection->quoteInto('value_id = ?', $attribute->value_id);

            $connection->update(
                $attributesTable,
                [
                    'store_id'         => 0,
                    'attribute_id'     => $id,
                    $entityIdFieldName => $row_id,
                    'value'            => $value
                ],
                $where
            );
        }

        /* Add missing attributes */

        foreach (array_diff($assignableAttributes, $toUpdate) as $attributeCode) {
            if (!isset($attributesSet[$attributeCode])) {
                continue;
            }

            $attributeId = $attributesSet[$attributeCode]->attribute_id;

            $connection->insert($attributesTable, [
                'store_id'         => 0,
                'attribute_id'     => $attributeId,
                $entityIdFieldName => $row_id,
                'value'            => $value
            ]);
        }
    }

    /**
     * Update attributes.
     *
     * @param $row_id
     * @param $value
     * @param Videosflow $videosflow
     * @param array $attributesSet
     */
    protected function addAttributes($row_id, $value, Videosflow $videosflow, array $attributesSet)
    {
        $connection = $this->getConnection();

        $entityIdFieldName = $this->getEntityField();

        $assignableAttributes = explode('|', $videosflow->getVideoType());

        if (empty($assignableAttributes)) {
            return;
        }

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

        /* Lookup for attibute_code => attribute_id */

        foreach ($assignableAttributes as $attribute) {
            if (!isset($attributesSet[$attribute])) {
                continue;
            }

            $attributeId = $attributesSet[$attribute]->attribute_id;

            $connection->insertOnDuplicate($attributesTable, [
                'store_id'         => 0,
                'attribute_id'     => $attributeId,
                $entityIdFieldName => $row_id,
                'value'            => $value
            ], ['value']);
        }
    }

    /**
     * @param $path
     * @return bool
     */
    protected function removeCatalogProductVideoByPath($path)
    {
        $file = BP . "/pub/media/catalog/product{$path}";

        $connection = $this->getConnection();

        $query = "DELETE FROM catalog_product_entity_media_gallery WHERE value = '{$path}'";
        $result = $connection->query($query);
        $add_where = '';

        if (!$result) {
            $this->_logger->info("INSERT VIDEOS: NOT Removed from catalog_product_entity_media_gallery {$path}");
            return false;
        }

        $this->_logger->info("INSERT VIDEOS: Removed from catalog_product_entity_media_gallery {$path}");

        $ProductMediaVideoAttributeIds = $this->getProductMediaVideoAttributeIds();
        if ($ProductMediaVideoAttributeIds) {
            $add_where = " AND attribute_id IN ({$ProductMediaVideoAttributeIds}) ";
        }

        // Removing also the "photo tags" (base, small, thumbnail) or they will be left there
        $query = "DELETE FROM catalog_product_entity_varchar WHERE value = '{$path}' {$add_where}";
        $result = $connection->query($query);

        if (!$result) {
            $this->_logger->info("INSERT VIDEOS: NOT Removed from catalog_product_entity_varchar {$path}");
            return false;
        }

        $this->_logger->info("INSERT VIDEOS: Removed TAG from catalog_product_entity_varchar {$path}");

        if (is_file($file)) {
            unlink($file);
            $this->_logger->info("INSERT VIDEOS: Removed file from disk {$file}");
        } else {
            $this->_logger->info("INSERT VIDEOS: Removing file from disk {$file} not found, skipping");
        }

        $this->removeVideoCacheFromVideoFileName($path);

        return true;
    }

    /**
     * @return string of ids comma separated
     */
    protected function getProductMediaVideoAttributeIds()
    {
        /** @var  $coll Collection */
        $coll = ObjectManager::getInstance()->create(Collection::class);
        $coll->addFieldToFilter('frontend_input', 'media_image');
        $attrAll = $coll->load()->getItems();
        $result = [];
        foreach ($attrAll as $attr) {
            $result[] = $attr->getAttributeId();
        }

        $return = false;
        if (count($result)) {
            $return = implode(',', $result);
        }

        return $return;
    }

    /**
     * @param null $filename
     * @return bool
     */
    protected function removeVideoCacheFromVideoFileName($filename = null)
    {
        return true;
        /*
                // Array of all cache main folders
                try {
                    $main_cache_image_paths = $this->getAllCacheImageMainPaths();
                } catch (Exception $e) {
                    $this->_logger->info('ERROR IMAGES: removeImageCacheFromImageFileName ' . $e->getMessage());
                    return false;
                }

                if (!isset($main_cache_image_paths) || !$main_cache_image_paths || count($main_cache_image_paths) === 0) {
                    return false;
                }

                foreach ($main_cache_image_paths as $path) {

                    // Safe check
                    $path = rtrim($path, DIRECTORY_SEPARATOR);

                    $full_path = $this->cache_folder . $path . $filename;

                    if (file_exists($full_path)) {
                        // Try to delete the cache
                        unlink($full_path);
                        $this->_logger->info("INSERT IMAGES: Removed cache image {$full_path}");
                    }
                }
        */
    }

    /**
     * @param $existingMediaGalleryEntries
     * @return void
     */
    public function clearPreviousMedia($existingMediaGalleryEntries)
    {
        if ($existingMediaGalleryEntries === null) {
            return;
        }

        $connection = $this->getConnection();

        $ids = [];
        foreach ($existingMediaGalleryEntries as $entry) {
            $ids[] = $entry->getId();
        }

        $mediaGalleryValueTable = $connection->getTableName('catalog_product_entity_media_gallery_value');
        $condition = [
            "value_id IN (?)" => $ids,
        ];

        $connection->delete($mediaGalleryValueTable, $condition);
    }
}
