<?php

namespace Webkul\DamBundle\Services;

use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Pim\Bundle\CatalogBundle\Entity\Attribute;
use Oro\Bundle\ConfigBundle\Entity\ConfigValue;
use Pim\Bundle\CatalogBundle\Entity\AttributeOption;
use Webkul\DamBundle\Entity\AssetTag;
use Webkul\DamBundle\Entity\Asset;
use Webkul\DamBundle\Entity\AssetMedia;
use Ijanki\Bundle\FtpBundle\Exception\FtpException;
use Symfony\Component\Filesystem\Filesystem;
use Webkul\DamBundle\Entity\AssetCategory;
use Webkul\DamBundle\Listener\ClassDefinationForCompatibility;

$versionCompatiblility = new ClassDefinationForCompatibility();
$versionCompatiblility->createClassAliases();

/**
 * Transforms media url path to absolute path
 *
 */
class DamServices
{
    const SECTION = 'wk_digital_asset';

    private $em;
    private $container;
    protected $attribute;
    protected $fileSystem;
    protected $metric;
    protected $measure;
    protected $ftp;
    protected $fileInfoRepo;
    protected $overrideImages = true;
    /**
     * @param AttributeRepositoryInterface $attributeRepository
     */
    public function __construct(
        $container,
        \Doctrine\ORM\EntityManager $em,
        $attribute,
        $fileSystem,
        $metric,
        $measure,
        $ftp,
        $fileInfoRepo
    ) {
        $this->container = $container;
        $this->em = $em;
        $this->attribute = $attribute;
        $this->fileSystem = $fileSystem;
        $this->metric = $metric;
        $this->measure = $measure;
        $this->ftp = $ftp;
        $this->fileInfoRepo = $fileInfoRepo;
    }

    /**
     * Transforms a relative path to absolute. Data must be provided in the pivot format.
     *
     * $item exemple:
     * [
     *   'side_view' => [
     *     [
     *       'locale' => null,
     *       'scope'  => null,
     *       'data'   => 'http://abcd.com/cat_003.png'
     *     ]
     *   ]
     * ]
     *
     * @param array  $attributeValues An associative array (attribute_code => values)
     * @param string $filePath        The absolute path
     *
     * @return array
     */
    
    public function gethostName()
    {
        $repo = $this->em->getRepository('OroConfigBundle:ConfigValue');
        $configs = $repo->findOneBy([
                'section' => "magento2_connector",
                'name' => "host"
                ]);

        return $configs->getValue();
    }

    public function generateImageUrl($filename, $host = null)
    {
        $filename = urldecode($filename);
        $baseurl = $this->gethostName();
        $host = !empty($baseurl) ? $baseurl : null;
        $router = $this->container->get('router');
        if ($host) {
            $context = $router->getContext();
            $context->setHost($host);
            $context->setScheme('http');
        }
        $request = new Request();
        try {
            $url = $router->generate('pim_enrich_media_download', [
                                                    'filename' => urlencode($filename)
                                                ], UrlGeneratorInterface::ABSOLUTE_URL);
        } catch (\Exception $e) {
            $url  = '';
        }
 
        return $url;
    }

    public function getAssetAttributeCodes()
    {
        $asset = [];
        $asset = $this->attribute->getAttributeCodesByType(
            'pim_catalog_asset_group'
        );
        
        return $asset;
    }

    public function getAttributeOption($attribute, $code, $locale)
    {
        $attrCode = $attribute . '.' . $code;
        if (empty($this->attributeOptions[$attrCode])) {
            $this->attributeOptions[$attrCode] = $this->em->getRepository('PimCatalogBundle:AttributeOption')->findOneByIdentifier($attrCode);
        }

        $attributeOption = $this->attributeOptions[$attrCode];
        if ($attributeOption) {
            $attributeOption->setLocale($locale);

            return $attributeOption->__toString() !== '[' . $code . ']' ? $attributeOption->__toString() : $code;
        }
    }

