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

namespace WriteTextAI\WriteTextAI\Controller\Adminhtml\Edit;

use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\Filter\FilterManager;
use Magento\Framework\HTTP\PhpEnvironment\RemoteAddress;
use Magento\Framework\Escaper;
use Magento\Store\Model\ScopeInterface;
use WriteTextAI\WriteTextAI\Helper\Data;
use WriteTextAI\WriteTextAI\Helper\Html;
use WriteTextAI\WriteTextAI\Helper\Image;
use WriteTextAI\WriteTextAI\Helper\Generate as GenerateHelper;
use WriteTextAI\WriteTextAI\Helper\Product as ProductHelper;
use WriteTextAI\WriteTextAI\Model\ApiManager;
use WriteTextAI\WriteTextAI\Model\OptionSource\Filter\Fields;
use WriteTextAI\WriteTextAI\Model\GeneratedText;
use WriteTextAI\WriteTextAI\Model\AiProductManager;
use Magento\Backend\Model\UrlInterface;
use WriteTextAI\WriteTextAI\ViewModel\Settings;
use Magento\Catalog\Helper\Output as OutputHelper;
use WriteTextAI\WriteTextAI\Model\MarkReview;
use WriteTextAI\WriteTextAI\Helper\Store as StoreHelper;
use WriteTextAI\WriteTextAI\Model\Api\Keywords;
use WriteTextAI\WriteTextAI\Model\KeywordIdeaFiltersManager;
use WriteTextAI\WriteTextAI\Model\Config\Source\AutomaticTextOptimization;
use WriteTextAI\WriteTextAI\Model\SingleGenerateRequestsManager;
use WriteTextAI\WriteTextAI\Model\Api\Session as ApiSession;
use Magento\Catalog\Helper\Image as MagentoImageHelper;
use WriteTextAI\WriteTextAI\Helper\Fields as FieldHelper;
use WriteTextAI\WriteTextAI\Model\Config\Source\ProductAttributes;

class Generate extends Action
{
    public const ADMIN_RESOURCE = 'WriteTextAI_WriteTextAI::generate';

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

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

    /**
     * @var ScopeConfigInterface
     */
    protected $scopeConfig;

    /**
     * @var Data
     */
    protected $helper;

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

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

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

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

    /**
     * @var Image
     */
    protected $imageHelper;

    /**
     * @var GenerateHelper
     */
    protected $generateHelper;

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

    /**
     * @var FilterManager
     */
    protected $filterManager;

    /**
     * @var Escaper
     */
    protected $escaper;

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

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

    /**
     * @var OutputHelper
     */
    protected $outputHelper;

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

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

    /**
     * @var Keywords
     */
    protected $keywords;

    /**
     * @var KeywordIdeaFiltersManager
     */
    protected $keywordIdeaFiltersManager;

    /**
     * @var SingleGenerateRequestsManager
     */
    protected $singleGenerateRequestsManager;

    /**
     * @var ApiSession
     */
    protected $apiSession;

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

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

