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

namespace WriteTextAI\WriteTextAI\Controller\Adminhtml\Categories\Edit;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\HTTP\PhpEnvironment\RemoteAddress;
use WriteTextAI\WriteTextAI\Model\ApiManager;
use Magento\Framework\App\Config\ScopeConfigInterface;
use WriteTextAI\WriteTextAI\Helper\Store as StoreHelper;
use Magento\Framework\Filter\FilterManager;
use Magento\Backend\Model\UrlInterface;
use Magento\Framework\Controller\ResultFactory;
use Magento\Store\Model\ScopeInterface;
use WriteTextAI\WriteTextAI\Model\OptionSource\Filter\Fields;
use WriteTextAI\WriteTextAI\Model\Categories\MarkReview;
use WriteTextAI\WriteTextAI\ViewModel\Settings;
use WriteTextAI\WriteTextAI\Helper\Html;
use WriteTextAI\WriteTextAI\Helper\Image;
use WriteTextAI\WriteTextAI\Helper\Data;
use WriteTextAI\WriteTextAI\Model\AiCategoryManager;
use WriteTextAI\WriteTextAI\Model\Api\Keywords;
use WriteTextAI\WriteTextAI\Model\KeywordIdeaFiltersManager;
use WriteTextAI\WriteTextAI\Model\Config\Source\AutomaticTextOptimization;
use Magento\Store\Model\StoreManagerInterface;
use WriteTextAI\WriteTextAI\Model\Magento\Category as MagentoCategory;
use WriteTextAI\WriteTextAI\Helper\Categories\Fields as FieldHelper;
use Magento\Catalog\Helper\Output as OutputHelper;
use Magento\Catalog\Api\ProductRepositoryInterface;
use WriteTextAI\WriteTextAI\Helper\Product as ProductHelper;
use Magento\Framework\UrlInterface as FrameworkUrlInterface;

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

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

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

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

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

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

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

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

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

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

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

    /**
     * @var AiCategoryManager
     */
    protected $aiCategoryManager;

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

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

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

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

    /**
     * @var MagentoCategory
     */
    protected $magentoCategory;

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

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

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

    /**
     * Constructor
     *
     * @param Context $context
     * @param RemoteAddress $remoteAddress
     * @param ApiManager $apiManager
     * @param ScopeConfigInterface $scopeConfig
     * @param StoreHelper $storeHelper
     * @param FilterManager $filterManager
     * @param UrlInterface $urlBuilder
     * @param MarkReview $markReview
     * @param Settings $settings
     * @param Html $htmlHelper
     * @param Image $imageHelper
     * @param AiCategoryManager $aiCategoryManager
     * @param Keywords $keywords
     * @param KeywordIdeaFiltersManager $keywordIdeaFiltersManager
     * @param Data $helper
     * @param StoreManagerInterface $storeManager
     * @param MagentoCategory $magentoCategory
     * @param FieldHelper $fieldHelper
     * @param OutputHelper $outputHelper
     * @param ProductRepositoryInterface $productRepository
     * @param ProductHelper $productHelper
     */
    public function __construct(
        Context $context,
        RemoteAddress $remoteAddress,
        ApiManager $apiManager,
        ScopeConfigInterface $scopeConfig,
        StoreHelper $storeHelper,
        FilterManager $filterManager,
        UrlInterface $urlBuilder,
        MarkReview $markReview,
        Settings $settings,
        Html $htmlHelper,
        Image $imageHelper,
        AiCategoryManager $aiCategoryManager,
        Keywords $keywords,
        KeywordIdeaFiltersManager $keywordIdeaFiltersManager,
        Data $helper,
        StoreManagerInterface $storeManager,
        MagentoCategory $magentoCategory,
        FieldHelper $fieldHelper,
        OutputHelper $outputHelper,
        ProductRepositoryInterface $productRepository,
        ProductHelper $productHelper
    ) {
        $this->remoteAddress = $remoteAddress;
        $this->apiManager = $apiManager;
        $this->scopeConfig = $scopeConfig;
        $this->storeHelper = $storeHelper;
        $this->filterManager = $filterManager;
        $this->urlBuilder = $urlBuilder;
        $this->markReview = $markReview;
        $this->settings = $settings;
        $this->htmlHelper = $htmlHelper;
        $this->imageHelper = $imageHelper;
        $this->aiCategoryManager = $aiCategoryManager;
        $this->keywords = $keywords;
        $this->keywordIdeaFiltersManager = $keywordIdeaFiltersManager;
        $this->helper = $helper;
        $this->storeManager = $storeManager;
        $this->magentoCategory = $magentoCategory;
        $this->fieldHelper = $fieldHelper;
        $this->outputHelper = $outputHelper;
        $this->productRepository = $productRepository;
        $this->productHelper = $productHelper;
        parent::__construct($context);
    }

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

            $failedImages = $params['failed_images'] ?? [];
            if (!is_array($failedImages)) {
                $failedImages = [];
            }

            $storeId = $params['store_id'];
            
            $country =  $this->scopeConfig->getValue(
                'general/country/default',
                ScopeInterface::SCOPE_STORE,
                $params['store_id']
            );
            $language = $this->storeHelper->getFormattedLanguage($params['store_id']);
            $ipAddress = $this->remoteAddress->getRemoteAddress();

            $category = $this->magentoCategory->getCategory($params['category_id'], $params['store_id']);

            $textData = $this->getTextsParams($params, $language);
            if (isset($params['selected_fields']) && in_array('category_description', $params['selected_fields'])) {
                $featuredUrl = $params['featured_image_url'] ?? ($params['category_image'] ?? '');
                $isFeaturedSelected = filter_var($params['category_image_selected'] ?? false, FILTER_VALIDATE_BOOLEAN);
                $failedImageIds = [];
                if (!empty($failedImages)) {
                    foreach ($failedImages as $failedUrl) {
                        $failedImageIds[] = $this->imageHelper->getCategoryImageId(
                            $params['category_id'],
                            $params['store_id'],
                            $failedUrl
                        );
                    }
                }

                if ($featuredUrl) {
                    $featuredImageId = $this->imageHelper->getCategoryImageId(
                        $params['category_id'],
                        $params['store_id'],
                        $featuredUrl
                    );

                    $isFeaturedFailed = (
                        in_array($featuredUrl, $failedImages, true)
                        || in_array($featuredImageId, $failedImageIds, true)
                    );

                    if ($isFeaturedSelected || $isFeaturedFailed) {
                        if ($isFeaturedFailed) {
                            $featuredImageId = '';
                        }

                        $textData['featuredImage'] = [
                            'url' => $featuredUrl,
                            'imageId' => $featuredImageId
                        ];
                    }
                }
            }

            /** Ensure images referenced by IDs exist in WriteText.ai before generating */
            if (!empty($textData['products']) && is_array($textData['products'])) {
                foreach ($textData['products'] as $productKey => $productData) {
                    if (empty($productData['image']) || empty($productData['imageUrl'])) {
                        continue;
                    }
                    try {
                        $this->imageHelper->getImageApiId(
                            $storeId,
                            $ipAddress,
                            $language,
                            $productData['image'],
                            $productData['imageUrl']
                        );
                    } catch (\Exception $e) {
                        $textData['products'][$productKey]['image'] = '';
                    }
                }
            }

            if (!empty($textData['featuredImage']['imageId']) && !empty($textData['featuredImage']['url'])) {
                try {
                    $this->imageHelper->getImageApiId(
                        $storeId,
                        $ipAddress,
                        $language,
                        $textData['featuredImage']['imageId'],
                        $textData['featuredImage']['url']
                    );
                } catch (\Exception $e) {
                    unset($textData['featuredImage']);
                }
            }

            $isCategoryImageSelected = filter_var($params['category_image_selected'] ?? false, FILTER_VALIDATE_BOOLEAN);
            if ($isCategoryImageSelected && !empty($params['category_image']) && !empty($textData['images'])) {
                $categoryImageId = $this->imageHelper->getCategoryImageId(
                    $params['category_id'],
                    $storeId,
                    $params['category_image']
                );

                if (in_array($categoryImageId, $textData['images'], true)) {
                    try {
                        $this->imageHelper->getImageApiId(
                            $storeId,
                            $ipAddress,
                            $language,
                            $categoryImageId,
                            $params['category_image']
                        );
                    } catch (\Exception $e) {
                        unset($textData['images']);
                    }
                }
            }

            $mappingSettings = $this->fieldHelper->getMappingSettings();
            $publishedContents = [
                'category_description' => $this->outputHelper->categoryAttribute(
                    $category,
                    $category->getData($mappingSettings['category_description'] ?? 'description'),
                    $mappingSettings['category_description'] ?? 'description'
                )
            ];

            $body = [
                "type" => "Category",
                "storeId" => $params['store_id'],
                "language" => $language,
                "queue" => true,
                "countries" => [$country],
                "ipAddress" => $ipAddress,
                "texts" => [$textData]
            ];

            $keywordAnalysis = filter_var(
                $params['keyword_analysis'],
                FILTER_VALIDATE_BOOLEAN
            );
            $deleteResponse = [];
            if ($keywordAnalysis) {
                /**
                 * delete previous optimization first
                 */
                $deleteResponse = $this->keywords->deleteOptimization(
                    $params['store_id'],
                    $params['category_id'],
                    'Category'
                );
                $randomProducts = $this->magentoCategory->getAllProductsNameRandomly(
                    $params['category_id'],
                    $params['store_id']
                );
                $body['keywordOptimization'] = $this->getKeywordOptimizationParams(
                    $params['store_id'],
                    $params,
                    $randomProducts
                );
                $body['development'] = filter_var($this->helper->getKoDev(), FILTER_VALIDATE_BOOLEAN);
            }
            if ($this->helper->getForceQueueSeconds()) {
                $body['developmentQueueWaitTimeInSeconds'] = $this->helper->getForceQueueSeconds();
            }

            if (isset($params['additional_prompt']) && $params['additional_prompt']) {
                $body['specialInstructions'] = $params['additional_prompt'];
            }

            $apiResponse = $this->apiManager->generate(json_encode($body));

            $this->aiCategoryManager->saveDate($params['category_id'], $params['store_id'], 'edited');
            $this->aiCategoryManager->saveDate($params['category_id'], $params['store_id'], 'generated');

            $result = [
                'success' => true,
                'reviewed' => $this->markReview->getReviewed($params['category_id'], $params['store_id']),
                'api_request' => $body,
                'api_response' => $apiResponse,
                'delete_response' => $deleteResponse
            ];
        } 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,
                'api_request' => $body ?? [],
                'api_response' => $apiResponse ?? []
            ];
        }

        $response->setData($result);

        return $response;
    }

    /**
     * Get keyword optimization params
     *
     * @param int $storeId
     * @param array $params
     * @param array $products
     *
     * @return array
     */
    private function getKeywordOptimizationParams($storeId, $params, $products)
    {
        $searchIntent = $params['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('Category');
        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_category'),
            "triggers" => $triggers,
            "doKeywordOptimizationOnly" => false,
            "products" => $products
        ];
        
        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;
    }

    // phpcs:disable Generic.Metrics.NestingLevel.TooHigh
    /**
     * Get texts params
     *
     * @param array $params
     * @param string $language
     * @return array
     */
    private function getTextsParams($params, $language)
    {
        $categoryName = $params['name'];

        $enableResearchRawValue = null;
        if (array_key_exists('wtaiProductResearchData', $params)) {
            $enableResearchRawValue = $params['wtaiProductResearchData'];
        } elseif (array_key_exists('wtai_product_research_data', $params)) {
            $enableResearchRawValue = $params['wtai_product_research_data'];
        } elseif (array_key_exists('product_research_data', $params)) {
            $enableResearchRawValue = $params['product_research_data'];
        }

        $enableResearch = false;
        if ($enableResearchRawValue !== null) {
            $enableResearch = filter_var($enableResearchRawValue, FILTER_VALIDATE_BOOLEAN);
        }

        if (!isset($params['products']) || !is_array($params['products']) || count($params['products']) === 0) {
            $enableResearch = false;
        }
        
        $textsParams = [
            "name" => $params['name'],
            "recordId" => $params['category_id'],
            "options" => 1,
            "autoselectFirst" => true,
            "keywordAnalysisViews" => $params['keyword_analysis_views'],
            "url" => $params['url'],
            "enableResearch" => $enableResearch
        ];

        if (filter_var($params['use_ai_model'], FILTER_VALIDATE_BOOLEAN)) {
            $textsParams['brandVoiceId'] = $params['selected_ai_model'];
        }

        if (filter_var($params['other_details_checked'], FILTER_VALIDATE_BOOLEAN)) {
            $textsParams['otherDetails'] = $this->filterManager->stripTags($params['other_details']);
        }
        $useAiModel = filter_var($params['use_ai_model'], FILTER_VALIDATE_BOOLEAN);
        if (!$useAiModel) {
            if (in_array('custom', $params['tones'])) {
                $textsParams['customTone'] = $params['custom_tone'];
            } else {
                $textsParams['tones'] = $params['tones'];
            }

            if ($params['style'] === 'custom') {
                $textsParams['customStyle'] = $params['custom_style'];
            } else {
                $textsParams['style'] = $params['style'];
            }

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

            if (isset($params['custom_audience'])) {
                $textsParams['customAudience'] = $params['custom_audience'];
            }
        }
        $rules = $this->settings->getSettings('rules');
        $credits = $this->settings->getSettings('credits');

        $maxInputChar = ((($rules['maxOutputWords'] / $credits['wordsPerCredit']) - 1
            ) * $rules['additionalReferenceTextLength']
        ) + $rules['maxReferenceTextLength'];

        $fields = [];
        foreach ($params['selected_fields'] as $selectedField) {
            $field = [];
            $field['field'] = Fields::CATEGORY_MAPPING[$selectedField];
            
            if (Fields::CATEGORY_MAPPING[$selectedField] === Fields::CATEGORY_DESCRIPTION) {
                $field["minWords"] = $params['min_words'];
                $field["maxWords"] = $params['max_words'];
            }

            $selectedFieldTemplate = $selectedField === 'page_title' ? 'category_page_title' : $selectedField;
            if (isset($params['templates_used'][$selectedFieldTemplate]) &&
                $params['templates_used'][$selectedFieldTemplate]) {
                $field['templateId'] = $params['templates_used'][$selectedFieldTemplate];
            }

            $fields[] = $field;
        }

        $textsParams['fields'] = $fields;

        if (isset($params['products']) && is_array($params['products'])) {
            $failedImages = $params['failed_images'] ?? [];
            if (!is_array($failedImages)) {
                $failedImages = [];
            }

            $products = [];
            foreach ($params['products'] as $product) {
                $productData = [
                    "id" => $product['value'] ?? '',
                    "name" => $product['label'] ?? '',
                    "description" => $product['description'] ?? ''
                ];

                $providedImageUrl = $product['image_url'] ?? ($product['imageUrl'] ?? '');
                if (!empty($providedImageUrl)) {
                    $productData['imageUrl'] = $providedImageUrl;
                }

                if (!empty($productData['imageUrl']) &&
                    strpos($productData['imageUrl'], '/cache/') !== false &&
                    isset($product['value']) && !empty($product['value'])
                ) {
                    $productObject = $this->productRepository->getById(
                        $product['value'],
                        false,
                        $params['store_id']
                    );
                    $galleryImages = $this->productHelper->getImages(
                        $productObject,
                        $params['store_id'],
                        $language
                    );

                    // phpcs:ignore Magento2.Functions.DiscouragedFunction.Discouraged
                    $providedBasename = basename(parse_url($productData['imageUrl'], PHP_URL_PATH) ?: '');
                    foreach ($galleryImages as $galleryImage) {
                        // phpcs:disable Magento2.Functions.DiscouragedFunction.Discouraged
                        $galleryBasename = basename(
                            parse_url($galleryImage['noncached_url'] ?? '', PHP_URL_PATH) ?: ''
                        );
                        // phpcs:enable Magento2.Functions.DiscouragedFunction.Discouraged
                        if ($providedBasename && $galleryBasename && $providedBasename === $galleryBasename) {
                            $productData['imageUrl'] = $galleryImage['noncached_url'];
                            if (empty($productData['image']) && !empty($galleryImage['id'])) {
                                $productData['image'] = $galleryImage['id'];
                            }
                            break;
                        }
                    }
                }

                if (!empty($product['image_id'])) {
                    $productData['image'] = $product['image_id'];

                    if (isset($product['value']) && !empty($product['value'])) {
                        $productObject = $this->productRepository->getById(
                            $product['value'],
                            false,
                            $params['store_id']
                        );
                        $galleryImages = $this->productHelper->getImages(
                            $productObject,
                            $params['store_id'],
                            $language
                        );
                        foreach ($galleryImages as $galleryImage) {
                            if ($galleryImage['id'] === $product['image_id']) {
                                $productData['imageUrl'] = $galleryImage['noncached_url'];

                                if (!empty($productData['imageUrl'])
                                    && in_array($productData['imageUrl'], $failedImages, true)
                                ) {
                                    $productData['image'] = '';
                                }
                            }
                        }
                    }
                }

                if (!empty($productData['imageUrl'])
                    && in_array($productData['imageUrl'], $failedImages, true)
                ) {
                    $productData['image'] = '';
                }

                $products[] = $productData;
            }
            $textsParams['products'] = $products;
        }

        if ($params['category_image'] && filter_var($params['category_image_selected'], FILTER_VALIDATE_BOOLEAN)) {
            $textsParams['images'] = [
                $this->imageHelper->getCategoryImageId(
                    $params['category_id'],
                    $params['store_id'],
                    $params['category_image']
                )
            ];
        }
        return $textsParams;
    }
    // phpcs:enable Generic.Metrics.NestingLevel.TooHigh

    /**
     * Get image URL for a category
     *
     * @param \Magento\Catalog\Model\Category $category
     * @param int $storeId
     * @param array $params
     * @return array
     */
    private function getImageUrl($category, $storeId, $params)
    {
        try {
            $categoryImage = [];
            if ($category->getImage()) {
                $categoryImageUrl = $this->imageHelper->getCategoryImageUrl($category);
            }
            if ($categoryImageUrl) {
                $imageId = $this->imageHelper->getCategoryImageId(
                    $params['category_id'],
                    $params['store_id'],
                    $categoryImageUrl
                );
                if (isset($params['category_image']) && !empty($params['category_image'])) {
                    $categoryImage = [
                        "imageId" =>  $imageId,
                        "url" => $categoryImageUrl
                    ];
                }
            }
            return $categoryImage;
        } catch (\Exception $e) {
            return '';
        }
    }
}
