<?php

namespace Webkul\DamBundle\Controller\Akeneo4;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Webkul\DamBundle\Entity\Asset; 
use Webkul\DamBundle\Repository\AssetRepository;
use Oro\Bundle\SecurityBundle\Annotation\AclAncestor;
use Symfony\Component\Validator\Constraints;
use Webkul\DamBundle\Entity\AssetMedia;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Doctrine\ORM\Tools\Pagination\Paginator;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Webkul\DamBundle\Services\DamServices;
use Webkul\DamBundle\Context\UserContext;

/**
 * Assets Controller
 *
 * @author    Aman Srivastav <aman.srivastava462@webkul.com>
 * @copyright 2019 Webkul Soft Pvt. Ltd (https://webkul.com/)
 */

class AssetsController extends Controller 
{
    /** @var DamServices */ 
    protected $damservices;
    
    /** @var AssetRepository */ 
    protected $assetrepository;
    
    /** @var UserContext */
    protected $usercontext; 

    /** @var FilesystemProvider */
    protected $filesystemprovider;

    /** @var FileStorer */
    protected $fileStorer; 

    /**
     * @param DamServices                           $damservices
     * @param AssetRepository                       $assetrepository
     * @param UserContext                           $usercontext
     * @param FilesystemProvider                    $filesystemprovider
     * @param FileStorer                            $fileStorer
     */
    public function __construct(
        DamServices $damservices,
        AssetRepository $assetrepository,
        UserContext $usercontext,
        \FilesystemProvider $filesystemprovider,
        \FileStorer $filestorer
    ) {
        $this->damservices = $damservices;
        $this->assetrepository = $assetrepository;
        $this->usercontext = $usercontext;
        $this->filesystemprovider = $filesystemprovider;
        $this->filestorer = $filestorer;
    }

    public function getAction()
    {
        return new JsonResponse([]);
    }

    public function getVersion(){
        if (class_exists('Akeneo\Platform\CommunityVersion')) {
            $versionClass = new \Akeneo\Platform\CommunityVersion();
        } elseif (class_exists('Pim\Bundle\CatalogBundle\Version')) {
            $versionClass = new \Pim\Bundle\CatalogBundle\Version();
        }
        $version = $versionClass::VERSION;
        return $version;
    }

    /**
     * @param Request $request
     *
     * @throws BadRequestHttpException
     *
     * @return Response
     *
     * @AclAncestor("webkul_dam_configuration")
     */
    public function saveAction(Request $request)
    {
        $data = $this->getDecodedContent($request->getContent());
        $defaultTimeZone = $this->usercontext->getUserTimezone();
        $data['default_timezone'] = $defaultTimeZone;
        if (array_key_exists('tag', $data)) {
            $this->damservices->saveTagAssociation($data);
        }

        if (array_key_exists('categories', $data)) {
            $this->damservices->saveCategoryAssociation($data);
        }
        $em = $this->getDoctrine()->getManager();

        if (!empty($data['code'])) {
            $asset = $this->assetrepository->findOneByCode($data['code']);
        }
        if (empty($asset)) {
            $asset = new Asset();
        } else {
            if (!($request->query->get('identifier'))) {
                return new JsonResponse(
                    $this->alreadyExistCode,
                    RESPONSE::HTTP_BAD_REQUEST
                );
            }
        }
        
        $form = $this->getAssetForm($asset);
        $form->submit($data);

        if ($form->isValid()) {
            $em->persist($asset);
            $em->flush();

            $assetMedias = !empty($data['medias']) ? $this->createMediasByAssetAndData($asset, $data['medias']) : [];
            foreach ($assetMedias as $assetMedia) {
                if ($assetMedia) {
                    $em->persist($assetMedia);
                }
            }
            foreach ($asset->getMedias() as $assetMedia) {
                if (!in_array($assetMedia, $assetMedias)) {
                    $em->remove($assetMedia);
                }
            }
            $em->flush();

            return new JsonResponse(['id' => $asset->getId(), 'code' => $asset->getCode() ]);
        } else {
            if ($request->query->get('identifier')) {
                $errors = $this->getFormErrors($form);
            } else {
                $errors = [ 'values' => $this->getJsFormErrors($form) ];
            }

            return new JsonResponse(
                $errors,
                RESPONSE::HTTP_BAD_REQUEST
            );
        }
    }