    /**
     * Constructor
     *
     * @param Context $context
     * @param ApiManager $apiManager
     * @param RemoteAddress $remoteAddress
     * @param ScopeConfigInterface $scopeConfig
     * @param Data $helper
     * @param ProductRepositoryInterface $productRepository
     * @param GeneratedText $generatedText
     * @param AiProductManager $aiProductManager
     * @param Html $htmlHelper
     * @param Image $imageHelper
     * @param GenerateHelper $generateHelper
     * @param ProductHelper $productHelper
     * @param FilterManager $filterManager
     * @param Escaper $escaper
     * @param UrlInterface $urlBuilder
     * @param Settings $settings
     * @param OutputHelper $outputHelper
     * @param MarkReview $markReview
     * @param StoreHelper $storeHelper
     * @param Keywords $keywords
     * @param KeywordIdeaFiltersManager $keywordIdeaFiltersManager
     * @param SingleGenerateRequestsManager $singleGenerateRequestsManager
     * @param ApiSession $apiSession
     * @param MagentoImageHelper $magentoImageHelper
     * @param FieldHelper $fieldHelper
     */
    public function __construct(
        Context $context,
        ApiManager $apiManager,
        RemoteAddress $remoteAddress,
        ScopeConfigInterface $scopeConfig,
        Data $helper,
        ProductRepositoryInterface $productRepository,
        GeneratedText $generatedText,
        AiProductManager $aiProductManager,
        Html $htmlHelper,
        Image $imageHelper,
        GenerateHelper $generateHelper,
        ProductHelper $productHelper,
        FilterManager $filterManager,
        Escaper $escaper,
        UrlInterface $urlBuilder,
        Settings $settings,
        OutputHelper $outputHelper,
        MarkReview $markReview,
        StoreHelper $storeHelper,
        Keywords $keywords,
        KeywordIdeaFiltersManager $keywordIdeaFiltersManager,
        SingleGenerateRequestsManager $singleGenerateRequestsManager,
        ApiSession $apiSession,
        MagentoImageHelper $magentoImageHelper,
        FieldHelper $fieldHelper
    ) {
        $this->apiManager = $apiManager;
        $this->remoteAddress = $remoteAddress;
        $this->scopeConfig = $scopeConfig;
        $this->helper = $helper;
        $this->productRepository = $productRepository;
        $this->generatedText = $generatedText;
        $this->aiProductManager = $aiProductManager;
        $this->htmlHelper = $htmlHelper;
        $this->imageHelper = $imageHelper;
        $this->generateHelper = $generateHelper;
        $this->productHelper = $productHelper;
        $this->filterManager = $filterManager;
        $this->escaper = $escaper;
        $this->urlBuilder = $urlBuilder;
        $this->settings = $settings;
        $this->outputHelper = $outputHelper;
        $this->markReview = $markReview;
        $this->storeHelper = $storeHelper;
        $this->keywords = $keywords;
        $this->keywordIdeaFiltersManager = $keywordIdeaFiltersManager;
        $this->singleGenerateRequestsManager = $singleGenerateRequestsManager;
        $this->apiSession = $apiSession;
        $this->magentoImageHelper = $magentoImageHelper;
        $this->fieldHelper = $fieldHelper;
        parent::__construct($context);
    }

    /**
     * Get image URLs for a product
     *
     * @param array $gallery
     * @param array $galleryImagesFromPost
     * @return array
     */
    private function getImageUrls($gallery, $galleryImagesFromPost)
    {
        try {
            //$product = $this->productRepository->getById($productId, false, $storeId);
            //$language = $this->storeHelper->getFormattedLanguage($storeId);

            $imageUrls = [];
            $mainImage = [];
            foreach ($gallery as $image) {
                if (!in_array($image['id'], $galleryImagesFromPost)) {
                    continue;
                }

                if ($image['is_featured']) {
                    $mainImage = [
                        "url" => $image['noncached_url'],
                        "imageId" => $image['id']
                    ];
                    continue;
                }

                $imageUrls[] = [
                    "url" => $image['noncached_url'],
                    "imageId" => $image['id']
                ];
            }

            // Get main product image
            // $mainImage = $this->magentoImageHelper->init($product, 'product_page_image_large')
            //     ->setImageFile($product->getImage())
            //     ->getUrl();
            
            return [
                'main_image' => $mainImage,
                'gallery_images' => $imageUrls
            ];
        } catch (\Exception $e) {
            return [
                'main_image' => [],
                'gallery_images' => []
            ];
        }
    }

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

