<?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\Components;

use Doctrine\DBAL\Connection as DBALConnection;
use Shopware\Bundle\MediaBundle\MediaService;
use Shopware\Bundle\StoreFrontBundle\Service\Core\ContextService;
use Shopware\Bundle\StoreFrontBundle\Service\Core\MediaService as StoreFrontMediaService;
use Shopware\Bundle\StoreFrontBundle\Struct\BaseProduct;
use Shopware\Bundle\StoreFrontBundle\Struct\Media;
use Shopware\Components\Model\ModelManager;

class ImageService
{
    /**
     * @var DBALConnection
     */
    private $connection;

    /**
     * @var ModelManager
     */
    private $entityManager;

    /**
     * @var ContextService
     */
    private $contextService;

    /**
     * @var StoreFrontMediaService
     */
    private $storeFrontMediaService;

    /**
     * @var MediaService
     */
    private $mediaService;

    /**
     * @param DBALConnection $connection
     * @param ModelManager $entityManager
     * @param ContextService $contextService
     * @param StoreFrontMediaService $storeFrontMediaService
     * @param MediaService $mediaService
     */
    public function __construct($connection, $entityManager, $contextService, $storeFrontMediaService, $mediaService)
    {
        $this->connection = $connection;
        $this->entityManager = $entityManager;
        $this->contextService = $contextService;
        $this->storeFrontMediaService = $storeFrontMediaService;
        $this->mediaService = $mediaService;
    }

    /**
     * Finds all images associated with any of the given article detail ids.
     *
     * @param int[] $articleDetailIds
     * @return Media[]
     */
    public function getVariantImages(array $articleDetailIds)
    {
        if (empty($articleDetailIds)) {
            return [];
        }

        // Create store front products
        $productData = $this->connection->fetchAll(
            'SELECT
                id AS articleDetailId,
                articleID AS articleId,
                ordernumber AS number
            FROM s_articles_details
            WHERE id IN (:articleDetailIds)',
            [
                'articleDetailIds' => $articleDetailIds,
            ],
            [
                'articleDetailIds' => \Doctrine\DBAL\Connection::PARAM_INT_ARRAY,
            ]
        );
        $products = array_map(
            function (array $row) {
                return new BaseProduct(
                    $row['articleId'],
                    $row['articleDetailId'],
                    $row['number']
                );
            },
            $productData
        );

        // Build shop context
        $shop = $this->entityManager->getRepository('Shopware\\Models\\Shop\\Shop')->getActiveDefault();
        $context = $this->contextService->createShopContext(
            $shop->getId(),
            $shop->getCurrency()->getId(),
            ContextService::FALLBACK_CUSTOMER_GROUP
        );

        // Use the media service to get the images for all article details
        $result = $this->storeFrontMediaService->getProductsMedia($products, $context);

        $groupedResult = [];
        foreach ($products as $product) {
            $groupedResult[$product->getVariantId()] = [];
            if (!isset($result[$product->getNumber()])) {
                continue;
            }

            foreach ($result[$product->getNumber()] as $image) {
                $groupedResult[$product->getVariantId()][] = $image;
            }
        }

        return $groupedResult;
    }

    /**
     * Finds the image URL for the given $image with respect to the given $minWidth and $minHeight. If image/thumbnail
     * satisfies the size constraints, the smallest one is returned.
     *
     * @param Media $image
     * @param int $minWidth
     * @param int $minHeight
     * @return string|null
     */
    public function findImageUrlForSize(Media $image, $minWidth, $minHeight)
    {
        $imageUrl = null;
        $bestSize = null;

        // Check whether the main image satisfies the constraints
        if ($image->getWidth() >= $minWidth && $image->getHeight() >= $minHeight) {
            $imageUrl = $image->getFile();
            $bestSize = [
                $image->getWidth(),
                $image->getHeight(),
            ];
        }

        // Check whether any of the thumbnails meet the constraints and is smaller than the currently selected image
        foreach ($image->getThumbnails() as $thumbnail) {
            if ($thumbnail->getMaxWidth() < $minWidth || $thumbnail->getMaxHeight() < $minHeight) {
                // Image too small
                continue;
            }
            if (!$bestSize || $thumbnail->getMaxWidth() < $bestSize[0] || $thumbnail->getMaxHeight() < $bestSize[1]) {
                // Found better size
                $imageUrl = $thumbnail->getSource();
                $bestSize = [
                    $thumbnail->getMaxWidth(),
                    $thumbnail->getMaxHeight(),
                ];
            }
        }

        return $imageUrl;
    }

    /**
     * Returns the data uri for an image given by its path.
     *
     * @param string $imagePath
     * @return string The given image as a data URI, or the empty string if it cannot be found. This makes the return
     *         value of this method safe to insert in an <img> tag's src attribute in either case.
     */
    public function getImageAsDataUri($imagePath)
    {
        if ($this->mediaService->has($imagePath)) {
            $imageString = base64_encode($this->mediaService->read($imagePath));

            return 'data:image/' .  pathinfo($imagePath)['extension'] . ';base64,' . $imageString;
        }

        return '';
    }
}
