<?php
/**
 * @author 1902 Software
 * @copyright Copyright © 2023 1902 Software (https://1902software.com/magento/)
 * @package WriteTextAI_WriteTextAI
 */

namespace WriteTextAI\WriteTextAI\Controller\Adminhtml\Grid;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Controller\ResultFactory;
use WriteTextAI\WriteTextAI\Helper\Image;
use Magento\Catalog\Helper\Image as ImageHelper;
use WriteTextAI\WriteTextAI\Helper\Product;
use Magento\Framework\UrlInterface;
use Magento\Framework\HTTP\PhpEnvironment\RemoteAddress;
use WriteTextAI\WriteTextAI\ViewModel\Settings;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory;
use WriteTextAI\WriteTextAI\Helper\Store as StoreHelper;
use Magento\Catalog\Model\Product\Media\Config as MediaConfig;

class UploadImages extends Action
{
    /**
     * @var Image
     */
    protected $imageHelper;

    /**
     * @var ImageHelper
     */
    protected $magentoImageHelper;

    /**
     * @var Product
     */
    protected $productHelper;

    /**
     * @var UrlInterface
     */
    protected $urlBuilder;

    /**
     * @var RemoteAddress
     */
    protected $remoteAddress;

    /**
     * @var Settings
     */
    protected $settings;

    /**
     * @var ProductCollectionFactory
     */
    protected $productCollectionFactory;

    /**
     * @var StoreHelper
     */
    protected $storeHelper;

    /**
     * @var MediaConfig
     */
    protected $mediaConfig;

    /**
     * @var array
     */
    protected $products = [];

    /**
     * Constructor
     *
     * @param Context $context
     * @param Image $imageHelper
     * @param ImageHelper $magentoImageHelper
     * @param Product $productHelper
     * @param UrlInterface $urlBuilder
     * @param RemoteAddress $remoteAddress
     * @param Settings $settings
     * @param ProductCollectionFactory $productCollectionFactory
     * @param StoreHelper $storeHelper
     * @param MediaConfig $mediaConfig
     */
    public function __construct(
        Context $context,
        Image $imageHelper,
        ImageHelper $magentoImageHelper,
        Product $productHelper,
        UrlInterface $urlBuilder,
        RemoteAddress $remoteAddress,
        Settings $settings,
        ProductCollectionFactory $productCollectionFactory,
        StoreHelper $storeHelper,
        MediaConfig $mediaConfig
    ) {
        $this->imageHelper = $imageHelper;
        $this->magentoImageHelper = $magentoImageHelper;
        $this->productHelper = $productHelper;
        $this->urlBuilder = $urlBuilder;
        $this->remoteAddress = $remoteAddress;
        $this->settings = $settings;
        $this->productCollectionFactory = $productCollectionFactory;
        $this->storeHelper = $storeHelper;
        $this->mediaConfig = $mediaConfig;
        parent::__construct($context);
    }

    /**
     * Execute action
     *
     * @return \Magento\Framework\Controller\Result\Json
     */
    public function execute()
    {
        $response = $this->resultFactory->create(ResultFactory::TYPE_JSON);
        $params = $this->getRequest()->getPost();
        $language = $this->storeHelper->getFormattedLanguage($params['store_id']);
        $ipAddress = $this->remoteAddress->getRemoteAddress();

        try {
            $images = $this->uploadImages(
                $params['store_id'],
                $language,
                $ipAddress,
                $params['images'] ?? []
            );
            $failedImages = $images['failed_images'] ?? [];
            $successImages = $images['success_images'] ?? [];
            $failedImageIds = $images['failed_image_ids'] ?? [];
            $failedImagesGrouped = $images['failed_images_grouped'] ?? [];
            $invalid = $images['invalid'] ?? [];
            $notSupported = $images['not_supported'] ?? [];
            $downloadFailed = $images['download_failed'] ?? [];
            $general = $images['general'] ?? [];
            $errorMessages = $images['error_messages'] ?? [];

            $result = [
                'success' => true,
                'failed_images' => $failedImages,
                'failed_image_ids' => $failedImageIds,
                'success_images' => $successImages,
                'failed_images_grouped' => $failedImagesGrouped,
                'invalid' => $invalid,
                'not_supported' => $notSupported,
                'download_failed' => $downloadFailed,
                'general' => $general,
                'error_messages' => $errorMessages
            ];
        } catch (\WriteTextAI\WriteTextAI\Exception\UnauthorizedException $e) {
            $result = [
                'success' => false,
                'unauthorized' => true,
                'login_url' => $this->urlBuilder->getUrl('wtai/setup/index'),
                'message' => $e->getMessage()
            ];
        } catch (\Exception $e) {
            $message = $e->getMessage();
            if (!$message) {
                $message = __(
                    'A system error has occurred. Please try again. If the issue persists,'
                    . ' please contact our support team at support@writetext.ai.'
                );
            }

            $result = [
                'success' => false,
                'message' => $message
            ];
        }

        $response->setData($result);

        return $response;
    }
    
