<?php
namespace NicolasBejean\CategoryWidget\Block\Widget;

use \Magento\Framework\Filesystem;
use \Magento\Framework\UrlInterface;
use \Magento\Framework\App\Filesystem\DirectoryList;
use \Magento\Framework\Image\AdapterFactory as ImageAdapterFactory;
use \Magento\Framework\View\Element\Template;
use \Magento\Framework\View\Element\Template\Context;
use \Magento\Store\Model\ScopeInterface;
use \Magento\Store\Model\StoreManagerInterface;
use \Magento\Widget\Block\BlockInterface;

use \NicolasBejean\Base\Helper\ImageOptimizer;

use \NicolasBejean\CategoryWidget\Model\CategoryWidget as CategoryWidgetModel;
use \NicolasBejean\CategoryWidget\Model\CategoryWidgetRepository;
use \NicolasBejean\CategoryWidget\Model\CategoryWidgetFactory;
use \NicolasBejean\CategoryWidget\Model\Template\FilterProvider;

use \NicolasBejean\MediaManager\Model\ImageRepository;
use \NicolasBejean\MediaManager\Model\Image as ImageModel;

use \Exception;
use \Magento\Framework\Exception\LocalizedException;
use \Magento\Framework\Exception\NoSuchEntityException;

/**
 * Class CategoryWidgetNEw for Widget
 *
 * @category PHP
 * @package  NicolasBejean\CategoryWidget\Block\Widget
 * @author   Nicolas Béjean <nicolas@bejean.eu>
 * @license  https://github.com/nicolasbejean/category-widget/blob/master/licence.txt BSD Licence
 * @link     https://www.bejean.eu
 */
class CategoryWidgetNew extends Template implements BlockInterface
{
    /**
     * @var string
     */
    protected $_template = "widget/categorywidget/default.phtml";

    /**
     * @var FilterProvider
     */
    protected $filterProvider;

    /**
     * Category Widget factory
     *
     * @var CategoryWidgetFactory
     */
    protected $categoryWidgetFactory;

    /**
     * @var ImageAdapterFactory
     */
    protected $imageAdapterFactory;

    /**
     * Store manager
     *
     * @var StoreManagerInterface
     */
    protected $storeManager;

    /**
     * Filesystem instance
     *
     * @var Filesystem
     */
    protected $filesystem;

    /**
     * @var array
     */
    protected $resizeSettings = [];

    /**
     * @var array
     *
     * - constrainOnly[true]: Guarantee, that image picture will not be bigger, than it was. It is false by default.
     * - keepAspectRatio[true]: Guarantee, that image picture width/height will not be distorted. It is true by default.
     * - keepTransparency[true]: Guarantee, that image will not lose transparency if any. It is true by default.
     * - keepFrame[false]: Guarantee, that image will have dimensions, set in $width/$height. Not applicable,
     * if keepAspectRatio(false).
     * - backgroundColor[null]: Default white
     */
    protected $defaultSettings = [];

    /**
     * @var ImageOptimizer
     */
    protected $imageOptimizer;

    /**
     * @var ImageRepository
     */
    private $imageRepository;

    /**
     * @var CategoryWidgetRepository
     */
    private $categoryWidgetRepository;