    public function transform($values, $filePath, $code)
    {
        $media = [];
       
        
        foreach ($values as $index => $value) {
            if (isset($value)) {
                if (filter_var($value, FILTER_VALIDATE_URL)) {
                    $media[] = $this->changeUrlToContent($value, $code, $index);
                } else {
                    
                    $dataFilePath = $value;
                    $mediapath = sprintf(
                        '%s%s%s',
                        $filePath,
                        DIRECTORY_SEPARATOR,
                        $dataFilePath
                    );
                    
                    $mediapath = $this->clean($mediapath);
                    // dd($filePath, $mediapath);
                    try {
                        $link_array = explode('/', $filePath);
                        $page = str_replace(' ', '', end($link_array));
                       
                        $newFilePath = $page.'/'.$dataFilePath;

                        $newFileDirectory = substr($newFilePath, 0, strrpos($newFilePath, '/'));
                        if (!file_exists($newFilePath) || $this->overrideImages) { 
                            
                            // if ($version > '3.0' && $version < '4.0') {
                            //     $fs = $this->fileSystem->getFilesystem('tmpStorage');
                            // } else {
                            //     $fs = $this->fileSystem->getFilesystem(\FileStorage::CATALOG_STORAGE_ALIAS);
                            // }
                            $fs = $this->fileSystem->getFilesystem('catalogStorage');
                            $content = fopen($mediapath, 'r');
                            try {
                                $content = fopen($mediapath, 'r');
                            } catch (\Exception $e) {
                                dump('Exception : ', $e->getMessage());
                            }
                            $fs->put($newFilePath, $content);

                            $newFilePath = $fs->getAdapter()->getPathPrefix() . $newFilePath;
                        }
                        
                        $media[] = $newFilePath;
                    } catch (\Exception $e) {
                        echo $e->getMessage();
                        $newFilePath = null;
                    }
                }
            }
        }
        
        
        return $media;
    }

    public function clean($full_path){
        return str_replace(array(
            "\\\\",
            "\\/", 
            "//", 
            "\\/", 
            "/\\"), DIRECTORY_SEPARATOR, $full_path);
    }

    public function getMetricUnits()
    {
        $measure = $this->metric->indexAction();
        $getFamilies = json_decode($measure->getContent(), true);
        $families = [];
        
        foreach ($getFamilies as $family => $familyData) {
            $families[] = $family;
        }
        $symbol = [];
        $getSymbolByFamily = $this->measure;
        
        foreach ($families as $family) {
            $symbolOfFamily = $getSymbolByFamily->getUnitSymbolsForFamily($family);
            $symbol = array_merge($symbol, $symbolOfFamily);
        }

        return $symbol;
    }

    public function changeUrlToContent($url, $code, $index)
    {
        try {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_HEADER, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.1 Safari/537.11');
            $res = curl_exec($ch);
            $rescode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch) ;
    
            $fileSystemProvide = $this->fileSystem;
            $fs = $fileSystemProvide->getFilesystem('tmpStorage');
            $file = pathinfo($url);
            $fileName = isset($file['extension']) ? (isset($file['basename']) ? $file['basename'] : null)
                                                  : (isset($file['basename']) ? $file['basename'].".jpg" : null);
            if (!$fileName) {
                throw new \Exception("file name does not exist");
            }
            
            $filePath = $code . "/" . $index . "/" . $fileName;
            $fs->put($filePath, $res);
            $newFilePath = $fs->getAdapter()->getPathPrefix() . $filePath;
        } catch (\Exception $e) {
            $newFilePath = null;
        }
        
