<?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\ViisonCommon\Classes\Installation\MediaAlbum;

use DateTime;
use Exception;
use Doctrine\ORM\EntityManager;
use InvalidArgumentException;
use LogicException;
use RuntimeException;
use Shopware\Components\Thumbnail\Manager as ThumbnailManager;
use Shopware\Models\Media;
use Shopware\Plugins\ViisonCommon\Classes\Exceptions\FileSystemExceptions\FileNotReadableException;
use Shopware\Plugins\ViisonCommon\Classes\Exceptions\FileSystemExceptions\FileNotWritableException;
use Shopware\Plugins\ViisonCommon\Classes\Util\Util as ViisonCommonUtil;
use Symfony\Component\HttpFoundation\File\File;

class InstallationHelper
{
    /**
     * @var EntityManager $entityManager
     */
    private $entityManager;

    /**
     * @var ThumbnailManager|null
     */
    private $thumbnailManager;

    /**
     * @param EntityManager $entityManager
     * @param ThumbnailManager|null $thumbnailManager
     */
    public function __construct(EntityManager $entityManager, $thumbnailManager = null)
    {
        $this->entityManager = $entityManager;
        $this->thumbnailManager = $thumbnailManager;
    }

    /**
     * Creates a new media album with the given name and icon class unless an album with
     * the same name already exists (regardless of differences in other properties).
     *
     * @param string $name
     * @param string $iconClass
     * @param int $position (optional, defaul 0)
     * @param string $thumbnailSize (optional, default '140x140')
     * @param integer $thumbnailQuality JPEG image quality for thumbnails created from JPEGs (optinal, valid values:
     *     1-100, default: 100)
     * @param boolean $createHighDpiThumbnails (optinal, default: true)
     * @return Media\Album The already existing or newly created album
     */
    public function createMediaAlbumUnlessExists(
        $name,
        $iconClass,
        $position = 0,
        $thumbnailSize = '140x140',
        $thumbnailQuality = 100,
        $createHighDpiThumbnails = true
    ) {
        // Try to find an album with the same name
        /** @var Media\Album $existingAlbum */
        $existingAlbum = $this->entityManager->getRepository('Shopware\\Models\\Media\\Album')->findOneBy([
            'name' => $name,
        ]);
        if ($existingAlbum) {
            return $existingAlbum;
        }

        // Create media settings
        $settings = new Media\Settings();
        $settings->setIcon($iconClass);
        $settings->setThumbnailSize($thumbnailSize);
        $settings->setCreateThumbnails(true);
        $settings->setThumbnailQuality($thumbnailQuality);
        $settings->setThumbnailHighDpiQuality($thumbnailQuality);
        $settings->setThumbnailHighDpi($createHighDpiThumbnails);

        // Create media album
        $album = new Media\Album();
        $album->setName($name);
        $album->setPosition($position);

        // Assign settings to album and vice versa
        $album->setSettings($settings);
        $settings->setAlbum($album);

        // Save changes
        $this->entityManager->persist($album);
        $this->entityManager->flush($album);

        return $album;
    }

    /**
     * Add an image from its path to a given album.
     *
     * @param string $imagePath
     * @param Media\Album $album
     * @return Media\Media
     * @throws InvalidArgumentException if the $imagePath points to a file that does not have a supported image format.
     * @throws Exception if the method is called on an instance that was created without passing a ThumbnailManager.
     */
    public function addImageByPathToAlbum($imagePath, Media\Album $album)
    {
        if (!$this->thumbnailManager) {
            throw new LogicException(sprintf(
                'Cannot call "%s()" without providing a valid ThumbnailManager upon constructing the receiver.',
                __METHOD__
            ));
        }

        // Shopware versions prior to 5.2.27 would always delete the file after adding it to the media library, which
        // kind of breaks the assumed contract of this method. Because of this, make a temporary copy of the file
        // $imagePath and add that to the media library instead when running on Shopware versions that delete the file.
        $imagePathForMedia = $imagePath;
        if (!ViisonCommonUtil::assertMinimumShopwareVersion('5.2.27')) {
            $imagePathForMedia = sprintf('%s/%s', ViisonCommonUtil::getTempDir(), basename($imagePath));
            if (!is_readable($imagePath)) {
                throw new FileNotReadableException($imagePath);
            }
            $fileCopiedSuccessfully = copy($imagePath, $imagePathForMedia);
            if (!$fileCopiedSuccessfully) {
                throw new FileNotWritableException($imagePathForMedia);
            }
        }

        $media = new Media\Media();
        $media->setFile(new File($imagePathForMedia));

        // .tif and .tiff images are not supported since the php gd extension does not support tifs.
        if ($media->getType() !== Media\Media::TYPE_IMAGE || in_array($media->getExtension(), ['tif', 'tiff'])) {
            throw new RuntimeException('The file cannot be added to a media album since its type is not supported.');
        }

        $media->setAlbum($album);
        $media->setDescription('');
        $media->setCreated(new DateTime());
        $media->setUserId(0);

        $this->entityManager->persist($media);
        $this->entityManager->flush($media);

        $this->thumbnailManager->createMediaThumbnail($media, [], true);

        return $media;
    }
}
