<?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\Controller\ResultFactory;
use WriteTextAI\WriteTextAI\Model\ApiManager;
use WriteTextAI\WriteTextAI\Model\Api\Keywords as ApiKeywords;
use WriteTextAI\WriteTextAI\Model\OptionSource\Filter\Stores as StoresFilter;
use WriteTextAI\WriteTextAI\Model\Magento\Category as MagentoCategory;
use WriteTextAI\WriteTextAI\Helper\Store as StoreHelper;
use WriteTextAI\WriteTextAI\Helper\Data as DataHelper;
use WriteTextAI\WriteTextAI\Model\Api\Session as ApiSession;
use WriteTextAI\WriteTextAI\Helper\Categories\Fields as FieldHelper;
use WriteTextAI\WriteTextAI\Helper\Generate as GenerateHelper;
use WriteTextAI\WriteTextAI\Model\GenerateOptionsManager;
use WriteTextAI\WriteTextAI\ViewModel\UserFieldsSelected;
use WriteTextAI\WriteTextAI\Model\UserFieldsSelectedManager;
use WriteTextAI\WriteTextAI\ViewModel\Settings;
use WriteTextAI\WriteTextAI\Model\AiCategoryManager;
use WriteTextAI\WriteTextAI\Model\Categories\GeneratedText as CategoryGeneratedText;
use Magento\Store\Model\StoreManagerInterface;
use WriteTextAI\WriteTextAI\Helper\Categories\RepresentativeProducts as RepresentativeProductsHelper;
use WriteTextAI\WriteTextAI\Model\KeywordIdeaFiltersManager;
use WriteTextAI\WriteTextAI\Helper\ReviewStatus as ReviewHelper;
use WriteTextAI\WriteTextAI\Model\Categories\MarkReview;
use WriteTextAI\WriteTextAI\Helper\Categories\Data as CategoriesDataHelper;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Catalog\Helper\Image as ImageHelper;
use WriteTextAI\WriteTextAI\Helper\Image as WtaImageHelper;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
use Magento\Catalog\Helper\Output as OutputHelper;
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite as UrlRewriteData;
use Magento\UrlRewrite\Model\UrlFinderInterface;
use WriteTextAI\WriteTextAI\Helper\Optimization as OptimizationHelper;
use Magento\User\Model\ResourceModel\User\CollectionFactory as UserCollectionFactory;

class Index extends Action
{
    /**
     * @var ApiManager
     */
    protected $apiManager;

    /**
     * @var ApiKeywords
     */
    protected $apiKeywords;

    /**
     * @var StoresFilter
     */
    protected $storesFilter;

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

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

    /**
     * @var DataHelper
     */
    protected $dataHelper;

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

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

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

    /**
     * @var GenerateOptionsManager
     */
    protected $generateOptionsManager;

    /**
     * @var UserFieldsSelected
     */
    protected $userFieldsSelected;

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

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

    /**
     * @var CategoryGeneratedText
     */
    protected $categoryGeneratedText;

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

    /**
     * @var RepresentativeProductsHelper
     */
    protected $representativeProductsHelper;

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

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

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

    /**
     * @var CategoriesDataHelper
     */
    protected $categoriesDataHelper;

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

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

    /**
     * @var WtaImageHelper
     */
    protected $wtaImageHelper;

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

    /**
     * @var UrlFinderInterface
     */
    protected $urlFinder;

    /**
     * @var OptimizationHelper
     */
    protected $optimizationHelper;

    /**
     * @var UserCollectionFactory
     */
    protected $userCollectionFactory;