        return $newFilePath;
    }

    public function saveTags($params)
    {
        $repo = $this->em->getRepository('WebkulDamBundle:AssetTag');
        
        foreach ($params as $param) {
            $configs = $repo->findOneBy([
                'code' => $param
                ]);
            if (!$configs) {
                $configs = new AssetTag();
                $configs->setCode($param);
                $this->em->persist($configs);
            }
            $this->em->flush();
        }
    }

    public function saveTagAssociation($params)
    {
        $repo = $this->container->get('webkul_dam.repository.asset')->findOneByCode($params['code']);
        $repoTags = $this->em->getRepository('WebkulDamBundle:AssetTag');
        $tag = $params['tag'];
        $assettag = $repo->getTags();
        $storedRelatedTag = [];
        foreach ($assettag->getValues() as $tags) {
            $storedRelatedTag[] =$tags->getCode();
        }
        
        foreach ($tag as $param) {
            $configs = $repoTags->findOneBy([
                'code' => $param
                ]);
            if (!in_array($param, $storedRelatedTag)) {
                $repo->addTag($configs);
            }
        }

        foreach ($storedRelatedTag as $relatedTags) {
            $configs = $repoTags->findOneBy([
                'code' => $relatedTags
                ]);
            if (!in_array($relatedTags, $tag)) {
                $repo->removeTag($configs);
            }
        }
        
        $this->em->persist($repo);
        $this->em->flush();
    }

    public function getRelatedTagsOfAssets($code)
    {
        $repo = $this->container->get('webkul_dam.repository.asset')->findOneByCode($code);
        $assettag = $repo->getTags();
        $storedRelatedTag = [];

        foreach ($assettag->getValues() as $tags) {
            $storedRelatedTag[] =$tags->getCode();
        }

        return $storedRelatedTag;
    }

    public function getRelatedCategoriesOfAssets($code)
    {
        $repo = $this->container->get('webkul_dam.repository.asset')->findOneByCode($code);
        $categoryCodes = [];
        
        foreach ($repo->getCategory() as $category) {
            $categoryCodes[] = $category->getCode();
        }
        
        return $categoryCodes;
    }
    public function getAllTag()
    {
        $allTag = [];
        $repoTags = $this->em->getRepository('WebkulDamBundle:AssetTag');
    
        foreach ($repoTags->findAll() as $allTags) {
            $allTag[] = $allTags->getCode();
        }
      

        return $allTag;
    }

    public function getChoiceTags()
    {
        $allTag = [];
        $repoTags = $this->em->getRepository('WebkulDamBundle:AssetTag');
    
        foreach ($repoTags->findAll() as $allTags) {
            $allTag[$allTags->getCode()] = $allTags->getId();
        }
       
        return $allTag;
    }

    public function saveCategoryAssociation($params)
    {
        $repo = $this->container->get('webkul_dam.repository.asset')->findOneByCode($params['code']);
        $repoCategory = $this->container->get('webkul_dam.repository.category');
        $category = $params['categories'];
        $assetcategory = $repo->getCategory();
        
        $storedRelatedCategory = [];
        foreach ($assetcategory->getValues() as $categories) {
            $storedRelatedCategory[] =$categories->getCode();
        }
        
        
        foreach ($category as $param) {
            $configs = $repoCategory->findOneBy([
                'code' => $param
                ]);
            
            if (!in_array($param, $storedRelatedCategory)) {
                $repo->addCategory($configs);
            }
        }

        foreach ($storedRelatedCategory as $relatedCategory) {
            $configs = $repoCategory->findOneBy([
                'code' => $relatedCategory
                ]);
            if (!in_array($relatedCategory, $category)) {
                $repo->removeCategory($configs);
            }
        }
        
        $this->em->persist($repo);
        $this->em->flush();
    }

    public function getThumbnailAssetByCode($code)
    {
        $repo = $this->container->get('webkul_dam.repository.asset')->findOneByCode($code);

        if ($repo->getThumbImage()) {
            
            return $this->fileInfoRepo->findOneByIdentifier($repo->getThumbImage());
        }   
         return null;
    }

    public function getImageCachePath()
    {
        return $this->container->get('kernel')->getProjectDir() . "/web/media/cache/thumbnail_small/";
    }

    public function getPreviewPath()
    {
        return $this->container->get('kernel')->getProjectDir() . "/web/media/cache/preview/";
    }

    public function getCatalogPath()
    {
        $fileSystemProvide = $this->fileSystem;
        $fs = $fileSystemProvide->getFilesystem('catalogStorage');
        $catalogPath = $fs->getAdapter()->getPathPrefix();

        return $catalogPath;
    }

    public function getMediaByFilepath($filePath)
    {
        $result = [];
        $repo = $this->em->getRepository('WebkulDamBundle:AssetMedia');
        $media = $repo->findOneBy([
            'filePath' => $filePath
        ]);

        if ($media) {
            $result = $media;
        }

        return $result;
    }

    public function connectFtp($param)
    {
        $host = isset($param['configuration']['hostname']) ? $param['configuration']['hostname'] : null;
        $username = isset($param['configuration']['username']) ? $param['configuration']['username'] : null;
        $password = isset($param['configuration']['password']) ? $param['configuration']['password'] : null;
        $directoryPath = isset($param['configuration']['filePath']) ? $param['configuration']['filePath'] : null;
        
        $result = true;
        try {
            $ftp = $this->ftp;
            $ftp->connect($host);
            $ftp->login($username, $password);
            $fileList = $ftp->nlist($directoryPath);
            if ($fileList) {
                $this->storeFtpDataIntoDb($fileList, $param['code']);
                return new JsonResponse($fileList);
            } else {
                throw new FtpException("File directory is empty or not found");
            }
        } catch (FtpException $e) {
            return new JsonResponse(
                [ "message"=> $e->getMessage()],
                RESPONSE::HTTP_BAD_REQUEST
            );
        }
    }

    public function storeFtpDataIntoDb($fileLists, $code)
    {
        $dirBaseName = [];
        foreach ($fileLists as $fileKey => $fileList) {
            $fileChecker = pathinfo($fileList);
            if (!isset($fileChecker['extension'])) {
                $dirBaseName[] = $fileChecker['basename'];
            }
        }
        
        $value = serialize($dirBaseName);

        $repo = $this->em->getRepository('OroConfigBundle:ConfigValue');
        $field = $repo->findOneBy([
                        'section' => self::SECTION,
                        'name' => $code,
                    ]);
        if (!$field) {
            $field = new ConfigValue();
        }
        $field->setName($code);
        $field->setSection(self::SECTION);
        $field->setValue($value);
        $this->em->persist($field);
        $this->em->flush();
    }

    public function getDirectories($code)
    {
        $repo = $this->em->getRepository('OroConfigBundle:ConfigValue');
        $field = $repo->findOneBy([
            'section' => self::SECTION,
            'name' => $code,
        ]);

        $directory = [];

        if ($field) {
            $directory = unserialize($field->getValue());
        }

        return new JsonResponse($directory);
    }

    public function getAllAssetCode()
    {
        $codes = [];
        $repo = $this->container->get('webkul_dam.repository.asset')->findAll();

        if (!empty($repo)) {
            $codes[] = "select Asset";
            foreach ($repo as $field) {
                $codes[] = $field->getCode();
            }
        }

        return new JsonResponse($codes);
    }

    public function getAllAssetCodes()
    {
        $codes = [];
        $repo = $this->container->get('webkul_dam.repository.asset')->findAll();

        if (!empty($repo)) {
            foreach ($repo as $field) {
                $codes[] = $field->getCode();
            }
        }

        return $codes;
    }

    public function connectToFtp($host, $username, $password, $directoryPath)
    {
        $result = null;
        try {
            $ftp = $this->ftp;
            $ftp->connect($host);
            $ftp->login($username, $password);
            $fileList = $ftp->nlist($directoryPath);
            
            if (!$fileList) {
                throw new FtpException("File directory is empty or not found");
            }
            $result = $ftp;
        } catch (FtpException $e) {
            return false;
        }
     
        return $result;
    }

    public function importFileAsAsset($ftp, $host, $username, $password, $directoryPath)
    {
        $fileLists = $ftp->nlist($directoryPath);

        if ($fileLists) {
            foreach ($fileLists as $key => $fileList) {
                $fileInfo = pathinfo($fileList);
                $item = null;
                $invalidExtension =  ["jpg", "png", "bmp", "gif", "tiff", "pdf", "doc", "svg"];
                if (isset($fileInfo['extension']) && in_array($fileInfo['extension'], $invalidExtension)) {
                    $item =  [
                        "code" => isset($fileInfo['filename']) ? $this->convertToCode($fileInfo['filename']) : uniqid(),
                        "media" => [ $this->StoreIntoTemp($ftp, $fileList)]
                    ];
                }
                
                if ($item) {
                    $items[] = $item;
                }
            }
        }

        return $items;
    }

    public function StoreIntoTemp($ftp, $fileList)
    {
        $filesystem = new Filesystem();
        try {
            $tempFolder = sys_get_temp_dir().'/pim/file_storage/'.random_int(1000, 10000);
            $filesystem->mkdir($tempFolder);
        } catch (IOExceptionInterface $exception) {
            throw new \Exception("An error occurred while creating your directory at ".$exception->getPath());
        }

        try {
            $fileInfo = pathinfo($fileList);
            $fileName = isset($fileInfo['basename'])
                                    ?   $fileInfo['basename']
                                    :   uniqid() . "." . $fileInfo['extension'];

            $fileName = $tempFolder . '/' . $fileName;
            $ftp->get($fileName, $fileList, FTP_BINARY);
        } catch (FtpException $e) {
            throw new FtpException("there is some error occured". $e->getMessage);
        }

        return $fileName;
    }

    public function getAllCategories()
    {
        $codes = [];
        $repo = $this->em->getRepository('WebkulDamBundle:AssetCategory')->createQueryBuilder('c');
        $categories = $repo->andWhere('c.level != :null')
                   ->setParameter('null', '0');
                   
        $categories = $categories->getQuery()->getResult();

        foreach ($categories as $category) {
            $codes[] = $category->getCode();
        }

        return new JsonResponse($codes);
    }

    public function convertToCode($name)
    {
        setlocale(LC_ALL, 'en_US.utf8');
        $name = iconv('utf-8', 'ascii//TRANSLIT', $name);
        $name = preg_replace('/[^a-zA-Z0-9\']/', '_', $name);
        $name = ltrim($name, '_');
        $code = preg_replace(['#\s#', '#-#', '#[^a-zA-Z0-9_\s]#'], ['_', '_', ''], strtolower($name));

        return $code;
    }

}