    /**
     * @param Request $request
     *
     * @throws BadRequestHttpException
     *
     * @return Response
     *
     * @AclAncestor("webkul_dam_configuration")
     */
    public function getAssetAction($identifier)
    {
        $asset = $this->assetrepository->getSingleArrayResultByCode($identifier);
        if ($asset['code']) {
            $tags = $this->damservices->getRelatedTagsOfAssets($asset['code']);
            if (!empty($tags)) {
                $asset['tag'] = $tags;
            }
            $categories = $this->damservices->getRelatedCategoriesOfAssets($asset['code']);
            if (!empty($categories)) {
                $asset['category'] = $categories;
            }
        }
       
        if (!$asset) {
            return new JsonResponse([], Response::HTTP_NOT_FOUND);
        }
 
        $fs = $this->filesystemprovider->getFilesystem('catalogStorage');
        if (get_class($fs->getAdapter()) == 'League\Flysystem\AwsS3v3\AwsS3Adapter') {
            $router = $this->get('router');
            foreach($asset['medias'] as $medKey => $medValue) {
                
                $awsService = $this->get('wk_aws_integration.service');
                $visibility = $awsService->getVisibilityByFileName($medValue['filePath']);
                $asset['medias'][$medKey]['visibility'] = $visibility['visibility'];
            }

        }

        return new JsonResponse($asset);
    }

    /**
     * @param Request $request
     *
     * @throws BadRequestHttpException
     *
     * @return Response
     *
     * @AclAncestor("webkul_dam_configuration")
     */
    public function deleteAction($code)
    {
        $em = $this->getDoctrine()->getManager();
        $asset = $this->assetrepository->findOneByCode($code);

        if ($asset) {
            foreach ($asset->getMedias() as $media) {
                $em->remove($media);
            }
            $em->remove($asset);
            $em->flush();
        }

        return new JsonResponse([]);
    }

    public function getAssetsAction(Request $request)
    {
        $identifiers = explode(',', $request->query->get('identifiers'));
        $em = $this->getDoctrine()->getManager();
        
        $assets = $this->assetrepository->getArrayResultsByIdentifiers($identifiers);
        
        return new JsonResponse($assets);
    }

    protected function getAssetForm($entity = null)
    {
        $form = $this->createFormBuilder($entity, [
                    'allow_extra_fields' => true,
                    'csrf_protection' => false
                ]);

        foreach ($this->getAssetFields() as $field => $constraints) {
            $form->add($field, null, [
                'constraints' => $constraints
            ]);
        }

        return $form->getForm();
    }

    protected function getFormErrors($form)
    {
        $errorContext = [];
        foreach ($form->getErrors(true) as $key => $error) {
            $errorContext[$error->getOrigin()->getName()] = $error->getMessage();
        }

        return $errorContext;
    }

    protected function getJsFormErrors($form)
    {
        $errorContext = [];
        foreach ($form->getErrors(true) as $key => $error) {
            $errorContext[] = [
                'message' => $error->getMessage(),
                'path' => $error->getOrigin()->getName(),
            ];
        }

        return $errorContext;
    }

    protected function getAssetFields()
    {
        return [
            'code' => [
                new Constraints\Regex([
                    'pattern' => '/^[a-zA-Z0-9_]+$/i',
                    'htmlPattern' => '^[a-zA-Z0-9_]+$',
                    'message' => 'Asset code may contain only letters, numbers and underscore.',
                    'match'   => true
                ]),
                new Constraints\NotBlank(),
            ],
            'description' => [ new Constraints\Optional() ],
            'starred' => [ new Constraints\Optional() ],
            'title' => [ new Constraints\Optional() ],
            'alt' => [ new Constraints\Optional() ],
            'expiration_date' => [ new Constraints\Optional() ],
            'default_timezone' => [ new Constraints\Optional() ]
        ];
    }

    /**
     * Get the JSON decoded content. If the content is not a valid JSON, it throws an error 400.
     *
     * @param string $content content of a request to decode
     *
     * @throws BadRequestHttpException
     *
     * @return array
     */
    protected function getDecodedContent($content)
    {
        $decodedContent = json_decode($content, true);

        if (null === $decodedContent) {
            throw new BadRequestHttpException('Invalid json message received');
        }

        return $decodedContent;
    }
    
    protected function createMediasByAssetAndData(Asset $asset, $data)
    {
        if (isset($data['data']) || !empty($data)) {
            $imageData = isset($data['data']) ? $data['data']
                                              : (!empty($data) ? $data : []) ;
        }
        if ($this->isAssoc($imageData)) {
            $imageData = [ $imageData ];
        }

      
        $assetMedias = [];
        foreach ($imageData as $data) {
            $assetMedia = null;
            if (isset($data['id'])) {
                $assetMedia = $this->getDoctrine()->getRepository('WebkulDamBundle:AssetMedia')->findOneById($data['id']);
            } elseif (!empty($data['filePath']) && !empty($data['originalFilename'])) {
                if (!$assetMedia) {
                    $assetMedia = $this->getDoctrine()->getRepository('WebkulDamBundle:AssetMedia')->findOneBy(["filePath" => $data['filePath']]);
                }
                
                if (!$assetMedia) {
                    $assetMedia = new AssetMedia();
                }
                if (isset($data['locale'])) {
                    $assetMedia->setLocale($data['locale']);
                }
                $assetMedia->setOriginalFilename($data['originalFilename']);
                $assetMedia->setFilePath($data['filePath']);
                $assetMedia->setAsset($asset);
            }
            if ($assetMedia) {
                $assetMedias[] = $assetMedia;
            }
        }

        return $assetMedias;
    }
     