    /**
     * @param Context $context
     * @param FilterProvider $filterProvider
     * @param CategoryWidgetFactory $categoryWidgetFactory
     * @param CategoryWidgetRepository $categoryWidgetRepository
     * @param ImageRepository $imageRepository
     * @param ImageOptimizer $imageOptimizer
     * @param ImageAdapterFactory $imageAdapterFactory
     * @param array $data
     */
    public function __construct(
        Context                            $context,
        FilterProvider                     $filterProvider,
        CategoryWidgetFactory              $categoryWidgetFactory,
        CategoryWidgetRepository           $categoryWidgetRepository,
        ImageRepository                    $imageRepository,
        ImageOptimizer                     $imageOptimizer,
        ImageAdapterFactory                $imageAdapterFactory,
        array $data                        = []
    ) {
        $this->storeManager                = $context->getStoreManager();
        $this->filesystem                  = $context->getFilesystem();

        $this->filterProvider              = $filterProvider;
        $this->categoryWidgetFactory       = $categoryWidgetFactory;
        $this->categoryWidgetRepository    = $categoryWidgetRepository;
        $this->imageRepository             = $imageRepository;
        $this->imageOptimizer              = $imageOptimizer;
        $this->imageAdapterFactory         = $imageAdapterFactory;

        parent::__construct($context, $data);

        $this->defaultSettings = [
            'constrainOnly' => $this->_scopeConfig->getValue('Categorywidget/resize/constrain_only', ScopeInterface::SCOPE_STORE),
            'keepAspectRatio' => $this->_scopeConfig->getValue('Categorywidget/resize/keep_aspect_ratio', ScopeInterface::SCOPE_STORE),
            'keepTransparency' => $this->_scopeConfig->getValue('Categorywidget/resize/keep_transparency', ScopeInterface::SCOPE_STORE),
            'keepFrame' => $this->_scopeConfig->getValue('Categorywidget/resize/keep_frame', ScopeInterface::SCOPE_STORE),
            'backgroundColor' => $this->_scopeConfig->getValue('Categorywidget/resize/background_color', ScopeInterface::SCOPE_STORE),
            'identifier' => $this->_scopeConfig->getValue('Categorywidget/save/identifier', ScopeInterface::SCOPE_STORE),
            'basename' => $this->_scopeConfig->getValue('Categorywidget/save/basename', ScopeInterface::SCOPE_STORE),
            'width' => $this->_scopeConfig->getValue('Categorywidget/save/width', ScopeInterface::SCOPE_STORE),
            'height' => $this->_scopeConfig->getValue('Categorywidget/save/height', ScopeInterface::SCOPE_STORE),
            'compression' => $this->_scopeConfig->getValue('Categorywidget/save/compression', ScopeInterface::SCOPE_STORE)
        ];
    }

    /**
     * Get Slider
     *
     * @return CategoryWidgetModel
     */
    public function getSlider()
    {
        try {
            /** @var CategoryWidgetModel $slider */
            $slider = $this->categoryWidgetRepository->getById($this->getId());

            return $slider;
        } catch (LocalizedException $e) {
            return null;
        }
    }

    /**
     * Get Slider Content
     *
     * @param $content
     * @return array
     */
    public function getSliderContent(string $content)
    {
        $array = explode('|', $content);
        $array = array_map('intval', $array);

        $result = array();

        foreach ($array as $image) {
            array_push($result, $this->getImage((int)$image));
        }

        return $result;
    }

    /**
     * Get Image
     *
     * @param int $id
     * @return array
     */
    private function getImage (int $id)
    {
        try {
            /** @var ImageModel $image */
            $image = $this->imageRepository->getById($id);

            $result = array();
            $result['id'] = $image->getId();
            $result['path'] = $image->getPath();
            $result['alt'] = $image->getAlt();
            $result['is_active'] = $image->isActive();

            return $result;
        } catch (LocalizedException $e) {
            return null;
        }
    }

    /**
     * Récupère l'ID du slider
     */
    public function getId()
    {
        return $this->getData('id');
    }

    /**
     * Récupère la valeur pour l'ajout d'un titre
     */
    public function getActiveTitle()
    {
        if ($this->getWidgetTitle() !== null) {
            if ($this->getData('active_title') === 'true') {
                return true;
            }

            return false;
        }

        return false;
    }

    /**
     * Récupère le titre du widget
     */
    public function getWidgetTitle()
    {
        return $this->getData('title');
    }

    /**
     * Récupère la balise du titre du widget
     */
    public function getWidgetTitleTag()
    {
        return $this->getData('title_tag');
    }

    /**
     * Récupère la class CSS du titre du widget
     */
    public function getWidgetTitleCSS()
    {
        return $this->getData('title_css_classes');
    }

    /**
     * Récupère la valeur pour l'ajout d'un contenu
     */
    public function getActiveContent()
    {
        if ($this->getWidgetContent() !== null) {
            if ($this->getData('active_content') === 'true') {
                return true;
            }

            return false;
        }

        return false;
    }

    /**
     * Récupère le contenu du widget
     */
    public function getWidgetContent()
    {
        if (strlen($this->getData('content')) === 0) {
            return false;
        }

        return $this->getData('content');
    }

    /**
     * Récupère la class CSS du contenu du widget
     */
    public function getWidgetContentCSS()
    {
        if (strlen($this->getData('content_css_classes')) === 0) {
            return false;
        }

        return $this->getData('content_css_classes');
    }

    /**
     * Récupère la largeur de l'image du widget
     */
    public function getWidth()
    {
        if (is_null($this->getData('width'))) {
            return $this->defaultSettings['width'];
        }

        return $this->getData('width');
    }

    /**
     * Récupère la hauteur de l'image du widget
     */
    public function getHeight()
    {
        if (is_null($this->getData('height'))) {
            return $this->defaultSettings['height'];
        }

        return $this->getData('height');
    }