    /**
     * Constructor
     *
     * @param Context $context
     * @param ApiManager $apiManager
     * @param ApiKeywords $apiKeywords
     * @param StoresFilter $storesFilter
     * @param MagentoCategory $magentoCategory
     * @param StoreHelper $storeHelper
     * @param DataHelper $dataHelper
     * @param ApiSession $apiSession
     * @param FieldHelper $fieldHelper
     * @param GenerateHelper $generateHelper
     * @param GenerateOptionsManager $generateOptionsManager
     * @param UserFieldsSelected $userFieldsSelected
     * @param Settings $settings
     * @param AiCategoryManager $aiCategoryManager
     * @param CategoryGeneratedText $categoryGeneratedText
     * @param StoreManagerInterface $storeManager
     * @param RepresentativeProductsHelper $representativeProductsHelper
     * @param KeywordIdeaFiltersManager $keywordIdeaFiltersManager
     * @param ReviewHelper $reviewHelper
     * @param MarkReview $markReview
     * @param CategoriesDataHelper $categoriesDataHelper
     * @param CollectionFactory $productCollectionFactory
     * @param ImageHelper $imageHelper
     * @param WtaImageHelper $wtaImageHelper
     * @param OutputHelper $outputHelper
     * @param UrlFinderInterface $urlFinder
     * @param OptimizationHelper $optimizationHelper
     * @param UserCollectionFactory $userCollectionFactory
     */
    public function __construct(
        Context $context,
        ApiManager $apiManager,
        ApiKeywords $apiKeywords,
        StoresFilter $storesFilter,
        MagentoCategory $magentoCategory,
        StoreHelper $storeHelper,
        DataHelper $dataHelper,
        ApiSession $apiSession,
        FieldHelper $fieldHelper,
        GenerateHelper $generateHelper,
        GenerateOptionsManager $generateOptionsManager,
        UserFieldsSelected $userFieldsSelected,
        Settings $settings,
        AiCategoryManager $aiCategoryManager,
        CategoryGeneratedText $categoryGeneratedText,
        StoreManagerInterface $storeManager,
        RepresentativeProductsHelper $representativeProductsHelper,
        KeywordIdeaFiltersManager $keywordIdeaFiltersManager,
        ReviewHelper $reviewHelper,
        MarkReview $markReview,
        CategoriesDataHelper $categoriesDataHelper,
        CollectionFactory $productCollectionFactory,
        ImageHelper $imageHelper,
        WtaImageHelper $wtaImageHelper,
        OutputHelper $outputHelper,
        UrlFinderInterface $urlFinder,
        OptimizationHelper $optimizationHelper,
        UserCollectionFactory $userCollectionFactory
    ) {
        $this->apiManager = $apiManager;
        $this->apiKeywords = $apiKeywords;
        $this->storesFilter = $storesFilter;
        $this->magentoCategory = $magentoCategory;
        $this->storeHelper = $storeHelper;
        $this->dataHelper = $dataHelper;
        $this->apiSession = $apiSession;
        $this->fieldHelper = $fieldHelper;
        $this->generateHelper = $generateHelper;
        $this->generateOptionsManager = $generateOptionsManager;
        $this->userFieldsSelected = $userFieldsSelected;
        $this->settings = $settings;
        $this->aiCategoryManager = $aiCategoryManager;
        $this->categoryGeneratedText = $categoryGeneratedText;
        $this->storeManager = $storeManager;
        $this->representativeProductsHelper = $representativeProductsHelper;
        $this->keywordIdeaFiltersManager = $keywordIdeaFiltersManager;
        $this->reviewHelper = $reviewHelper;
        $this->markReview = $markReview;
        $this->categoriesDataHelper = $categoriesDataHelper;
        $this->productCollectionFactory = $productCollectionFactory;
        $this->imageHelper = $imageHelper;
        $this->wtaImageHelper = $wtaImageHelper;
        $this->outputHelper = $outputHelper;
        $this->urlFinder = $urlFinder;
        $this->optimizationHelper = $optimizationHelper;
        $this->userCollectionFactory = $userCollectionFactory;
        parent::__construct($context);
    }

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

