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

namespace WriteTextAI\WriteTextAI\Controller\Adminhtml\Edit;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Controller\ResultFactory;
use Magento\Catalog\Model\ResourceModel\Product\Action as ProductAction;
use WriteTextAI\WriteTextAI\Model\GeneratedText;
use WriteTextAI\WriteTextAI\Helper\Data;
use WriteTextAI\WriteTextAI\Model\AiProductManager;
use WriteTextAI\WriteTextAI\Helper\Fields as FieldHelper;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Framework\Exception\NoSuchEntityException;
use WriteTextAI\WriteTextAI\Helper\Product as ProductHelper;
use WriteTextAI\WriteTextAI\Model\ApiManager;
use WriteTextAI\WriteTextAI\ViewModel\Settings;
use WriteTextAI\WriteTextAI\Helper\ReviewStatus as ReviewHelper;
use WriteTextAI\WriteTextAI\Model\ReviewStatus;
use WriteTextAI\WriteTextAI\Model\MarkReview;
use WriteTextAI\WriteTextAI\Helper\Store as StoreHelper;
use WriteTextAI\WriteTextAI\Helper\Html;
use Magento\Store\Model\StoreManagerInterface;
use WriteTextAI\WriteTextAI\Service\ImageAltTextTransfer;

class Transfer extends Action
{
    public const ADMIN_RESOURCE = 'WriteTextAI_WriteTextAI::transfer';
    
    /**
     * @var Data
     */
    protected $helper;

    /**
     * @var ProductAction
     */
    protected $productAction;

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

    /**
     * @var AiProductManager
     */
    protected $aiProductManager;

    /**
     * @var FieldHelper
     */
    protected $fieldHelper;

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

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

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

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

    /**
     * @var ReviewHelper
     */
    protected $reviewHelper;

    /**
     * @var ReviewStatus
     */
    protected $reviewStatus;

    /**
     * @var MarkReview
     */
    protected $markReview;

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

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

    /**
     * @var Html
     */
    protected $htmlHelper;

    /**
     * @var StoreManagerInterface
     */
    protected $storeManager;

    /**
     * @var bool
     */
    protected $isAltIncluded = false;

    /**
     * @var ImageAltTextTransfer
     */
    protected $imageAltTextTransfer;

    /**
     * Constructor
     *
     * @param Context $context
     * @param Data $helper
     * @param ProductAction $productAction
     * @param GeneratedText $generatedText
     * @param AiProductManager $aiProductManager
     * @param FieldHelper $fieldHelper
     * @param ProductRepositoryInterface $productRepository
     * @param ProductHelper $productHelper
     * @param ApiManager $apiManager
     * @param Settings $settings
     * @param ReviewHelper $reviewHelper
     * @param ReviewStatus $reviewStatus
     * @param MarkReview $markReview
     * @param StoreHelper $storeHelper
     * @param Html $htmlHelper
     * @param StoreManagerInterface $storeManager
     * @param ImageAltTextTransfer $imageAltTextTransfer
     */
    public function __construct(
        Context $context,
        Data $helper,
        ProductAction $productAction,
        GeneratedText $generatedText,
        AiProductManager $aiProductManager,
        FieldHelper $fieldHelper,
        ProductRepositoryInterface $productRepository,
        ProductHelper $productHelper,
        ApiManager $apiManager,
        Settings $settings,
        ReviewHelper $reviewHelper,
        ReviewStatus $reviewStatus,
        MarkReview $markReview,
        StoreHelper $storeHelper,
        Html $htmlHelper,
        StoreManagerInterface $storeManager,
        ImageAltTextTransfer $imageAltTextTransfer
    ) {
        $this->helper = $helper;
        $this->productAction = $productAction;
        $this->generatedText = $generatedText;
        $this->aiProductManager = $aiProductManager;
        $this->fieldHelper = $fieldHelper;
        $this->productRepository = $productRepository;
        $this->productHelper = $productHelper;
        $this->apiManager = $apiManager;
        $this->settings = $settings;
        $this->reviewHelper = $reviewHelper;
        $this->reviewStatus = $reviewStatus;
        $this->markReview = $markReview;
        $this->storeHelper = $storeHelper;
        $this->htmlHelper = $htmlHelper;
        $this->storeManager = $storeManager;
        $this->imageAltTextTransfer = $imageAltTextTransfer;
        parent::__construct($context);
    }

