<?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\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\Controller\ResultFactory;
use Magento\Ui\Component\MassAction\Filter;
use WriteTextAI\WriteTextAI\Model\GeneratedText;
use Magento\Store\Model\Store;
use WriteTextAI\WriteTextAI\Helper\Product as ProductHelper;
use WriteTextAI\WriteTextAI\Model\ApiManager;
use Magento\Catalog\Api\ProductRepositoryInterface;
use WriteTextAI\WriteTextAI\Helper\Store as StoreHelper;

class Transferable extends Action implements HttpPostActionInterface
{
    public const ADMIN_RESOURCE = 'WriteTextAI_WriteTextAI::transfer';

    /**
     * @var GeneratedText
     */
    protected $generatedText;

    /**
     * @var Filter
     */
    protected $filter;

    /**
     * @var CollectionFactory
     */
    protected $collectionFactory;

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

    /**
     * @var ApiManager
     */
    protected $apiManager;

    /**
     * @var ProductRepositoryInterface
     */
    protected $productRepository;

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

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

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

    /**
     * Constructor
     *
     * @param Context $context
     * @param GeneratedText $generatedText
     * @param Filter $filter
     * @param CollectionFactory $collectionFactory
     * @param ProductHelper $productHelper
     * @param ApiManager $apiManager
     * @param ProductRepositoryInterface $productRepository
     * @param StoreHelper $storeHelper
     */
    public function __construct(
        Context $context,
        GeneratedText $generatedText,
        Filter $filter,
        CollectionFactory $collectionFactory,
        ProductHelper $productHelper,
        ApiManager $apiManager,
        ProductRepositoryInterface $productRepository,
        StoreHelper $storeHelper
    ) {
        $this->generatedText = $generatedText;
        $this->filter = $filter;
        $this->collectionFactory = $collectionFactory;
        $this->productHelper = $productHelper;
        $this->apiManager = $apiManager;
        $this->productRepository = $productRepository;
        $this->storeHelper = $storeHelper;
        parent::__construct($context);
    }

    /**
     * Execute
     *
     * @return \Magento\Framework\Controller\Result\Json
     */
    public function execute()
    {
        $result = $this->resultFactory->create(ResultFactory::TYPE_JSON);
        $batchSize = 50;
        try {
            $fields = $this->getRequest()->getPost('fields', []);
            $filters = $this->getRequest()->getPost('filters', []);

            $storeFilter = isset($filters['store_id']) ? $filters['store_id'] : Store::DEFAULT_STORE_ID;
            $collection = $this->filter->getCollection($this->collectionFactory
                ->create()
                ->addAttributeToSelect('*'))
                ->setStoreId($storeFilter)
                ->addMediaGalleryData();
            $resultData = [
                'success' => false,
                'message' => __(
                    'Transfer failed because there are no generated' .
                    ' texts yet for the products selected.' .
                    ' Generate text first before transferring.'
                )
            ];

            $this->collectProducts($collection, $storeFilter);
            $transferableFound = false;

            //check if collection has any products
            if ($collection->getSize() == 0) {
                $resultData = [
                    'success' => false,
                    'message' => __('No products found')
                ];
                $result->setData($resultData);
                return $result;
            }

            // Convert collection to array for batch processing
            $collectionArray = $collection->getItems();
            $totalProducts = count($collectionArray);
            
            // Process in batches of 50
            for ($i = 0; $i < $totalProducts; $i += $batchSize) {
                $batch = array_slice($collectionArray, $i, $batchSize, true);
                
                // Get generated text for current batch
                $batchIds = array_keys($batch);
                $implodedBatchIds = implode(',', $batchIds);
                $generatedText = $this->generatedText->getGenerated($implodedBatchIds, $storeFilter);
                
                foreach ($batch as $product) {
                    $item = $this->generatedText->getTextFields(
                        $product->getId(),
                        $storeFilter,
                        false,
                        $generatedText
                    );

                    $hasTransferableContent = $this->hasTransferableContent(
                        $item,
                        $fields,
                        $product->getId(),
                        $storeFilter
                    );

                    if (in_array('alt_text', $fields)) {
                        $this->addProductImage($product->getId(), $storeFilter);
                    }
                    
                    if ($hasTransferableContent) {
                        $resultData = [
                            'success' => true,
                        ];

                        break 2; // Break out of both loops
                    }
                }
            }

            if (in_array('alt_text', $fields)) {
                //check if image list is not empty
                $hasTransferableImage = $this->hasTransferableImage($storeFilter);
                if ($hasTransferableImage) {
                    $resultData = [
                        'success' => true,
                    ];
                }
            }
            $result->setData($resultData);
        } 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->setData([
                'success' => false,
                'message' => $message
            ]);
        }

