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

declare(strict_types=1);

namespace WriteTextAI\WriteTextAI\Controller\Adminhtml\Settings;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Controller\ResultFactory;
use WriteTextAI\WriteTextAI\Helper\Data;
use WriteTextAI\WriteTextAI\Model\Config\Source\ProductAttributes;
use WriteTextAI\WriteTextAI\Model\Config\Source\TriggerActions;
use WriteTextAI\WriteTextAI\Model\Config\Source\AutomaticTextOptimization;
use WriteTextAI\WriteTextAI\Model\GenerateOptionsManager;
use WriteTextAI\WriteTextAI\Model\UserFieldsSelectedManager;
use WriteTextAI\WriteTextAI\ViewModel\Tooltip;
use WriteTextAI\WriteTextAI\ViewModel\Permissions;
use WriteTextAI\WriteTextAI\ViewModel\Settings;
use WriteTextAI\WriteTextAI\ViewModel\UserFieldsSelected;
use WriteTextAI\WriteTextAI\ViewModel\TemplateSettings;
use Magento\Framework\View\LayoutInterface;
use WriteTextAI\WriteTextAI\Model\Config\Source\ProductTexts;
use WriteTextAI\WriteTextAI\Model\Config\Source\DefaultValues\ProductTexts as DefaultProductTexts;
use WriteTextAI\WriteTextAI\Helper\CronStatus;

class Prompt extends Action
{
    /**
     * @var Data
     */
    protected $helper;

    /**
     * @var ProductAttributes
     */
    protected $attributes;

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

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

    /**
     * @var Tooltip
     */
    protected $tooltip;

    /**
     * @var Permissions
     */
    protected $permissions;

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

    /**
     * @var UserFieldsSelectedManager
     */
    protected $userFieldsSelectedManager;

    /**
     * @var LayoutInterface
     */
    protected $layout;

    /**
     * @var TemplateSettings
     */
    protected $templateSettings;

    /**
     * @var ProductTexts
     */
    protected $productTexts;

    /**
     * @var DefaultProductTexts
     */
    protected $defaultProductTexts;

    /**
     * @var CronStatus
     */
    protected $cronStatus;

    /**
     * Constructor
     *
     * @param Context $context
     * @param Data $helper
     * @param ProductAttributes $attributes
     * @param GenerateOptionsManager $generateOptionsManager
     * @param UserFieldsSelected $userFieldsSelected
     * @param Tooltip $tooltip
     * @param Permissions $permissions
     * @param Settings $settings
     * @param UserFieldsSelectedManager $userFieldsSelectedManager
     * @param LayoutInterface $layout
     * @param TemplateSettings $templateSettings
     * @param ProductTexts $productTexts
     * @param DefaultProductTexts $defaultProductTexts
     * @param CronStatus $cronStatus
     */
    public function __construct(
        Context $context,
        Data $helper,
        ProductAttributes $attributes,
        GenerateOptionsManager $generateOptionsManager,
        UserFieldsSelected $userFieldsSelected,
        Tooltip $tooltip,
        Permissions $permissions,
        Settings $settings,
        UserFieldsSelectedManager $userFieldsSelectedManager,
        LayoutInterface $layout,
        TemplateSettings $templateSettings,
        ProductTexts $productTexts,
        DefaultProductTexts $defaultProductTexts,
        CronStatus $cronStatus
    ) {
        $this->helper = $helper;
        $this->attributes = $attributes;
        $this->generateOptionsManager = $generateOptionsManager;
        $this->userFieldsSelected = $userFieldsSelected;
        $this->tooltip = $tooltip;
        $this->permissions = $permissions;
        $this->settings = $settings;
        $this->userFieldsSelectedManager = $userFieldsSelectedManager;
        $this->layout = $layout;
        $this->templateSettings = $templateSettings;
        $this->productTexts = $productTexts;
        $this->defaultProductTexts = $defaultProductTexts;
        $this->cronStatus = $cronStatus;
        parent::__construct($context);
    }

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

