<?php
/**
 * Copyright © 2015 FiloBlu . All rights reserved.
 */

namespace FiloBlu\Flow\Helper;

use InvalidArgumentException;
use Magento\Catalog\Model\Product\Type;
use Magento\Catalog\Model\ProductFactory;
use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\Helper\Context;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Store\Model\ScopeInterface;

use function strlen;

/**
 * Class Images
 * @package FiloBlu\Flow\Helper
 */
class Images extends AbstractHelper
{
    /**
     * @var ResourceConnection
     */
    protected $resourceConnection;

    /**
     * @var Configurable
     */
    protected $_configurable_type;

    /**
     * @var ProductFactory
     */
    protected $_product_factory;

    /**
     * @var AdapterInterface
     */
    protected $connection;

    /**
     * Images constructor.
     * @param Context $context
     * @param ResourceConnection $connection
     * @param ProductFactory $productFactory
     * @param Configurable $configurableProduct
     */
    public function __construct(
        Context $context,
        ResourceConnection $connection,
        ProductFactory $productFactory,
        Configurable $configurableProduct
    ) {
        $this->resourceConnection = $connection;
        $this->_configurable_type = $configurableProduct;
        $this->_product_factory = $productFactory;
        parent::__construct($context);
    }

    /**
     * @return mixed
     */
    public function isFullPhotoCleanActive()
    {
        return $this->scopeConfig->getValue('filoblu_flow/flow_images/flow_images_force_clean', ScopeInterface::SCOPE_WEBSITE);
    }

    /**
     * @return mixed
     */
    public function isClearImageCacheActive()
    {
        return $this->scopeConfig->getValue('filoblu_flow/flow_images/flow_images_clean_cache', ScopeInterface::SCOPE_WEBSITE);
    }

    /**
     * @return mixed
     */
    public function isUniqueUploadImagesActive()
    {
        return $this->scopeConfig->getValue('filoblu_flow/flow_images/flow_images_upload_unique', ScopeInterface::SCOPE_WEBSITE);
    }

    /**
     * @return mixed
     */
    public function isDuplicateImagesActive()
    {
        return $this->scopeConfig->getValue('filoblu_flow/flow_images/flow_images_create_duplicates', ScopeInterface::SCOPE_WEBSITE);
    }

    /**
     * Returns an array of folders of $source_dir
     *
     * @param $source_dir
     * @param int $directory_depth
     * @param bool $hidden
     * @return array|bool
     */
    public function foldersMap($source_dir, $directory_depth = 0, $hidden = false)
    {
        if ($fp = @opendir($source_dir)) {
            $fileData = [];
            $new_depth = $directory_depth - 1;
            $source_dir = rtrim($source_dir, '/') . '/';

            while (false !== ($file = readdir($fp))) {
                // Remove '.', '..', and hidden files [optional]
                if (($hidden === false && strpos($file, '.') === 0) || !trim($file, '.')) {
                    continue;
                }

                if (($directory_depth < 1 || $new_depth > 0) && @is_dir($source_dir . $file)) {
                    $fileData[$file] = $this->foldersMap($source_dir . $file . '/', $new_depth, $hidden);
                } else {
                    $fileData[] = $file;
                }
            }

            closedir($fp);
            return $fileData;
        }
        echo 'can not open dir';
        return false;
    }

    /**
     * This function will get as input one array of folders from foldersMap function
     * Then will convert that array into paths (strings) of the magento
     * images cache folder checking that the last folder is an MD5 (because this is how Magento builds the image caches paths)
     * https://www.sonassi.com/blog/knowledge-base/deconstructing-the-cache-image-path-on-magento
     *
     * $result = [];
     * collapse("",$array_of_paths,$result);
     *
     * $result will be an array of paths (strings)
     *
     * @param $path
     * @param $collapse
     * @param $result
     */
    public function collapse($path, $collapse, &$result)
    {
        foreach ($collapse as $key => $value) {
            if (is_array($value)) {
                $this->collapse($path . $key . DIRECTORY_SEPARATOR, $value, $result);
                continue;
            }

            if (preg_match('/^[a-f0-9]{32}$/', $value)) {
                $result[] = $path . $value . DIRECTORY_SEPARATOR;
            } else {
                $result[] = $path;
            }
        }
    }

    /**
     * This function will return all the products childs of a parent that have the same super_attibute value
     *
     * @param $child_sku
     * @param $super_attribute_code
     * @return array
     */
    public function getAllChildsOfParentWithSameAttribute($child_sku, $super_attribute_code)
    {
        $childrenSku = [];

        $child_id = $this->fastGetIdBySku($child_sku);

        if (!is_numeric($child_id)) {
            return $childrenSku;
        }

        $loaded_child = $this->_product_factory->create()->load($child_id);

        //$super_attribute_value = $loaded_child->getResource()->getAttribute($super_attribute_code)->getFrontend()->getValue($loaded_child);
        $super_attribute_value = $loaded_child->getData($super_attribute_code);

        // Get the product parent
        if ($loaded_child->getTypeId() !== Type::DEFAULT_TYPE) {
            return $childrenSku;
        }

        $parentIds = $this->_configurable_type->getParentIdsByChild($child_id);

        if (count($parentIds) === 0) {
            return $childrenSku;
        }

        foreach ($parentIds as $parentId) {
            $parent_product = $this->_product_factory->create()->load($parentId);
            // Get now all the children of the parent
            $_children = $parent_product->getTypeInstance()->getUsedProducts($parent_product);
            foreach ($_children as $child) {
                if ($child->getData($super_attribute_code) === $super_attribute_value && $child->getSku() !== $loaded_child->getSku()) {
                    $childrenSku[] = $child->getSku();
                }
            }
            // Handling only one parent_sku
            break;
        }

        return $childrenSku;
    }

    /**
     * @param null $sku
     * @return bool
     */
    protected function fastGetIdBySku($sku = null)
    {
        if (!$sku) {
            return false;
        }

        $sql = "SELECT entity_id FROM catalog_product_entity WHERE sku = '{$sku}'";
        $result = $this->getConnection()->fetchRow($sql);

        if (isset($result['entity_id']) && $result['entity_id']) {
            return $result['entity_id'];
        }

        return false;
    }

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

    /**
     * @param $fileName
     * @throws InvalidArgumentException
     * @return string|null
     */
    public function getCorrectFileName($fileName)
    {
        $fileName = preg_replace('/[^a-z0-9_\\-\\.]+/i', '_', $fileName);
        $fileInfo = pathinfo($fileName);
        $fileInfo['extension'] = $fileInfo['extension'] ?? '';

        // account for excessively long filenames that cannot be stored completely in database
        if (strlen($fileInfo['basename']) > 240) {
            throw new InvalidArgumentException('Filename is too long; must be 240 characters or less');
        }

        if (preg_match('/^_+$/', $fileInfo['filename'])) {
            $fileName = 'file.' . $fileInfo['extension'];
        }

        return $fileName;
    }
}
