<?php

namespace Comitium5\DesignerBundle\Manager\Widget;

use Comitium5\DesignerBundle\Entity\Widget;
use Comitium5\DesignerBundle\Factory\AbstractFactory;
use Comitium5\DesignerBundle\Factory\Widget\WidgetFactory;
use Comitium5\DesignerBundle\Helper\Widget\WidgetHelper;
use Comitium5\DesignerBundle\Manager\AbstractManager;
use Comitium5\DesignerBundle\Model\Interfaces\Widget\WidgetInterface;
use Comitium5\DesignerBundle\Model\WidgetType;
use Comitium5\DesignerBundle\Repository\Layout\LayoutPageWidgetRepository;
use Comitium5\DesignerBundle\Repository\Widget\WidgetRepository;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\HttpFoundation\File\File;

/**
 * Class WidgetManager
 *
 * @author Carles Gómez <carles@bab-soft.com>
 * @package Comitium5\DesignerBundle\Manager\Widget
 */
class WidgetManager extends AbstractManager
{
    /**
     * @var WidgetHelper
     */
    private $helper;

    /**
     * @var LayoutPageWidgetRepository
     */
    private $layoutPageWidgetRepository;

    /**
     * @var string
     */
    private $tmpDir;

    /**
     * @var WidgetFactory
     */
    private $widgetFactory;

    /**
     * WidgetManager constructor.
     *
     * @param AbstractFactory $factory
     * @param WidgetRepository $repository
     * @param ObjectManager $objectManager
     * @param WidgetHelper $helper
     * @param LayoutPageWidgetRepository $layoutPageWidgetRepository
     * @param $tmpDir
     * @param WidgetFactory $widgetFactory
     */
    public function __construct(
        AbstractFactory $factory,
        WidgetRepository $repository,
        ObjectManager $objectManager,
        WidgetHelper $helper,
        LayoutPageWidgetRepository $layoutPageWidgetRepository,
        $tmpDir,
        WidgetFactory $widgetFactory
    ) {
        $this->factory = $factory;
        $this->repository = $repository;
        $this->objectManager = $objectManager;
        $this->helper = $helper;
        $this->layoutPageWidgetRepository = $layoutPageWidgetRepository;
        $this->tmpDir = $tmpDir;
        $this->widgetFactory = $widgetFactory;
    }

    /**
     * @param $item
     *
     * @return mixed
     */
    public function cloneItem($item)
    {
        $clonedItem = clone $item;
        $clonedItem->setName($this->translator->trans('cs_core.label.copy_of').$clonedItem->getName());

        $this->cloneHandler($clonedItem, $item);

        $clonedItem->setCreatedAt(new \DateTime('NOW'));
        $clonedItem->setUpdatedAt(new \DateTime('NOW'));

        return $clonedItem;
    }

    /**
     * Use to allow or deny remove action
     *
     * @param WidgetInterface $widget
     *
     * @return bool
     */
    public function checkIfIsUsedByLayouts(WidgetInterface $widget)
    {
        $layoutPageWidgets = $this
            ->layoutPageWidgetRepository
            ->findBy([
                "widget" => $widget,
            ]);

        return count($layoutPageWidgets) ? true : false;
    }

    /**
     * @param WidgetInterface $widget
     * @param File $file
     *
     * @return array
     */
    public function compareFiles(WidgetInterface $widget, File $file)
    {
        $originalPath = $this->helper->pathInBundle($widget);

        $fileSystem = new Filesystem();

        if (!$fileSystem->exists($originalPath)) {
            return [];
        }

        $uploadedTmpPathBase = $this
                ->tmpDir.
            DIRECTORY_SEPARATOR.
            'uploaded'.
            DIRECTORY_SEPARATOR.
            $widget->buildFolderName(false);

        $zip = new \ZipArchive();

        $zip->open($file->getPathName());
        $zip->extractTo($uploadedTmpPathBase);
        $zip->close();

        $uploadedTmpPath = $uploadedTmpPathBase.DIRECTORY_SEPARATOR.$widget->formatName();

        $finder = new Finder();
        $finder->files()->in($originalPath.'/Resources/public/css')->name('styles.css');
        $finder
            ->files()
            ->in(
                $originalPath.
                '/Resources/translations'
            )
            ->name(sprintf('/%s\.(.+)\.yml$/', $widget->formatName()));

        $originalFiles = [];
        foreach ($finder as $file) {
            $originalFiles[] = str_replace($originalPath, '',
                ($file->getPath().DIRECTORY_SEPARATOR.$file->getFilename()));
        }

        $finder = new Finder();
        $finder->files()->in($uploadedTmpPath.'/Resources/public/css')->name('styles.css');
        $finder
            ->files()
            ->in(
                $uploadedTmpPath.'/Resources/translations'
            )
            ->name(sprintf('/%s\.(.+)\.yml$/', $widget->formatName()));

        $uploadedFiles = [];
        foreach ($finder as $file) {
            $uploadedFiles[] = str_replace($uploadedTmpPath, '',
                ($file->getPath().DIRECTORY_SEPARATOR.$file->getFilename()));
        }

        $filesToCompare = array_intersect($originalFiles, $uploadedFiles);

        $compare = [];

        $fileComparator = $this->fileComparator;

        foreach ($filesToCompare as $fileToCompare) {
            $key = \preg_match('/(.+)translations(.+)/', $fileToCompare) ? 'translation' : 'css';

            $originalFile = $originalPath.$fileToCompare;
            $uploadedFile = $uploadedTmpPath.$fileToCompare;

            $diff = $fileComparator::toTable($fileComparator::compareFiles($originalFile, $uploadedFile));

            if ($fileComparator::hasDifferences()) {
                $compare[$key][$fileToCompare] = $diff;
            }
        }

        if ($fileSystem->exists($uploadedTmpPathBase)) {
            $fileSystem->remove($uploadedTmpPathBase);
        }

        return $compare;
    }

    /**
     * @param $name
     * @param $title
     * @param int $type
     * @param string $author
     * @param null $description
     */
    public function createWidget($name, $title, $type = WidgetType::DYNAMIC, $author = "BAB", $description = null)
    {
        $widget = $this->createWidgetInstance($name, $title, $type, $author, $description);

        $this->save($widget);
    }

    /**
     * @param $name
     * @param $title
     * @param int $type
     * @param null $description
     *
     * @return mixed
     */
    public function createWidgetInstance($name, $title, $type = WidgetType::DYNAMIC, $description = null)
    {
        $widget = $this->widgetFactory->create();

        $widget->setType($type);
        $widget->setName($name);
        $widget->setDescription($description);
        $widget->setTitle($title);

        return $widget;
    }

    /**
     * @param Widget $widget
     *
     * @throws \Exception
     */
    public function updateWidget(Widget $widget)
    {
        $this->update($widget);
    }

    /**
     * @param Widget $widget
     */
    public function deleteWidget(Widget $widget)
    {
        $this->remove($widget);
    }

    /**
     * @param  mixed $data
     *
     * @return WidgetInterface
     */
    public function fromArray($data)
    {
        try {
            $widget = $this->find(
                !empty($data['id']) ? $data['id'] : 0
            );
        } catch (\Exception $e) {
            $widget = $this->getFactory()->create();
        }

        $widget->fromArray($data);

        return $widget;
    }
}