        return $result;
    }

    /**
     * Collect products
     *
     * @param \Magento\Catalog\Model\ResourceModel\Product\Collection $collection
     * @param int $storeId
     * @return void
     */
    private function collectProducts($collection, $storeId)
    {
        $this->products = [];

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

    /**
     * Remove empty and already transferred fields
     *
     * @param array $item
     * @param array $fields
     * @param int $productId
     * @param int $storeFilter
     * @return array
     */
    private function removeEmptyAndTransferredFields($item, $fields, $productId, $storeFilter)
    {
        $productFields = [];

        foreach ($fields as $field) {
            if ($field !== 'alt_text' &&
                isset($item[$field]) &&
                $item[$field] != '' &&
                $item[$field] != null
            ) {
                $productFields[] = $field;
            }
        }

        if (in_array('alt_text', $fields) && $this->isImageGenerated($productId, $storeFilter)) {
            $productFields[] = 'alt_text';
        }

        return $productFields;
    }

    /**
     * Check if product has transferable content (optimized version)
     *
     * @param mixed $item
     * @param array $fields
     * @param int $productId
     * @param int $storeFilter
     * @return bool
     */
    private function hasTransferableContent($item, $fields, $productId, $storeFilter)
    {
        try {
            // Check regular text fields first (faster)
            foreach ($fields as $field) {
                if ($field !== 'alt_text' &&
                    isset($item[$field]) &&
                    $item[$field] != '' &&
                    $item[$field] != null
                ) {
                    return true;
                }
            }
            
            // Check alt_text only if it's in the fields (slower due to API call)
            // if (in_array('alt_text', $fields) && $this->isImageGenerated($productId, $storeFilter)) {
            //     return true;
            // }
            
            return false;
        } catch (\Exception $e) {
            // If there's an error, assume no transferable content
            return false;
        }
    }

    /**
     * Add image ids to array
     *
     * @param int $productId
     * @param int $storeId
     * @return void
     */
    private function addProductImage($productId, $storeId)
    {
        // Use static cache to avoid repeated API calls for the same product
        static $imageGeneratedCache = [];
        $cacheKey = $productId . '_' . $storeId;
        
        if (isset($imageGeneratedCache[$cacheKey])) {
            return $imageGeneratedCache[$cacheKey];
        }
        $generated = false;

        $language = $this->storeHelper->getFormattedLanguage($storeId);

        if (isset($this->products[$productId])) {
            $product = $this->products[$productId];
        } else {
            $product = $this->productRepository->getById($productId, false, $storeId);
        }

        $mediaGalleryEntries = $product->getMediaGalleryEntries();
 
        foreach ($mediaGalleryEntries as $mediaGalleryEntry) {
            $this->imageIds[] = $mediaGalleryEntry->getId();
        }
    }

    /**
     * Check if image is generated
     *
     * @param int $productId
     * @param int $storeId
     * @return bool
     */
    private function isImageGenerated($productId, $storeId)
    {
        // Use static cache to avoid repeated API calls for the same product
        static $imageGeneratedCache = [];
        $cacheKey = $productId . '_' . $storeId;
        
        if (isset($imageGeneratedCache[$cacheKey])) {
            return $imageGeneratedCache[$cacheKey];
        }
        $generated = false;

        $language = $this->storeHelper->getFormattedLanguage($storeId);

        if (isset($this->products[$productId])) {
            $product = $this->products[$productId];
        } else {
            $product = $this->productRepository->getById($productId, false, $storeId);
        }

        try {
            $images = $this->productHelper->getImages($product, $storeId, $language);
        } catch (\Exception $e) {
            return false;
        }

        $mediaGalleryEntries = $product->getMediaGalleryEntries();
 
        foreach ($images as $image) {
            foreach ($mediaGalleryEntries as $mediaGalleryEntry) {
                if ($mediaGalleryEntry->getId() == $image['id']) {
                    $mediaGalleryEntry->setLabel($image['writetext_alt']);
                    break;
                }
            }

            try {
                $getParams = [
                    "storeId" => $storeId,
                    "language" => $language,
                    "imageId" => $image['id']
                ];

                $altText = $this->apiManager->getImage($getParams);

                if (isset($altText['altText']['id'])) {
                    $generated = true;
                    break;
                }
            } catch (\WriteTextAI\WriteTextAI\Exception\ApiException $e) {
                if ($e->getCode() !== 404) {
                    throw $e;
                }
            } catch (\Exception $e) {
                continue;
            }
            
            if ($generated) {
                break;
            }
        }

        $imageGeneratedCache[$cacheKey] = $generated;
        return $generated;
    }

    /**
     * Check if image is transferable
     *
     * @param int $storeId
     * @return bool
     */
    private function hasTransferableImage($storeId)
    {
        $language = $this->storeHelper->getFormattedLanguage($storeId);

        if (empty($this->imageIds)) {
            return false;
        }
        
        //process batch of 100
        $chunks = array_chunk($this->imageIds, 100);
        $apiImages = [];
        foreach ($chunks as $chunk) {
            $apiImages = $this->apiManager->getImageList([
                "language" => $language,
                "images" => $chunk,
                "storeId" => $storeId,
                "includeUpdateHistory" => "true"
            ]);

            if (isset($apiImages['images']) && !empty($apiImages['images'])) {
                foreach ($apiImages['images'] as $image) {
                    if (isset($image['altText']['id'])) {
                        return true;
                    }
                }
            }
        }

        return false;
    }
}
