<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonPickwareMobile\Subscribers\Api;

use Shopware\Plugins\ViisonCommon\Classes\Subscribers\Base;
use Shopware\Plugins\ViisonCommon\Classes\Util\Util as ViisonCommonUtil;
use Shopware\Components\Api\Manager as ResourceManager;
use Symfony\Component\HttpFoundation\FileBag;

class MediaSubscriber extends Base
{
    /**
     * @var array $fileExtensionWhitelist
     */
    private $fileExtensionWhitelist = [
        'png',
        'jpg',
        'jpeg',
        'gif',
        'pdf',
    ];

    /**
     * @see \Shopware\Plugins\ViisonCommon\Classes\Subscribers\Base::getSubscribedEvents()
     */
    public static function getSubscribedEvents()
    {
        return [
            'Shopware_Controllers_Api_Media::postAction::before' => 'onBeforePostAction',
            'Shopware_Controllers_Api_Media::postAction::after' => 'onAfterPostAction',
        ];
    }

    /**
     * Checks the request for a POSTed 'userId' and, if none is set, sets the ID of the
     * requesting user as the 'userId' parameter.
     *
     * @param \Enlight_Hook_HookArgs $args
     */
    public function onBeforePostAction(\Enlight_Hook_HookArgs $args)
    {
        $request = $args->getSubject()->Request();
        // Check for posted file data, if the Shopware version is < 5.2.4 (starting from Shopware v5.2.4, the
        // REST API uploads the file itself)
        // Following our style guide, the $_FILES global is not allowed and hence must be ignored!
        // phpcs:ignore MySource.PHP.GetRequestData
        if (!ViisonCommonUtil::assertMinimumShopwareVersion('5.2.4') && $_FILES['file'] !== null) {
            // Move the uploaded file and add the new file path to the request
            $file = $this->moveUploadedFile($_FILES['file']); // @codingStandardsIgnoreLine ; $_FILES not allowed
            $request->setPost('file', $file->getPathName());
        }

        // Make sure a user is selected
        $userId = $request->getParam('userId');
        if (empty($userId)) {
            $request->setPost('userId', $this->get('auth')->getIdentity()->id);
        }
    }

    /**
     * Checks the data assigned to the view for success and, in case the original action was
     * successful, adds detailed data of the created media entity to the response.
     *
     * @param \Enlight_Hook_HookArgs $args
     */
    public function onAfterPostAction(\Enlight_Hook_HookArgs $args)
    {
        // Try to get the ID of the created media
        $responseData = $args->getSubject()->View()->data;
        if (!is_array($responseData) || $responseData['id'] === null) {
            return;
        }

        // Add more data of the created media entity to the response
        $resource = ResourceManager::getResource('media');
        $responseData += $resource->getOne($responseData['id']);
        $args->getSubject()->View()->data = $responseData;
    }

    /**
     * Checks the passed $uploadedFile array for errors and, if none exist, moves the
     * file to a new location using Symfony's FileBag and returns the created UploadedFile
     * instance.
     *
     * @param array $uploadedFile
     * @param \Symfony\Component\HttpFoundation\File\UploadedFile
     * @throws \Exception
     */
    private function moveUploadedFile(array $uploadedFile)
    {
        if ($uploadedFile['error'] !== UPLOAD_ERR_OK) {
            throw new \Exception(
                sprintf('Could not upload file "%s"', $uploadedFile['name'])
            );
        }

        // Load the file and check its type
        $fileBag = new FileBag($_FILES); // @codingStandardsIgnoreLine ; $_FILES not allowed
        $file = $fileBag->get('file');
        $fileInfo = pathinfo($file->getClientOriginalName());
        if (!in_array(mb_strtolower($fileInfo['extension']), $this->fileExtensionWhitelist)) {
            throw new \Exception(
                sprintf('The type of the uploaded file "%s" is not supported', $uploadedFile['name'])
            );
        }

        // Rename the uploaded file in its tmp directory to achieve that the media entry
        // has the correct file name. This is necessary because of the bhaviour of
        // Shopware\Models\Media\Media::setFileInfo, which can only use the real file
        // name, if it has a Symfony\Component\HttpFoundation\File\UploadedFile instance.
        // However, the private method Shopware\Components\Api\Resource\Media::prepareMediaData
        // creates only a general Symfony\Component\HttpFoundation\File\File instance,
        // which results in using the temporary PHP file name instead of the uploaded file name.

        // @codingStandardsIgnoreLine ; sys_get_temp_dir() not allowed
        $file = $file->move(sys_get_temp_dir(), $file->getClientOriginalName());

        return $file;
    }
}