        try {
            $request = $this->getRequest();
            $categoryId = $request->getParam('category_id');
            $storeId = $request->getParam('store_id');
            $currentUser = $this->apiSession->getCurrentUser();
            $category = $this->magentoCategory->getCategory($categoryId, $storeId);
            $subcategories = $this->magentoCategory->getAllChildren(true, $categoryId, $storeId);
            $representativeProducts = $this->magentoCategory->getProductCollection($subcategories, $storeId);
            $generatedText = $this->categoryGeneratedText->getGenerated($categoryId, $storeId, 'Category');
            $aiCategory = $this->aiCategoryManager->getCategory($categoryId, $storeId);

            $mappingSettings = $this->fieldHelper->getMappingSettings();
            $useDefault = [];
            foreach ($mappingSettings as $field => $value) {
                $useDefault[$field] = $this->fieldHelper->isUsingDefaultValues(
                    $category,
                    $storeId,
                    $value
                );
            }
        
            $locationCode = $this->keywordIdeaFiltersManager->getLocationCode($storeId);
            $languageCode = $this->storeHelper->getRegionIndependentLanguage($storeId);

            $categoryImage = '';
            if ($category->getImage()) {
                $categoryImage = rtrim(
                    $this->storeManager->getStore()->getBaseUrl(
                        \Magento\Framework\UrlInterface::URL_TYPE_DIRECT_LINK
                    ),
                    '/'
                ) . $category->getImage();
            }

            $categoryUrl = $this->getUrlByCategoryId($category, $categoryId, $storeId);

            $categoryName = $category->getName();

            $searchIntent = $this->userFieldsSelected->getUserFieldsSelected(
                UserFieldsSelectedManager::ACTION_TYPE_SEARCH_INTENT,
                'category',
                ''
            );
            if ($searchIntent) {
                $searchIntentSelected = explode(',', $searchIntent);
            } else {
                $searchIntentSelected = explode(
                    ',',
                    'commercial'
                );
            }
            
            $optimizationData = $this->apiKeywords->getOptimization(
                $storeId,
                $categoryId,
                'Category'
            );
            
            $result = [
                'success' => true,
                'api_texts' => $generatedText,
                'language' => strtoupper($languageCode),
                'country' => $this->keywordIdeaFiltersManager->getCountryCode($storeId),
                'location' => $locationCode,
                'stores' => array_values($this->storesFilter->toOptionArray()),
                'store_scope' => $this->storeHelper->getStoreScope($storeId),
                'store_id' => $storeId,
                'category_data' => $category->getData(),
                'name' => $categoryName,
                'is_active' => (bool)$category->getIsActive(),
                'category_placeholder_image' => $this->imageHelper->getDefaultPlaceholderUrl('thumbnail'),
                'image' => $categoryImage,
                'image_id' => $this->wtaImageHelper->getCategoryImageId($categoryId, $storeId, $category->getImage()),
                'api_thumbnail' => $optimizationData['imageId'] ?? '',
                'breadcrumbs' => $this->categoriesDataHelper->getBreadcrumbs($category, $storeId),
                'users' => $this->getUsers(),
                'use_default_image' => $this->fieldHelper->isUsingDefaultValues(
                    $category,
                    $storeId,
                    'image'
                ),
                'representative_products' => [
                    'options' => $representativeProducts['options'],
                    'total' => $representativeProducts['total'],
                    'selected' => $this->removeNonExistingProducts(
                        $this->representativeProductsHelper->getRepresentativeProductsSelected($aiCategory),
                        $representativeProducts['all_options'],
                        $storeId
                    ),
                    'other_details_checked' => (bool)$aiCategory->getOtherDetailsChecked(),
                    'other_details' => $aiCategory->getOtherDetails(),
                    'product_research_data' => $this->userFieldsSelected->getUserFieldsSelected(
                        UserFieldsSelectedManager::ACTION_TYPE_PRODUCT_RESEARCH_DATA,
                        '',
                        ''
                    ) === "true"
                ],
                'additional_prompt' => $aiCategory->getAdditionalPrompt(),
                'link_preview_url' => $categoryUrl,
                'preview_changes_url' => $categoryUrl. '?' . http_build_query([
                    'wtai-preview' => base64_encode($currentUser->getId())
                ]),
                'texts' => [
                    'category_description' => (string) $this->outputHelper->categoryAttribute(
                        $category,
                        $category->getData($mappingSettings['category_description'] ?? 'description'),
                        $mappingSettings['category_description'] ?? 'description'
                    ),
                    'page_title' => (string) $category->getMetaTitle(),
                    'page_description' => (string) $category->getMetaDescription()
                ],
                'generated_texts' => $this->categoryGeneratedText->getTextFields(
                    $categoryId,
                    $storeId,
                    false,
                    $generatedText
                ),
                'textfields_statuses' => $this->categoryGeneratedText->getTextFieldsStatuses(
                    $categoryId,
                    $storeId,
                    $generatedText
                ),
                'keywords_used' => $this->categoryGeneratedText->getTextsKeywordsUsed($generatedText),
                'use_default' => $useDefault,
                'reviewed' => $this->markReview->getReviewed($categoryId, $storeId, $generatedText),
                'review_status' => $this->reviewHelper->getCategoryReviewStatus($categoryId, $storeId),
                'feedback' => $this->categoryGeneratedText->getTextsFeedback($generatedText),
                'search_intent_selected' => $searchIntentSelected,
                'templates_used' => $this->categoryGeneratedText->getTextFieldsTemplate(
                    $categoryId,
                    $storeId,
                    $generatedText
                )
            ];

            $result['optimization'] = $optimizationData;
            $selectedKeywords = $this->getSelectedKeywords(
                $optimizationData,
                $categoryName,
                $storeId,
                $categoryId
            );

            $settingsData = $this->getSettingsData($storeId, $categoryId, $categoryName, $selectedKeywords);
            $userPreferences = $this->getUserPreferences();

            $result = array_merge(
                $result,
                $settingsData,
                $userPreferences,
                $selectedKeywords
            );
        } catch (\Exception $e) {
            $result = [
                'success' => false,
                'message' => __(
                    'A system error has occurred. Please try again. If the issue persists,'
                    . ' please contact our support team at support@writetext.ai.'
                ),
                'error' => $e->getMessage(),
                'trace' => $e->getTrace()
            ];
        }