        try {
            $params = $this->getRequest()->getParams();
            $getTemplateSettings = $params['getTemplateSettings'] ?? 'false';
            $getTemplateSettings = $getTemplateSettings === 'true';

            $rules = $this->getRules();
            $triggerActions = $this->getTriggerActions();

            $data = [
                'tones' => $this->getTones(),
                'tones_selected' => $this->getTonesSelected(),
                'custom_tone' => $this->getCustomTone(),
                'styles' => $this->getStyles(),
                'styles_selected' => $this->getStylesSelected(),
                'custom_style' => $this->getCustomStyle(),
                'audiences' => $this->getAudience(),
                'audience_selected' => $this->getAudienceSelected(),
                'attributes' => $this->getAttributes(),
                'attributes_selected' => $this->getAttributesSelected(),
                'desc_min' => $this->getDescriptionMin(),
                'desc_max' => $this->getDescriptionMax(),
                'exc_min' => $this->getExcerptMin(),
                'exc_max' => $this->getExcerptMax(),
                'special_instructions' => $this->getSpecialInstructions(),
                'selected_fields' => $this->getFieldsSelected(),
                'rules' => $rules,
                'maxOutputWords' => $rules['maxOutputWords'],
                'minOutputWords' => $rules['minOutputWords'],
                'maxOtherDetailsLength' => $rules['maxOtherDetailsLength'],
                'disallowedCombinations' => $this->getDisallowedCombinations(),
                'attrAllowed' => $this->isAttrAllowed(),
                'toneStyleAllowed' => $this->isToneStyleAllowed(),
                'wordsAllowed' => $this->isWordsAllowed(),
                'transferAllowed' => $this->isTransferAllowed(),
                "autoTextOptimizationSelected" => $this->getAutomaticTextOptimizationSelected(),
                "searchIntent" => $this->getSearchIntent(),
                "clusterCount" => $this->getClusterCount(),
                "maxClusterCount" => (int)(($rules['maxKeywords'] ?? 6) - 1),
                "minClusterCount" => $rules['minClusterBasedPipelinesCount'] ?? 1,
                "isCronAvailable" => $this->isCronRunning(),
                "triggerActions" => $triggerActions,
                "triggerActionNPositionLow" => $triggerActions['low']['trigger_action_n_position'] ?? '',
                "triggerActionNDaysLow" => $triggerActions['low']['trigger_action_n_days'] ?? '',
                "triggerActionNPositionLowMid" => $triggerActions['low_mid']['trigger_action_n_position'] ?? '',
                "triggerActionNDaysLowMid" => $triggerActions['low_mid']['trigger_action_n_days'] ?? '',
                "triggerActionNPositionMid" => $triggerActions['mid']['trigger_action_n_position'] ?? '',
                "triggerActionNDaysMid" => $triggerActions['mid']['trigger_action_n_days'] ?? '',
                "triggerActionNPositionMidHigh" => $triggerActions['mid_high']['trigger_action_n_position'] ?? '',
                "triggerActionNDaysMidHigh" => $triggerActions['mid_high']['trigger_action_n_days'] ?? '',
                "minTriggerActionNPosition" => $rules['minTriggerActionNPosition'] ?? 2,
                "maxTriggerActionNPosition" => $rules['maxTriggerActionNPosition'] ?? 100,
                "minTriggerActionNDays" => $rules['minTriggerActionNDays'] ?? 1,
                "maxTriggerActionNDays" => $rules['maxTriggerActionNDays'] ?? 365,
                "productFields" => $this->getDefaultProductTexts(),
                "allProductFields" => array_column($this->getProductFields(), 'value'),
                "automaticTextOptimizationOptions" => $this->getAutomaticTextOptimizationOptions()
            ];
            
            if ($getTemplateSettings) {
                $data['currentTemplateSettings'] = $this->getCurrentTemplateSettings();
                $data['fields'] = $this->getFields();
            }
            
            $result = [
                'success' => true,
                'data' => $data
            ];
        } 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 automatic text optimization options
     *
     * @return array
     */
    public function getAutomaticTextOptimizationOptions()
    {
        return $this->helper->getAutomaticTextOptimizationOptions();
    }

    /**
     * Is Attribute Allowed
     *
     * @return bool
     */
    public function isAttrAllowed()
    {
        return $this->permissions->isAttrAllowed();
    }