    /**
     * Upload images to api
     *
     * @param int $storeId
     * @param string $language
     * @param string $ipAddress
     * @param array $images
     *
     * @return array
     */
    private function uploadImages(
        $storeId,
        $language,
        $ipAddress,
        $images
    ) {
        $successImages = [];
        $failedImages = [];
        $failedImageIds = [];

        if (empty($images)) {
            return [
                'success_images' => [],
                'failed_images' => [],
                'failed_image_ids' => [],
                'failed_images_grouped' => [],
                'invalid' => [],
                'not_supported' => [],
                'download_failed' => [],
                'general' => [],
                'error_messages' => [],
            ];
        }

        $this->collectProducts(array_column($images, 'entityId'), $storeId);

        foreach ($images as $image) {
            try {
                if (isset($this->products[$image['entityId']])) {
                    $product = $this->products[$image['entityId']];
                } else {
                    $product = $this->productHelper->getProduct($image['entityId'], $storeId);
                }
                
                $imageFileData = $this->getImageFile($product, $image['image']);
                $imageFile = $imageFileData['file'] ?? '';
                $imageFilePreview = $this->magentoImageHelper->init(
                    $product,
                    'product_listing_thumbnail_preview'
                )->setImageFile($imageFile);
                $url = $imageFilePreview->getUrl();
                $originalUrl = $imageFileData['noncached_url'] ?? '';
                $imageFileThumbnail = $this->magentoImageHelper->init(
                    $product,
                    'product_listing_thumbnail'
                )->setImageFile($imageFile);
                $thumbnailUrl = $imageFileThumbnail->getUrl();
                if ($url !== $imageFilePreview->getDefaultPlaceholderUrl()) {
                    $successImages[] = $this->imageHelper->getImageApiId(
                        $storeId,
                        $ipAddress,
                        $language,
                        $image['image'],
                        $url
                    );
                }
            } catch (\WriteTextAI\WriteTextAI\Exception\ImageUnsupported $e) {
                $failedUrl = $originalUrl ?: $thumbnailUrl;
                $failedImages[] = $failedUrl;
                $failedImageIds[] = $image['image'];
                $failedImagesGrouped[$e->getMessage()]['message'] = $e->getMessage();
                $failedImagesGrouped[$e->getMessage()][$image['image']]['id'] = $image['image'];
                $failedImagesGrouped[$e->getMessage()][$image['image']]['url'] = $failedUrl;
                $notSupported[] = [
                    'id' => $image['image'],
                    'url' => $failedUrl
                ];
                $errorMessages['not_supported'] = $e->getMessage();
            } catch (\WriteTextAI\WriteTextAI\Exception\ImageInvalid $e) {
                $failedUrl = $originalUrl ?: $thumbnailUrl;
                $failedImages[] = $failedUrl;
                $failedImageIds[] = $image['image'];
                $failedImagesGrouped[$e->getMessage()]['message'] = $e->getMessage();
                $failedImagesGrouped[$e->getMessage()]['images'][$image['image']]['id'] = $image['image'];
                $failedImagesGrouped[$e->getMessage()]['images'][$image['image']]['url'] = $failedUrl;
                $invalid[] = [
                    'id' => $image['image'],
                    'url' => $failedUrl
                ];
                $errorMessages['invalid'] = $e->getMessage();
            } catch (\WriteTextAI\WriteTextAI\Exception\ImageDownloadFailed $e) {
                $failedUrl = $originalUrl ?: $thumbnailUrl;
                $failedImages[] = $failedUrl;
                $failedImageIds[] = $image['image'];
                $failedImagesGrouped[$e->getMessage()]['message'] = $e->getMessage();
                $failedImagesGrouped[$e->getMessage()]['images'][$image['image']]['id'] = $image['image'];
                $failedImagesGrouped[$e->getMessage()]['images'][$image['image']]['url'] = $failedUrl;
                $downloadFailed[] = [
                    'id' => $image['image'],
                    'url' => $failedUrl
                ];
                $errorMessages['download_failed'] = $e->getMessage();
            } catch (\Exception $e) {
                $failedUrl = $originalUrl ?: $thumbnailUrl;
                $failedImages[] = $failedUrl;
                $failedImageIds[] = $image['image'];
                $failedImagesGrouped['general']['message'] = $e->getMessage();
                $failedImagesGrouped['general']['images'][$image['image']]['id'] = $image['image'];
                $failedImagesGrouped['general']['images'][$image['image']]['url'] = $failedUrl;
                $general[] = [
                    'id' => $image['image'],
                    'url' => $failedUrl
                ];
                $errorMessages['general'] = $e->getMessage();
            }
        }

        return [
            'success_images' => $successImages ?? [],
            'failed_images' => $failedImages ?? [],
            'failed_image_ids' => $failedImageIds ?? [],
            'failed_images_grouped' => $failedImagesGrouped ?? [],
            'invalid' => $invalid ?? [],
            'not_supported' => $notSupported ?? [],
            'download_failed' => $downloadFailed ?? [],
            'general' => $general ?? [],
            'error_messages' => $errorMessages ?? []
        ];
    }

    /**
     * Collect products
     *
     * @param array $productIds
     * @param int $storeId
     * @return void
     */
    private function collectProducts($productIds, $storeId)
    {
        $this->products = [];

        $collection = $this->productCollectionFactory->create();
        $collection->setStoreId($storeId);
        $collection->addFieldToFilter('entity_id', ['in' => $productIds])
            ->addMediaGalleryData();

        foreach ($collection as $product) {
            $this->products[$product->getId()] = $product;
        }
    }

    /**
     * Get image file
     *
     * @param \Magento\Catalog\Api\Data\ProductInterface $product
     * @param string $imageId
     * @return string
     */
    private function getImageFile($product, $imageId)
    {
        $mediaGallery = $product->getMediaGalleryImages();
        
        if (!empty($mediaGallery)) {
            foreach ($mediaGallery as $mediaGalleryEntry) {
                if ($mediaGalleryEntry->getId() === $imageId) {
                    $file = $mediaGalleryEntry->getFile();
                    return [
                        'file' => $file,
                        'noncached_url' => $this->mediaConfig->getMediaUrl($file)
                    ];
                }
            }
        }

        return [
            'file' => '',
            'noncached_url' => ''
        ];
    }
}