    /**
     * Execute
     *
     * @return \Magento\Framework\Controller\Result\Json
     */
    public function execute()
    {
        $response = $this->resultFactory->create(ResultFactory::TYPE_JSON);

        try {
            $storeFilter = $this->getRequest()->getPost('store_id');
            $productId = $this->getRequest()->getPost('product_id');
            $selectedStores = $this->getRequest()->getPost('selected_stores', []);
            $selectedFields = $this->getRequest()->getPost('selected_fields', []);
            $field = $this->getRequest()->getParam('field');
            $value = $this->getRequest()->getParam('value');

            $mediaUrl = $this->storeManager->getStore($storeFilter)
                ->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);

            $mappingSettings = $this->helper->getMappingSettings();

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

            $this->transferImageAltTexts(
                $productId,
                $selectedStores,
                $language,
                $storeFilter
            );
            
            try {
                $product = $this->productRepository->getById($productId, false, $storeFilter, true);
            } catch (NoSuchEntityException $e) {
                $result = [
                    'success' => false,
                    'message' => $e->getMessage()
                ];
            }

            if (!empty($selectedFields) || ($field && $value)) {
                if (!empty($selectedFields)) {
                    $pageTitle = $this->getRequest()->getParam('page_title');
                    $pageDescription = $this->getRequest()->getParam('page_description');
                    $productDescription = $this->getRequest()->getParam('product_description');
                    $productShortDescription = $this->getRequest()->getParam('product_short_description');
                    $openGraph = $this->getRequest()->getParam('open_graph');

                    $productDescription = $this->convertMediaUrl($productDescription);
                    $productShortDescription = $this->convertMediaUrl($productShortDescription);
                    $openGraph = $this->convertMediaUrl($openGraph);

                    $this->generatedText->saveText(
                        $storeFilter,
                        $productId,
                        $pageTitle,
                        $pageDescription,
                        $productDescription,
                        $productShortDescription,
                        $openGraph,
                        $selectedFields
                    );
                
                    $fields = [
                        'page_title' => $pageTitle,
                        'page_description' => $pageDescription,
                        'product_description' => $productDescription,
                        'short_product_description' => $productShortDescription,
                        'open_graph' => $openGraph
                    ];

                    if ($this->helper->getCustomOpenGraph() && !empty($openGraph)) {
                        $fields['open_graph'] = $openGraph;
                    }

                    $toReview = [];
                    foreach ($selectedFields as $selectedField) {
                        if (!empty($fields[$selectedField])) {
                            $toReview[$selectedField] = $fields[$selectedField];
                        }
                    }
                } else {
                    $value = $this->convertMediaUrl($value);
                    $selectedFields = [$field];
                    $this->generatedText->saveText(
                        $storeFilter,
                        $productId,
                        $field === 'page_title' ? $value : null,
                        $field === 'page_description' ? $value : null,
                        $field === 'product_description' ? $value : null,
                        $field === 'short_product_description' ? $value : null,
                        $field === 'open_graph' ? $value : null,
                        $selectedFields
                    );

                    $fields = [
                        $field => $value
                    ];
                }

                $imageAltTexts = [];
                if ($this->isAltIncluded && !empty($images)) {
                    $imageAltTexts = $images;
                } else {
                    $imageAltTexts = $this->productHelper->getPublishedImages($product, $storeFilter, $language);
                }

                foreach ($selectedStores as $storeId) {
                    $toUpdate = [];
                    foreach ($fields as $field => $value) {
                        $value = $this->processContentImageAltTexts($value, $imageAltTexts, $this->isAltIncluded);
                        if (isset($mappingSettings[$field]) && in_array($field, $selectedFields)) {
                            $value = $this->htmlHelper->stripEmojis($value);
                            $toUpdate[$mappingSettings[$field]] = $value;
                        }
                    }

                    $this->productAction->updateAttributes(
                        [$productId],
                        $toUpdate,
                        $storeId
                    );
                    $this->aiProductManager->saveDate($productId, $storeId, 'transferred');
                    $this->aiProductManager->saveDate($productId, $storeId, 'reviewed');
                }

                $resultFields = [];
                $directives = [];
            }

            try {
                /** needed to get the product again to get the updated product object */
                $product = $this->productRepository->getById($productId, false, $storeFilter, true);
            } catch (NoSuchEntityException $e) {
                $result = [
                    'success' => false,
                    'message' => $e->getMessage()
                ];
            }

            if (!empty($selectedFields) || ($field && $value)) {
                foreach ($fields as $field => $value) {
                    $fieldValue = $this->fieldHelper->getAttributesValues($product, $field);
                    $resultFields[$field] = $fieldValue;
                    $resultFields[$field . '_char'] = $fieldValue ? strlen($fieldValue) : 0;
                    $resultFields[$field . '_words'] = $fieldValue ? count(array_filter(
                        explode(' ', (string) $fieldValue),
                        function ($n) {
                            return $n !== '';
                        }
                    )) : 0;

                    if (in_array($field, ['product_description', 'short_product_description'])) {
                        $directives[$field] = $this->fieldHelper->isDirectiveExists($product, $field);
                    }
                }
            }

            if (!empty($fields)) {
                /**
                 * $toReview is set if transfered from transfer all button
                 */
                if (isset($toReview) && !empty($toReview)) {
                    $fields = $toReview;
                }

                $this->reviewStatus->updateReview(array_keys($fields), $productId, $selectedStores, $this->products);
            }
            
            $useDefault = $this->getUseDefault($storeFilter, $product, $mappingSettings);

            $updatedReview = $this->reviewHelper->getReviewStatus($productId, $storeFilter);

            $result = [
                'success' => true,
                'reviewed' => $this->markReview->getReviewed($productId, $storeFilter),
                'fields' => $resultFields ?? [],
                'directives' => $directives ?? [],
                'images' => $this->productHelper->getImages($product, $storeFilter, $language),
                'updatedReview' => $updatedReview,
                'use_default' => $useDefault
            ];
        } 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;
    }

    /**
     * Get use default
     *
     * @param int $storeId
     * @param \Magento\Catalog\Api\Data\ProductInterface $product
     * @param array $mappingSettings
     *
     * @return array
     */
    public function getUseDefault($storeId, $product, $mappingSettings)
    {
        $useDefault = [
            'page_title' => $this->fieldHelper->isUsingDefaultValues(
                $product,
                $storeId,
                $mappingSettings['page_title']
            ),
            'page_description' => $this->fieldHelper->isUsingDefaultValues(
                $product,
                $storeId,
                $mappingSettings['page_description']
            ),
            'product_description' => $this->fieldHelper->isUsingDefaultValues(
                $product,
                $storeId,
                $mappingSettings['product_description']
            ),
            'short_product_description' => $this->fieldHelper->isUsingDefaultValues(
                $product,
                $storeId,
                $mappingSettings['short_product_description']
            ),
            'open_graph' => isset($mappingSettings['open_graph']) ?
                $this->fieldHelper->isUsingDefaultValues($product, $storeId, $mappingSettings['open_graph']) : false
        ];

        return $useDefault;
    }

    /**
     * Transfer image alt texts
     *
     * @param int $productId
     * @param array $selectedStores
     * @param string $language
     * @param int $storeFilter
     *
     * @return void
     */
    public function transferImageAltTexts($productId, $selectedStores, $language, $storeFilter)
    {
        $selectedImages = $this->getRequest()->getParam('selected_images', []);
        $images = $this->getRequest()->getParam('images', []);
        
        if (empty($selectedImages)) {
            return;
        }
        $this->isAltIncluded = true;

        $rules = $this->settings->getSettings('rules');
        $selectedImagesChunk = array_chunk($selectedImages, $rules['maxImageAltTextPerRequest']);
        $this->products = [];

        $imagesToUpdate = [];
        $storeImageLabels = [];
        foreach ($selectedStores as $storeId) {
            $product = $this->productRepository->getById($productId, true, $storeId);
            $this->products[$storeId] = $product;
            $mediaGalleryEntries = $product->getMediaGalleryEntries();

            foreach ($selectedImagesChunk as $selectedImageChunk) {
                try {
                    $apiImages = $this->apiManager->getImageList([
                        "language" => $language,
                        "images" => $selectedImageChunk,
                        "storeId" => $storeId,
                        "includeUpdateHistory" => "true"
                    ]);
                } catch (\WriteTextAI\WriteTextAI\Exception\ApiException $e) {
                    if ($e->getCode() === 404) {
                        $apiImages = [];
                    }
                }

                foreach ($images as $image) {
                    if (!in_array($image['id'], $selectedImageChunk)
                        || empty($image['writetext_alt'])) {
                        continue;
                    }
                    
                    foreach ($mediaGalleryEntries as $mediaGalleryEntry) {
                        if ($mediaGalleryEntry->getId() == $image['id']) {
                            $mediaGalleryEntry->setLabel($image['writetext_alt']);
                            $storeImageLabels[$storeId][$image['id']] = $image['writetext_alt'];
                            break;
                        }
                    }

                    $filteredImages = array_filter(
                        $apiImages['images'],
                        function ($apiImage) use ($image) {
                            return $apiImage['imageId'] == $image['id'];
                        }
                    );
                    
                    if (!empty($filteredImages)) {
                        $apiImage = reset($filteredImages);
                        if (isset($apiImage['altText']['id'])) {
                            $imagesToUpdate[] = [
                                "storeId" => $storeId,
                                "language" => $language,
                                "imageId" => $image['id'],
                                "textId" => $apiImage['altText']['id'],
                                "value" => $image['writetext_alt'],
                                "publish" => true,
                                "reviewed" => true
                            ];
                        }
                    }
                }
            }

            $product->setMediaGalleryEntries($mediaGalleryEntries);
            $this->aiProductManager->saveDate($productId, $storeId, 'transferred');
            $this->aiProductManager->saveDate($productId, $storeId, 'reviewed');
        }

        if (!empty($storeImageLabels)) {
            $this->imageAltTextTransfer->updateStoreImageLabels($storeImageLabels);
        }

        $this->apiManager->batchUpdateAltText(json_encode([
            "images" => $imagesToUpdate
        ]));
    }

    /**
     * Process content image alt texts
     *
     * @param string $fieldValue
     * @param array $imageAltTexts
     * @param bool $isAltIncluded
     *
     * @return string
     */
    public function processContentImageAltTexts($fieldValue, $imageAltTexts = [], $isAltIncluded = false)
    {
        $updatedFieldValue = $fieldValue;
        if ($imageAltTexts) {
            $updatedFieldValue = $this->htmlHelper->addAltTextToContentViaPreg(
                $fieldValue,
                $imageAltTexts,
                $isAltIncluded
            );
        }

        return $updatedFieldValue;
    }

    /**
     * Convert media URL
     *
     * @param string $content
     *
     * @return string
     */
    public function convertMediaUrl($content)
    {
        if (empty($content)) {
            return $content;
        }

        $mediaBaseUrl = $this->storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);

        $decodedContent = htmlspecialchars_decode($content, ENT_QUOTES);

        // Replace {{media url="..."}} with real media URL
        $convertedContent = preg_replace_callback(
            '/{{media url=["\']([^"\']+)["\']}}/',
            function ($matches) use ($mediaBaseUrl) {
                return $mediaBaseUrl . ltrim($matches[1], '/');
            },
            $decodedContent
        );

        return $convertedContent;
    }
}