    /**
     * Is Tone Style Allowed
     *
     * @return bool
     */
    public function isToneStyleAllowed()
    {
        return $this->permissions->isToneStyleAllowed();
    }

    /**
     * Is Words Allowed
     *
     * @return bool
     */
    public function isWordsAllowed()
    {
        return $this->permissions->isWordsAllowed();
    }

    /**
     * Is Transfer Allowed
     *
     * @return bool
     */
    public function isTransferAllowed()
    {
        return $this->permissions->isTransferAllowed();
    }

    /**
     * Get tooltip
     *
     * @param string $block
     * @return string
     */
    public function getTooltip($block)
    {
        return $this->tooltip->getTooltip($block);
    }

    /**
     * Get tones
     *
     * @return array
     */
    public function getTones()
    {
        return $this->generateOptionsManager->getOptions('tones');
    }

    /**
     * Get tones selected
     *
     * @return array
     */
    public function getTonesSelected()
    {
        $userPreference = $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_TONES,
            'global',
            'grid'
        );

        if (!empty($userPreference)) {
            return $userPreference;
        } else {
            return $this->getTonesFromGlobalSettings();
        }
    }

    /**
     * Get custom tone
     *
     * @return string
     */
    public function getCustomTone()
    {
        return $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_CUSTOM_TONE,
            'global',
            'grid'
        );
    }

    /**
     * Get custom style
     *
     * @return string
     */
    public function getCustomStyle()
    {
        return $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_CUSTOM_STYLE,
            'global',
            'grid'
        );
    }

    /**
     * Get tones from global settings
     *
     * @return array
     */
    private function getTonesFromGlobalSettings()
    {
        $tones = $this->getTones();

        if (!is_array($tones)) {
            return [];
        }

        $tonesSelected = array_filter($tones, function ($tone) {
            return isset($tone['default']) && $tone['default'] === true;
        });

        if (empty($tonesSelected)) {
            return [];
        }

        $tonesSelected = array_column($tonesSelected, 'id');

        return $tonesSelected;
    }

    /**
     * Get styles
     *
     * @return array
     */
    public function getStyles()
    {
        return $this->generateOptionsManager->getOptions('styles');
    }

    /**
     * Get styles selected
     *
     * @return string
     */
    public function getStylesSelected()
    {
        $userPreference = $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_STYLE,
            'global',
            'grid'
        );

        if ($userPreference) {
            return $userPreference;
        } else {
            return $this->getStylesFromGlobalSettings();
        }
    }

    /**
     * Get styles from global settings
     *
     * @return string
     */
    private function getStylesFromGlobalSettings()
    {
        $styles = $this->getStyles();

        if (!is_array($styles)) {
            return [];
        }

        $stylesSelected = array_filter($styles, function ($style) {
            return isset($style['default']) && $style['default'] === true;
        });

        if (empty($stylesSelected)) {
            return [];
        }

        $stylesSelected = array_column($stylesSelected, 'id');

        return array_shift($stylesSelected);
    }

    /**
     * Get audience
     *
     * @return array
     */
    public function getAudience()
    {
        return $this->generateOptionsManager->getOptions('audience');
    }

    /**
     * Get audiences selected
     *
     * @return array
     */
    public function getAudienceSelected()
    {
        $userPreference = $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_AUDIENCES,
            'global',
            'grid'
        );

        if ($userPreference) {
            return $userPreference;
        } else {
            return $this->getAudienceFromGlobalSettings();
        }
    }

    /**
     * Get audience selected from global settings
     *
     * @return array
     */
    private function getAudienceFromGlobalSettings()
    {
        $audience = $this->getAudience();

        if (!is_array($audience)) {
            return [];
        }

        $audienceSelected = array_filter($audience, function ($audience) {
            return isset($audience['default']) && $audience['default'] === true;
        });

        if (empty($audienceSelected)) {
            return [];
        }

        $audienceSelected = array_column($audienceSelected, 'id');

        return $audienceSelected;
    }

    /**
     * Get attributes
     *
     * @return array
     */
    public function getAttributes()
    {
        return $this->generateOptionsManager->getOptions('attributes');
    }

    /**
     * Get attributes selected from global settings
     *
     * @return array
     */
    private function getAttributesSelectedFromGlobalSettings()
    {
        $attributes = $this->getAttributes();

        $defaultAttributes = array_filter($attributes, function ($attribute) {
            return $attribute['default'];
        });
        $attributesSelected = array_map(function ($attribute) {
            return $attribute['value'];
        }, $defaultAttributes);

        return array_values($attributesSelected);
    }

    /**
     * Get attributes selected
     *
     * @return array
     */
    public function getAttributesSelected()
    {
        $userPreference = $this->userFieldsSelectedManager->checkUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_ATTRIBUTES_SELECTED,
            'product',
            'grid'
        );

        $productResearchDataSelected = $this->userFieldsSelectedManager->checkUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_PRODUCT_RESEARCH_DATA,
            '',
            ''
        );

        if ($userPreference) {
            $selectedAttributes = $this->userFieldsSelected->getUserFieldsSelected(
                UserFieldsSelectedManager::ACTION_TYPE_ATTRIBUTES_SELECTED,
                'product',
                'grid'
            );
            if ($productResearchDataSelected) {
                $selectedAttributes = $this->processProductResearchData(
                    $selectedAttributes,
                    $productResearchDataSelected
                );
            }

            return $selectedAttributes;
        } else {
            $globalAttributes = $this->getAttributesSelectedFromGlobalSettings();
            if ($productResearchDataSelected) {
                $globalAttributes = $this->processProductResearchData($globalAttributes, $productResearchDataSelected);
            }
            return $globalAttributes;
        }
    }

    /**
     * Process product research data
     *
     * @param array $selectedAttributes
     * @param string $researchDataUserPreference
     * @return array
     */
    public function processProductResearchData($selectedAttributes, $researchDataUserPreference)
    {
        $researchDataUserPreference = $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_PRODUCT_RESEARCH_DATA,
            '',
            ''
        );

        if ($researchDataUserPreference === 'true') {
            if (!in_array('wtai_product_research_data', $selectedAttributes)) {
                $selectedAttributes[] = 'wtai_product_research_data';
            }
        }

        if ($researchDataUserPreference === 'false') {
            $selectedAttributes = array_values(array_filter($selectedAttributes, function ($attribute) {
                return $attribute !== 'wtai_product_research_data';
            }));
        }
        return $selectedAttributes;
    }

    /**
     * Get special instructions
     *
     * @return string
     */
    public function getSpecialInstructions()
    {
        return $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_SPECIAL_INSTRUCTIONS,
            'product',
            'grid'
        );
    }

    /**
     * Get description min
     *
     * @return string
     */
    public function getDescriptionMin()
    {
        // global settings by default
        return $this->helper->getDescriptionSettings('min');
    }

    /**
     * Get description max
     *
     * @return string
     */
    public function getDescriptionMax()
    {
        // global settings by default
        return $this->helper->getDescriptionSettings('max');
    }

    /**
     * Get excerpt min
     *
     * @return string
     */
    public function getExcerptMin()
    {
        // global settings by default
        return $this->helper->getExcerptSettings('min');
    }

    /**
     * Get excerpt max
     *
     * @return string
     */
    public function getExcerptMax()
    {
        // global settings by default
        return $this->helper->getExcerptSettings('max');
    }

    /**
     * Get rules
     *
     * @return array
     */
    public function getRules()
    {
        return $this->settings->getSettings('rules');
    }

    /**
     * Get disallowed combinations
     *
     * @return array
     */
    public function getDisallowedCombinations()
    {
        return $this->settings->getSettings('disallowedCombinations');
    }
    
    /**
     * Get text types
     *
     * @return array
     */
    public function getFields()
    {
        $fields = [[
            'value' => 'page_title',
            'label' =>  __('Meta title'),
            'hasTemplate' => true,
            'templates' => $this->getTemplateOptionPerField('page_title')
        ], [
            'value' => 'page_description',
            'label' =>  __('Meta description'),
            'hasTemplate' => false
        ], [
            'value' => 'product_description',
            'label' =>  __('Description'),
            'hasTemplate' => true,
            'templates' => $this->getTemplateOptionPerField('product_description')
        ], [
            'value' => 'short_product_description',
            'label' => __('Short description'),
            'hasTemplate' => true,
            'templates' => $this->getTemplateOptionPerField('short_product_description')
        ]];

        if ($this->helper->getCustomOpenGraph()) {
            $fields[] = [
                'value' => 'open_graph',
                'label' => __('Open Graph text'),
                'hasTemplate' => false
            ];
        }

        return $fields;
    }

    /**
     * Get fields selected
     *
     * @return array
     */
    public function getFieldsSelected()
    {
        return $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_BULK_GENERATE_FIELDS,
            'product',
            'grid'
        );
    }

    /**
     * Get search intent
     *
     * @return array
     */
    public function getSearchIntent()
    {
        $searchIntent = $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_SEARCH_INTENT,
            'product',
            ''
        );
        if ($searchIntent) {
            $searchIntent = explode(',', $searchIntent);
        } else {
            $searchIntent = explode(',', $this->helper->getKeywordOptimizationSettings('search_intent'));
        }
        return $searchIntent;
    }

    /**
     * Get cluster count
     *
     * @return int
     */
    public function getClusterCount()
    {
        return $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_CLUSTER_COUNT,
            'product',
            'grid'
        );
    }

    /**
     * Get global settings for keyword optimization
     *
     * @param string $path
     * @return string
     */
    public function getKeywordOptimizationSettings($path)
    {
        return $this->helper->getKeywordOptimizationSettings($path);
    }

    /**
     * Get automatic text optimization selected
     *
     * @return string
     */
    public function getAutomaticTextOptimizationSelected()
    {
        $userPreference = $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_AUTO_TEXT_OPTIMIZATION,
            'product',
            'grid'
        );

        if ($userPreference) {
            return $userPreference;
        } else {
            $global = $this->getKeywordOptimizationSettings('automatic_text_optimization');
            return $global ? $global : AutomaticTextOptimization::FLAG;
        }
    }

    /**
     * Get template settings
     *
     * @return array
     */
    public function getCurrentTemplateSettings()
    {
        return $this->templateSettings->getCurrentTemplateSettings();
    }

    /**
     * Get template options per field
     *
     * @param string $field
     * @return array
     */
    public function getTemplateOptionPerField($field)
    {
        return $this->templateSettings->getCurrentTemplateSettings($field);
    }

    /**
     * Get trigger actions
     *
     * @return array
     */
    public function getTriggerActions()
    {
        $lowTriggerAction = $this->getKeywordOptimizationSettings('pipeline_keyword/low');
        $lowMidTriggerAction = $this->getKeywordOptimizationSettings('pipeline_keyword/low_mid');
        $midTriggerAction = $this->getKeywordOptimizationSettings('pipeline_keyword/mid');
        $midHighTriggerAction = $this->getKeywordOptimizationSettings('pipeline_keyword/mid_high');
        
        $triggerActions = [
            'low' => $lowTriggerAction,
            'low_mid' => $lowMidTriggerAction,
            'mid' => $midTriggerAction,
            'mid_high' => $midHighTriggerAction
        ];

        return $triggerActions;
    }

    /**
     * Get product texts
     *
     * @return array
     */
    public function getProductFields()
    {
        return $this->productTexts->toOptionArray();
    }

    /**
     * Get global product fields
     *
     * @return array
     */
    public function getGlobalProductFields()
    {
        $selected = $this->helper->getKeywordOptimizationSettings('products');
        if ($selected) {
            return explode(',', $selected);
        }

        return [];
    }

    /**
     * Get default product texts
     *
     * @return array
     */
    public function getDefaultProductTexts()
    {
        $selected = $this->helper->getKeywordOptimizationSettings('products');
        if ($selected) {
            $selected = explode(',', $selected);
            if (!$this->helper->getCustomOpenGraph()) {
                $noOpenGraph = array_diff($selected, ['open_graph']);
                return $noOpenGraph;
            }
            return $selected;
        }

        $defaultProductTexts = $this->defaultProductTexts->getDefaultValues();

        return explode(',', $defaultProductTexts);
    }

    /**
     * Returns true if cron is available (running recently)
     *
     * @return bool
     */
    public function isCronRunning(): bool
    {
        return $this->cronStatus->isCronRunning();
    }
}