        $response->setData($result);

        return $response;
    }

    /**
     * Get category url
     *
     * @param \Magento\Catalog\Model\Category $category
     * @param int $categoryId
     * @param int $storeId
     * @return string
     */
    public function getUrlByCategoryId($category, $categoryId, $storeId)
    {
        $rewrite = $this->urlFinder->findOneByData([
            UrlRewriteData::ENTITY_ID => $categoryId,
            UrlRewriteData::ENTITY_TYPE => 'category',
            UrlRewriteData::STORE_ID => $storeId
        ]);
        
        $category->getUrlInstance()->setScope($storeId);
        
        $targetPath = (!$rewrite) ? $category->getUrl() :
            $this->storeManager->getStore($storeId)->getBaseUrl() . $rewrite->getRequestPath();

        return $targetPath;
    }

    /**
     * Remove non-existing products
     *
     * @param array $selected
     * @param array $options
     * @param int $storeId
     *
     * @return array
     */
    private function removeNonExistingProducts($selected, $options, $storeId)
    {
        $newSelected = [];

        foreach ($selected as $_selected) {
            if (in_array($_selected->value, $options)) {
                $newSelected[] = $_selected;
            }
        }

        $newSelected = $this->updateProductData($newSelected, $storeId);

        return $newSelected;
    }

    /**
     * Update product data
     *
     * @param array $selected
     * @param int $storeId
     *
     * @return array
     */
    private function updateProductData($selected, $storeId)
    {
        $ids = [];
        foreach ($selected as $_selected) {
            $ids[] = $_selected->value;
        }

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

        $newSelected = [];
        $mappingSettings = $this->dataHelper->getMappingSettings();
        foreach ($collection as $product) {
            $image = $this->imageHelper->init($product, 'product_listing_thumbnail')
                ->setImageFile($product->getThumbnail())
                ->getUrl();
            $imageId = $this->wtaImageHelper->getImageValue($product);
            $status = $product->getStatus() == Status::STATUS_ENABLED ? __('enabled') : __('disabled');
            $newSelected[] = [
                'value' => $product->getId(),
                'label' => $product->getName(),
                'image' => $image,
                'image_id' => $imageId,
                'description' => $product->getData($mappingSettings['product_description']),
                'status' => sprintf("(%s)", $status)
            ];
        }

        return $newSelected;
    }

    /**
     * Get user preferences
     *
     * @return array
     */
    private function getUserPreferences()
    {
        // $userDescMin = $this->userFieldsSelected->getUserFieldsSelected(
        //     UserFieldsSelectedManager::ACTION_TYPE_DESC_MIN,
        //     '',
        //     ''
        // );
        // $userDescMax = $this->userFieldsSelected->getUserFieldsSelected(
        //     UserFieldsSelectedManager::ACTION_TYPE_DESC_MAX,
        //     '',
        //     ''
        // );

        // if (!$userDescMin) {
            $userDescMin = $this->dataHelper->getCategoryDescriptionSettings('min');
        // }
        // if (!$userDescMax) {
            $userDescMax = $this->dataHelper->getCategoryDescriptionSettings('max');
        // }
        
        return [
            'guide_steps' => filter_var($this->userFieldsSelected->getUserFieldsSelected(
                UserFieldsSelectedManager::ACTION_TYPE_GUIDE_STEPS,
                '',
                'edit'
            ), FILTER_VALIDATE_BOOLEAN),
            'selected_fields' => $this->userFieldsSelected->getUserFieldsSelected(
                UserFieldsSelectedManager::ACTION_TYPE_SINGLE_EDITOR_FIELDS,
                'category',
                'edit'
            ),
            'highlight_pronouns' => $this->userFieldsSelected->getUserFieldsSelected(
                UserFieldsSelectedManager::ACTION_TYPE_HIGHLIGHT_PRONOUNS,
                '',
                'edit'
            ),
            'custom_tone' => $this->userFieldsSelected->getUserFieldsSelected(
                UserFieldsSelectedManager::ACTION_TYPE_CUSTOM_TONE,
                '',
                ''
            ),
            'custom_style' => $this->userFieldsSelected->getUserFieldsSelected(
                UserFieldsSelectedManager::ACTION_TYPE_CUSTOM_STYLE,
                '',
                ''
            ),
            'category_image_selected' => $this->userFieldsSelected->getUserFieldsSelected(
                UserFieldsSelectedManager::ACTION_TYPE_CATEGORY_IMAGE,
                'category',
                'edit'
            ),
            'auto_generate_after_ko' => filter_var($this->userFieldsSelected->getUserFieldsSelected(
                UserFieldsSelectedManager::ACTION_TYPE_AUTO_GENERATE_AFTER_KO,
                '',
                'edit'
            ), FILTER_VALIDATE_BOOLEAN),
            'desc_min' => $userDescMin,
            'desc_max' => $userDescMax
        ];
    }

    /**
     * Get settings parameters
     *
     * @param int $storeId
     * @param int $categoryId
     * @param string $categoryName
     * @param array $selectedKeywords
     *
     * @return array
     */
    private function getSettingsData($storeId, $categoryId, $categoryName, $selectedKeywords)
    {
        $tones = $this->generateHelper->updateDefault(
            $this->generateOptionsManager->getOptions('tones'),
            $this->userFieldsSelected->getUserFieldsSelected(
                UserFieldsSelectedManager::ACTION_TYPE_TONES,
                '',
                ''
            )
        );

        $userStyles = $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_STYLE,
            '',
            ''
        );

        $styles = $this->generateHelper->updateDefault(
            $this->generateOptionsManager->getOptions('styles'),
            $userStyles ? [$userStyles] : []
        );

        $audiences = $this->generateHelper->updateDefault(
            $this->generateOptionsManager->getOptions('audience'),
            $this->userFieldsSelected->getUserFieldsSelected(
                UserFieldsSelectedManager::ACTION_TYPE_AUDIENCES,
                '',
                ''
            )
        );
        
        $audience = [];
        $keywords = [$categoryName];
        if (isset($selectedKeywords['selected_keywords'])) {
            $keywordsData = $selectedKeywords['selected_keywords'];
            if (isset($selectedKeywords['optimizing_keywords']) && !empty($selectedKeywords['optimizing_keywords'])) {
                $keywordsData = $selectedKeywords['optimizing_keywords'];
            }
            //make sure selected_keywords are all small letters
            $keywordsData = array_map('strtolower', $keywordsData);
            $keywords = array_merge($keywords, $keywordsData);
            $audience = $this->apiManager->getSuggestedAudience(
                $storeId,
                $categoryId,
                $keywords,
                'false',
                'Category'
            );
        }

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

        $langCode = $this->storeHelper->getRegionIndependentLanguage($storeId);

        $formalLanguages = [];
        if (in_array($langCode, $formalLanguageSupport)) {
            $formalLanguages = $this->settings->getFormalLanguages($langCode);
        }

        return [
            'tones' => $tones,
            'styles' => $styles,
            'audience' => $audiences,
            'selected_audience' => $audience['selected'] ?? [],
            'suggested_audience' => $audience['values'] ?? [],
            'disallowed_combinations' => $this->settings->getSettings('disallowedCombinations'),
            'formal_language_support' => $formalLanguageSupport,
            'formal_languages' => $formalLanguages,
            'global_triggers' => $this->optimizationHelper->getGlobalTriggers('Category')
        ];
    }

    /**
     * Get selected keywords
     *
     * @param array $optimizationData
     * @param string $categoryName
     * @param int $storeId
     * @param int $categoryId
     */
    private function getSelectedKeywords($optimizationData, $categoryName, $storeId, $categoryId)
    {
        /**
         * Get selected keywords for optimizationData
         */
        $keywords = [];
        $optimizingKeywords = [];
        if (empty($optimizationData)) {
            $invalidChars = '/[,\.!@%^*()={};~`<>?\\\\|]/';
            $categoryName = preg_replace($invalidChars, '', $categoryName);
            $seedKeywords = [$categoryName];
            $this->apiKeywords->saveManualKeywords($storeId, $categoryId, $seedKeywords, 'Category');
            $keywords = $seedKeywords;
        } else {
            $keywords = $optimizationData['manualKeywords'] ?? [];
            $optimizingKeywords = $optimizationData['optimizingKeywords'] ?? [];
        }

        return [
            'selected_keywords' => $keywords,
            'optimizing_keywords' => $optimizingKeywords
        ];
    }
    
    /**
     * Get users
     *
     * @return array
     */
    private function getUsers()
    {
        $collection = $this->userCollectionFactory->create();
        $users = [];

        foreach ($collection as $user) {
            $users[] = [
                'id' => $user->getUserId(),
                'name' => $user->getFirstname() . ' ' . $user->getLastname()
            ];
        }

        return $users;
    }
}