    public function isAssoc(array $arr)
    {
        if (array() === $arr) {
            return false;
        }
        return array_keys($arr) !== range(0, count($arr) - 1);
    }
    public function addTagAction(Request $request)
    {
        $params = $request->request->all() ? : json_decode($request->getContent(), true);
        
        if ($request->getMethod() == 'POST') {
            $this->damservices->saveTags($params);
        }
        return new JsonResponse(['nsvksbhsdibvhjx']);
    }
     
    public function getTagAction()
    {
        $tags = $this->damservices->getAllTag();

        return new JsonResponse($tags);
    }

    public function editMediaAction(Request $request)
    {
        $url = $request->query->get('url');
        $code = $request->query->get('code');
        $filePath = $request->query->get('filePath');
        $router = $this->get('router');
        $url = $router->generate('webkuldam_media_download', [
            'identifier' => rawurlencode($filePath)
        ], UrlGeneratorInterface::ABSOLUTE_URL);
        $url = str_replace("%2f", "%252F", $url);
        
        $host = $request->getSchemeAndHttpHost();
        
        $version = $this->getVersion();
        if($version > '3.0' && $version < '4.0'){
            return $this->render('WebkulDamBundle:Media:edit.html.twig', array(
                'url' => $url,
                'host' => $host,
                'code' => $code,
                'filePath' => $filePath,
                'nounce' => false
            ));
        }else{
            return $this->render('@WebkulDamMedia/edit.html.twig', array(
                'url' => $url,
                'host' => $host,
                'code' => $code,
                'filePath' => $filePath,
                'nounce' => true
            ));
        }
    }

    public function editorMediaAction()
    {
        $version = $this->getVersion();
        if($version > '3.0' && $version < '4.0'){
            return $this->render('WebkulDamBundle:Media:editor.html.twig', array(
                'nounce' => false
            ));
        }else{
            return $this->render('@WebkulDamMedia/editor.html.twig', array(
                'nounce' => true
            ));
        }
    }

    public function saveMediaAction(Request $request)
    {
        $params = $request->request->all() ? $request->request->all() : json_decode($request->getContent(), true);
    
        $checkMedia = $this->damservices->getMediaByFilepath($params['filePath']);
        
        $fsc = $this->filesystemprovider->getFilesystem(\FileStorage::CATALOG_STORAGE_ALIAS);
        $em = $this->getDoctrine()->getManager();
        if ($checkMedia) {
            $originalName = $checkMedia->getOriginalFilename();
            $img = $params['url'];
            $img = str_replace('data:image/png;base64,', '', $img);
            $img = str_replace(' ', '+', $img);
            $data = base64_decode($img);
            $oldPath = $params['filePath'];
            $filePath = pathinfo($params['filePath']);
            $filePath = $filePath['dirname'] . '/' . $originalName;
            $fsc->put($filePath, $data);
            $newFilePath = $fsc->getAdapter()->getPathPrefix() . $filePath;
            $uploadedFile = $this->postMedia($newFilePath, $originalName);
            $checkMedia->setFilePath($uploadedFile->getKey());
            $fsc->delete($oldPath);
            $em->persist($checkMedia);
        }
        $em->flush();
        return new Response('success');
    }

    protected function postMedia($filePath, $originalName)
    {
        $filename = explode('/', $filePath);
        $fname = end($filename);

        $file = new UploadedFile(
            implode('/', $filename),
            $fname,
            mime_content_type($filePath),
            filesize($filePath),
            null,
            false
        );

        $uploadedFile = $this->storeFile($file);

        return $uploadedFile;
    }
    /**
     * @param uploadedFile $uploadedFile
     * @return fileData
     */
    protected function storeFile(UploadedFile $uploadedFile)
    {
        return $this->filestorer->store($uploadedFile, \FileStorage::CATALOG_STORAGE_ALIAS);
    }

    public function checkCredentialAction(Request $request)
    {
        $data = $this->getDecodedContent($request->getContent());
    
        return $this->damservices->connectFtp($data);
    }

    public function getDirectoryAction(Request $request)
    {
        $identifier = $request->query->get('options')['idenitifer'];
        

        return $this->damservices->getDirectories($identifier);
    }

    public function getAssetListAction()
    {
        return $this->damservices->getAllAssetCode();
    }

    public function getListCategoriesAction()
    {
        return $this->damservices->getAllCategories();
    }

    protected $alreadyExistCode = [
                "values"=>
                    [
                        [
                            "attribute" => "code",
                            "locale" => null,
                            "scope" => null,
                            "message" => "The same identifier is already set on another asset"
                        ]
                    ]
        ];
}