    /**
     * Récupère les classes CSS
     */
    public function getCssClasses()
    {
        if (strlen($this->getData('css_classes')) === 0) {
            return false;
        }

        return $this->getData('css_classes');
    }

    /**
     * Récupère le CSS pour l'attribut style
     */
    public function getExtraCss()
    {
        if (strlen($this->getData('extra_css')) === 0) {
            return false;
        }

        return $this->getData('extra_css');
    }

    /**
     * Récupère les attributs pour le data-bind
     */
    public function getDataBind()
    {
        if (strlen($this->getData('data')) === 0) {
            return false;
        }

        return $this->getData('data');
    }

    /**
     * Récupère la valeur pour l'activation du wrapper
     */
    public function getActiveWrapper()
    {
        if ($this->getData('active_wrapper') === 'true') {
            return true;
        }

        return false;
    }

    /**
     * Récupère les classes CSS complémentaires pour le wrapper
     */
    public function getWrapperCssClasses()
    {
        if (strlen($this->getData('wrapper_css_classes')) === 0) {
            return false;
        }

        return $this->getData('wrapper_css_classes');
    }

    /**
     * Récupère la création du lien
     */
    public function getActiveLink()
    {
        if ($this->getData('active_link') === 'true') {
            return true;
        }

        return false;
    }

    /**
     * Récupère le lien
     */
    public function getLinkHref()
    {
        return $this->getData('link');
    }

    /**
     * Récupère la cible du lien
     */
    public function getLinkTarget()
    {
        return $this->getData('link_target');
    }

    /**
     * Prepare and set resize settings for image
     *
     * @param array $resizeSettings
     */
    protected function initResizeSettings(array $resizeSettings)
    {
        // Init resize settings with default
        $this->resizeSettings = $this->defaultSettings;
        // Override resizeSettings only if key matches with existing settings
        foreach ($resizeSettings as $key => $value) {
            if (array_key_exists($key, $this->resizeSettings)) {
                $this->resizeSettings[$key] = $value;
            }
        }
    }

    /**
     * Permet d'optimiser les images
     *
     * @param $image
     * @param null $width
     * @param null $height
     * @param array $settings
     * @return string
     * @throws NoSuchEntityException
     */
    public function getResizeImage($image, $width = null, $height = null, array $settings = [])
    {
        $baseURL = $this->storeManager->getStore()->getBaseUrl(UrlInterface::URL_TYPE_MEDIA);

        /* Si c'est pas un fichier JPG, on retourne l'original */
        if (substr($image, -3) != 'jpg') {
            return $baseURL . $image;
        }

        /* Si il n'y a pas de resize activé, on retourne l'original */
        if ($this->getData('active_resize') === 'false') {
            return $baseURL . $image;
        }

        $settings['basename'] = $image;

        if ($image) {
            if (is_string($image)) {
                $isRelativeUrl = substr($image, 0, 1) === '/';
                if ($isRelativeUrl) {
                    $image = ltrim($image, '/media/');
                } else {
                    $image = 'mediamanager/image/' . $image;
                }
            }
        }

        $dirPath = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA);
        $absolutePath = $dirPath->getAbsolutePath('') . $image;

        if (!is_null($width)) {
            $settings['width'] = (int)$width;
        }

        if (!is_null($height)) {
            $settings['height'] = (int)$height;
        }

        if (!is_null($this->getData('quality'))) {
            $settings['compression'] = (int)$this->getData('quality');
        }

        /* Initialise les options de redimensionnement */
        $this->initResizeSettings($settings);

        try {
            return $this->imageOptimizer->getResizeImage($absolutePath, $dirPath->getAbsolutePath(''), $this->resizeSettings);
        } catch (Exception $e) {
            return $baseURL . $image;
        }
    }

    /**
     * Récupère la largeur de l'image du widget
     *
     * @param $imagePath
     * @return int|mixed|null
     */
    public function getResizedImageWidth($imagePath)
    {
        $dirPath = $this->filesystem->getDirectoryRead(DirectoryList::PUB);
        $absoluteImagePath = $dirPath->getAbsolutePath($imagePath);

        return $this->imageOptimizer->getImageWidth($absoluteImagePath);
    }

    /**
     * Récupère la hauteur de l'image du widget
     *
     * @param $imagePath
     * @return int|mixed|null
     */
    public function getResizedImageHeight($imagePath)
    {
        $dirPath = $this->filesystem->getDirectoryRead(DirectoryList::PUB);
        $absoluteImagePath = $dirPath->getAbsolutePath($imagePath);

        return $this->imageOptimizer->getImageHeight($absoluteImagePath);
    }
}