        try {
            $tones = $this->getRequest()->getPost('tones', explode(",", (string) $this->helper->getTones()));
            $style = $this->getRequest()->getPost('styles');
            $audience = $this->getRequest()->getPost('audience');
            $keywords = $this->getRequest()->getPost('keywords', []);
            $storeId = $this->getRequest()->getPost('store_id');
            $productId = $this->getRequest()->getPost('product_id');
            $descriptionMin = $this->getRequest()->getPost('desc_min', "");
            $descriptionMax = $this->getRequest()->getPost('desc_max', "");
            $excerptMin = $this->getRequest()->getPost('exc_min', "");
            $excerptMax = $this->getRequest()->getPost('exc_max', "");
            $attributes = $this->getRequest()->getPost('product_attributes', []);
            $attributes_selected = $this->getRequest()->getPost('product_attributes_selected', []);
            $otherProductDetails = $this->getRequest()->getPost('other_product_details', "");
            $additionalPrompt = $this->getRequest()->getPost('additional_prompt', "");
            $selectedFields = $this->getRequest()->getPost('selected_fields', []);
            $selectedImages = $this->getRequest()->getPost('selected_images', []);
            $gallery = $this->getRequest()->getPost('images', []);
            $customTone = $this->getRequest()->getPost('custom_tone', "");
            $customStyle = $this->getRequest()->getPost('custom_style', "");
            $customAudience = $this->getRequest()->getPost('custom_audience', "");
            $galleryImagesFromPost = $this->getRequest()->getPost('gallery_images', []);
            $templatesUsed = $this->getRequest()->getPost('templates_used', []);
            $keywordAnalysisViews = $this->getRequest()->getPost('keyword_analysis_views');
            $useAiModel = $this->getRequest()->getPost('use_ai_model', false);
            $selectedAiModel = $this->getRequest()->getPost('selected_ai_model', '');
            $keywordAnalysis = filter_var(
                $this->getRequest()->getPost('keyword_analysis'),
                FILTER_VALIDATE_BOOLEAN
            );
            
            $product = $this->productRepository->getById($productId, false, $storeId);
            $productName = $this->outputHelper->productAttribute(
                $product,
                $product->getName(),
                'name'
            );
            $mappingSettings = $this->helper->getMappingSettings();
            $country =  $this->scopeConfig->getValue(
                'general/country/default',
                ScopeInterface::SCOPE_STORE,
                $storeId
            );
            $language = $this->storeHelper->getFormattedLanguage($storeId);
            $ipAddress = $this->remoteAddress->getRemoteAddress();
            $frontendStoreId = $this->storeHelper->getFrontendStoreId($storeId);

            $rules = $this->settings->getSettings('rules');

            $isProductResearchDataSelected = false;

            if (!empty($selectedFields) || !empty($selectedImages)) {
                $maxOutputWords = $rules['maxOutputWords'] ?? '';
                $maxReferenceTextLength = $rules['maxReferenceTextLength'] ?? '';
                $additionalReferenceTextLength = $rules['additionalReferenceTextLength'] ?? '';
                $maxAttributes = $rules['maxAttributes'] ?? '';
                $maxAttributeValueLength = $rules['maxAttributeValueLength'] ?? '';

                $credits = $this->settings->getSettings('credits');
                $wordsPerCredit = $credits['wordsPerCredit'] ?? '';

                $maxInputChar = ((($maxOutputWords / $wordsPerCredit) - 1) * $additionalReferenceTextLength)
                    + $maxReferenceTextLength;

                // get attributes
                $attributesData = [];
                $images = [];
                foreach ($attributes as $attribute) {
                    if (!in_array($attribute['attribute_code'], $attributes_selected)) {
                        continue;
                    }
                    
                    /*if ($maxAttributes <= count($attributesData)) {
                        continue;
                    }*/

                    if (strtolower($attribute['attribute_code']) ===
                        ProductAttributes::PRODUCT_RESEARCH_DATA_ATTRIBUTE_CODE) {
                        $isProductResearchDataSelected = true;
                        continue;
                    }
                    try {
                        if (strtolower($attribute['attribute']) !== 'thumbnail') {
                            if (is_array($attribute['details'])) {
                                $attribute['details'] = $attribute['details'][$attribute['value']] ?? '';
                            }
                            if (!empty(trim($attribute['details']))) {
                                $attributeValue = str_replace("<br />", "\n", $attribute['details']);
                                $attributeValue = $this->filterManager->stripTags($attributeValue);
                                $attributeValue = htmlspecialchars(
                                    $attributeValue,
                                    ENT_QUOTES | ENT_SUBSTITUTE,
                                    'UTF-8'
                                );
                                $attributesData[] = [
                                    "name" => $attribute['attribute'],
                                    "value" => $attributeValue,
                                    "isCustom" => "false"
                                ];
                            }
                        } else {
                                $images[] = $this->imageHelper->getImageApiId(
                                    $storeId,
                                    $ipAddress,
                                    $language,
                                    $attribute['value'],
                                    $attribute['details']
                                );
                        }
                    } catch (\WriteTextAI\WriteTextAI\Exception\ImageUnsupported $e) {
                        continue;
                    } catch (\WriteTextAI\WriteTextAI\Exception\ImageInvalid $e) {
                        continue;
                    } catch (\Exception $e) {
                        continue;
                    }
                }

                // fields to generate
                $fieldConfig = [
                    'page_title' => Fields::PAGE_TITLE,
                    'page_description' => Fields::PAGE_DESCRIPTION,
                    'product_description' => Fields::PRODUCT_DESCRIPTION,
                    'short_product_description' => Fields::EXCERPT,
                    'open_graph' => Fields::OPEN_GRAPH,
                ];

                $fields = [];
                foreach ($fieldConfig as $fieldName => $fieldConstant) {
                    if (in_array($fieldName, $selectedFields)) {
                        $field = [
                            "field" => $fieldConstant
                        ];

                        if ($fieldName == 'product_description') {
                            $field["minWords"] = $descriptionMin;
                            $field["maxWords"] = $descriptionMax;
                        } elseif ($fieldName == 'short_product_description') {
                            $field["minWords"] = $excerptMin;
                            $field["maxWords"] = $excerptMax;
                        }

                        if (isset($templatesUsed[$fieldName]) && $templatesUsed[$fieldName]) {
                            $field['templateId'] = $templatesUsed[$fieldName];
                        }

                        $fields[] = $field;
                    }
                }
                
                $textData = [
                    "name" => $productName,
                    "recordId" => $productId,
                    "sku" => $product->getSku(),
                    "options" => 1,
                    "autoselectFirst" => true,
                    "attributes" => $attributesData,
                    "otherDetails" => $this->filterManager->stripTags($otherProductDetails),
                    "fields" => $fields,
                    "keywordAnalysisViews" => $keywordAnalysisViews,
                    "url" => $product->setStoreId($frontendStoreId)->getUrlInStore(),
                    "enableResearch" => $isProductResearchDataSelected
                ];

                if (filter_var($useAiModel, FILTER_VALIDATE_BOOLEAN)) {
                    $textData['modelId'] = $selectedAiModel;
                }

                if (!empty($images)) {
                    $textData["images"] = $images;
                }
                
                $imageAltTextParams = $this->getAltTextParam(
                    $selectedImages,
                    $gallery
                );
                if ($imageAltTextParams) {
                    $textData["imageAltTexts"] = $imageAltTextParams;
                }
                
                if ($customAudience) {
                    $textData['customAudience'] = $customAudience;
                }

                if (!empty($audience)) {
                    $textData['audiences'] = $audience;
                }

                if (in_array('custom', $tones)) {
                    $textData['customTone'] = $customTone;
                } else {
                    $textData['tones'] = $tones;
                }

                if ($style == 'custom') {
                    $textData['customStyle'] = $customStyle;
                } else {
                    $textData['style'] = $style;
                }

                $galleryImages = $this->productHelper->getImages($product, $storeId, $language);
                $imageUrls = $this->getImageUrls($galleryImages, $galleryImagesFromPost);
                if (isset($imageUrls['main_image']) && $imageUrls['main_image']) {
                    $textData['featuredImage'] = $imageUrls['main_image'];
                }
                if (isset($imageUrls['gallery_images']) && $imageUrls['gallery_images']) {
                    $textData['galleryImages'] = $imageUrls['gallery_images'];
                }

                $publishedContents = [
                    'product_description' => $this->fieldHelper->getAttributesValues($product, 'product_description'),
                    'short_product_description' => $this->fieldHelper->getAttributesValues(
                        $product,
                        'short_product_description'
                    )
                ];
                
                $params = [
                    "type" => "Product",
                    "storeId" => $storeId,
                    "language" => $language,
                    "countries" => [$country],
                    "ipAddress" => $ipAddress,
                    "texts" => [$textData],
                    "queue" => true
                ];

                if ($keywordAnalysis) {
                    $params['keywordOptimization'] = $this->getKeywordOptimizationParams($storeId);
                    $params['development'] = filter_var($this->helper->getKoDev(), FILTER_VALIDATE_BOOLEAN);
                }
                if ($this->helper->getForceQueueSeconds()) {
                    $params['developmentQueueWaitTimeInSeconds'] = $this->helper->getForceQueueSeconds();
                }

                if ($additionalPrompt) {
                    $params['specialInstructions'] = $additionalPrompt;
                }
                $apiResponse = $this->apiManager->generate(json_encode($params));

                if ($apiResponse && isset($apiResponse['requestId']) && $apiResponse['requestId']) {
                    $this->singleGenerateRequestsManager->setSingleGenerateRequest(
                        $apiResponse['requestId'],
                        $this->apiSession->getCurrentUser()->getEmail(),
                        'Product',
                        $storeId,
                        $productId
                    );
                }
            }
            
            $this->aiProductManager->saveDate($productId, $storeId, 'generated');
            $this->aiProductManager->saveDate($productId, $storeId, 'edited');

            $result = [
                'success' => true,
                'reviewed' => $this->markReview->getReviewed($productId, $storeId),
                'response' => $apiResponse ?? [],
                'params' => $params ?? []
            ];
        } 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,
                'params' => $params ?? [],
            ];
            $result['message'] = $message;
        }

        $response->setData($result);

        return $response;
    }

    /**
     * Get keyword optimization params
     *
     * @param int $storeId
     *
     * @return array
     */
    private function getKeywordOptimizationParams($storeId)
    {
        $searchIntent = $this->getRequest()->getPost('search_intent_selected');
        
        $action = $this->getDefaultAutomaticTextOptimization();
        switch ($action) {
            case AutomaticTextOptimization::AUTO_REWRITE_AND_QUEUE:
                $action = 'AutomaticRewrite';
                break;
            case AutomaticTextOptimization::FLAG:
                $action = 'FlagForRewrite';
                break;
            case AutomaticTextOptimization::AUTO_REWRITE_AND_TRANSFER:
                $action = 'FullAutomation';
                break;
        }

        $triggers = $this->keywords->prepareDefaultTriggerSettingsParameters();
        foreach ($triggers as $key => $trigger) {
            $triggers[$key]['action'] = $action;
        }

        $params = [
            "intents" => $searchIntent,
            "countryCode" => $this->keywordIdeaFiltersManager->getCountryCode($storeId),
            "clusters" => $this->helper->getKeywordOptimizationSettings('cluster_based_pipelines_count'),
            "triggers" => $triggers,
            "doKeywordOptimizationOnly" => false
        ];
        
        if (filter_var($this->helper->getKoDev(), FILTER_VALIDATE_BOOLEAN)) {
            $params["developmentSettings"] = [
                "waitTimePerStep" => 1000,
                "maxSteps" => 9,
                "failAfterFirstStep" => filter_var($this->helper->getForceFailed(), FILTER_VALIDATE_BOOLEAN)
            ];
        }

        return $params;
    }

    /**
     * Get default automatic text optimization
     *
     * @return string
     */
    public function getDefaultAutomaticTextOptimization()
    {
        $selected = $this->helper->getKeywordOptimizationSettings('automatic_text_optimization');
        if ($selected) {
            return $selected;
        }
        return AutomaticTextOptimization::AUTO_REWRITE_AND_QUEUE;
    }

    /**
     * Generate alt text for images
     *
     * @param array $selectedImages
     * @param array $gallery
     *
     * @return array
     */
    private function getAltTextParam(
        $selectedImages,
        $gallery
    ) {
        if (empty($selectedImages)) {
            return [];
        }

        $images = [];
        foreach ($gallery as $image) {
            if (in_array($image['id'], $selectedImages)) {
                $images[] = [
                    "imageId" => $image['id']
                ];
            }
        }

        return $images;
    }
}
