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

namespace WriteTextAI\WriteTextAI\Controller\Adminhtml\Edit;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Controller\ResultFactory;
use WriteTextAI\WriteTextAI\Model\ApiManager;
use WriteTextAI\WriteTextAI\Model\Api\Keywords as ApiKeywords;
use WriteTextAI\WriteTextAI\Model\Api\Session as ApiSession;
use WriteTextAI\WriteTextAI\Model\GeneratedText;
use WriteTextAI\WriteTextAI\Model\KeywordIdeaFiltersManager;
use WriteTextAI\WriteTextAI\Model\UserFieldsSelectedManager;
use WriteTextAI\WriteTextAI\Model\GenerateOptionsManager;
use WriteTextAI\WriteTextAI\Model\AiProductManager;
use Magento\User\Model\ResourceModel\User\CollectionFactory;
use WriteTextAI\WriteTextAI\Helper\Data as HelperData;
use WriteTextAI\WriteTextAI\Helper\Fields as FieldHelper;
use WriteTextAI\WriteTextAI\Model\OptionSource\Filter\Stores as StoresFilter;
use Magento\Catalog\Model\Product\Visibility;
use WriteTextAI\WriteTextAI\Helper\Product as ProductHelper;
use WriteTextAI\WriteTextAI\Helper\Generate as GenerateHelper;
use WriteTextAI\WriteTextAI\ViewModel\Settings;
use WriteTextAI\WriteTextAI\ViewModel\UserFieldsSelected;
use WriteTextAI\WriteTextAI\Helper\ProductAttributes as ProductAttributesHelper;
use Magento\Catalog\Helper\Output as OutputHelper;
use WriteTextAI\WriteTextAI\Helper\ReviewStatus as ReviewHelper;
use WriteTextAI\WriteTextAI\Model\MarkReview;
use WriteTextAI\WriteTextAI\Helper\Store as StoreHelper;
use Magento\Catalog\Helper\Image as ImageHelper;
use WriteTextAI\WriteTextAI\Helper\Image as WtaImageHelper;
use WriteTextAI\WriteTextAI\Helper\Optimization as OptimizationHelper;
use WriteTextAI\WriteTextAI\ViewModel\AiModels as AiModelsViewModel;
use Magento\Catalog\Model\Product\Type as ProductType;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
use Magento\ConfigurableProduct\Model\Product\Type\Configurable as ConfigurableType;
use Magento\GroupedProduct\Model\Product\Type\Grouped as GroupedType;
use Magento\Store\Model\StoreManagerInterface;

class Index extends Action
{
    public const ADMIN_RESOURCE = 'WriteTextAI_WriteTextAI::menu';

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

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

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

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

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

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

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

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

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

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

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

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

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

    /**
     * @var AiModelsViewModel
     */
    protected $aiModelsViewModel;

    /**
     * @var ProductAttributesHelper
     */
    protected $productAttributesHelper;

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

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

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

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

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

    /**
     * @var array
     */
    protected $directivePatterns;

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

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

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

    /**
     * @var ProductType
     */
    protected $productType;

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

    /**
     * Constructor
     *
     * @param Context $context
     * @param ApiManager $apiManager
     * @param ApiKeywords $apiKeywords
     * @param ApiSession $apiSession
     * @param CollectionFactory $userCollectionFactory
     * @param GeneratedText $generatedText
     * @param KeywordIdeaFiltersManager $keywordIdeaFiltersManager
     * @param UserFieldsSelected $userFieldsSelected
     * @param GenerateOptionsManager $generateOptionsManager
     * @param AiProductManager $aiProductManager
     * @param HelperData $helper
     * @param FieldHelper $fieldHelper
     * @param StoresFilter $storesFilter
     * @param ProductHelper $productHelper
     * @param GenerateHelper $generateHelper
     * @param Settings $settings
     * @param ProductAttributesHelper $productAttributesHelper
     * @param OutputHelper $outputHelper
     * @param ReviewHelper $reviewHelper
     * @param MarkReview $markReview
     * @param StoreHelper $storeHelper
     * @param ImageHelper $imageHelper
     * @param WtaImageHelper $wtaImageHelper
     * @param OptimizationHelper $optimizationHelper
     * @param AiModelsViewModel $aiModelsViewModel
     * @param ProductType $productType
     * @param StoreManager $storeManager
     * @param array $directivePatterns
     */
    public function __construct(
        Context $context,
        ApiManager $apiManager,
        ApiKeywords $apiKeywords,
        ApiSession $apiSession,
        CollectionFactory $userCollectionFactory,
        GeneratedText $generatedText,
        KeywordIdeaFiltersManager $keywordIdeaFiltersManager,
        UserFieldsSelected $userFieldsSelected,
        GenerateOptionsManager $generateOptionsManager,
        AiProductManager $aiProductManager,
        HelperData $helper,
        FieldHelper $fieldHelper,
        StoresFilter $storesFilter,
        ProductHelper $productHelper,
        GenerateHelper $generateHelper,
        Settings $settings,
        ProductAttributesHelper $productAttributesHelper,
        OutputHelper $outputHelper,
        ReviewHelper $reviewHelper,
        MarkReview $markReview,
        StoreHelper $storeHelper,
        ImageHelper $imageHelper,
        WtaImageHelper $wtaImageHelper,
        OptimizationHelper $optimizationHelper,
        AiModelsViewModel $aiModelsViewModel,
        ProductType $productType,
        StoreManagerInterface $storeManager,
        $directivePatterns = []
    ) {
        $this->apiManager = $apiManager;
        $this->apiKeywords = $apiKeywords;
        $this->apiSession = $apiSession;
        $this->userCollectionFactory = $userCollectionFactory;
        $this->generatedText = $generatedText;
        $this->keywordIdeaFiltersManager = $keywordIdeaFiltersManager;
        $this->userFieldsSelected = $userFieldsSelected;
        $this->generateOptionsManager = $generateOptionsManager;
        $this->aiProductManager = $aiProductManager;
        $this->helper = $helper;
        $this->fieldHelper = $fieldHelper;
        $this->directivePatterns = $directivePatterns;
        $this->storesFilter = $storesFilter;
        $this->productHelper = $productHelper;
        $this->generateHelper = $generateHelper;
        $this->settings = $settings;
        $this->productAttributesHelper = $productAttributesHelper;
        $this->outputHelper = $outputHelper;
        $this->reviewHelper = $reviewHelper;
        $this->markReview = $markReview;
        $this->storeHelper = $storeHelper;
        $this->imageHelper = $imageHelper;
        $this->wtaImageHelper = $wtaImageHelper;
        $this->optimizationHelper = $optimizationHelper;
        $this->aiModelsViewModel = $aiModelsViewModel;
        $this->productType = $productType;
        $this->storeManager = $storeManager;
        parent::__construct($context);
    }

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

        try {
            $request = $this->getRequest();
            $productId = $request->getParam('id');
            $storeId = $request->getParam('store_id');

            $product = $this->productHelper->getProduct($productId, $storeId);

            $productName = $this->outputHelper->productAttribute(
                $product,
                $product->getName(),
                'name'
            );

            $aiProduct = $this->aiProductManager->getProduct($productId, $storeId);
            $result = [
                'success' => true,
                'users' => $this->getUsers(),
                //'stores' => array_values($this->storesFilter->toOptionArray())
            ];

            $productData = $this->getProductData(
                $product,
                $productId,
                $storeId,
                $productName
            );
            $textsData = $this->getTextsData(
                $product,
                $productId,
                $storeId
            );
            $userPreferences = $this->getUserPreferences();
            $attributesData = $this->getAttributesData(
                $aiProduct,
                $product
            );
            $additionalPrompt = $this->getAdditionalPrompt($aiProduct);
            $optimizationData = $this->apiKeywords->getOptimization(
                $storeId,
                $productId,
                'Product'
            );
            $result['optimization'] = $optimizationData;
            $selectedKeywords = $this->getSelectedKeywords(
                $optimizationData,
                $product->getName(),
                $storeId,
                $productId
            );
            $imagesData = $this->getImageData(
                $product,
                $productId,
                $storeId,
                $optimizationData
            );
            $settingsData = $this->getSettingsData(
                $storeId,
                $productId,
                $productName,
                $selectedKeywords
            );

            $result = array_merge(
                $result,
                $productData,
                $settingsData,
                $textsData,
                $imagesData,
                $userPreferences,
                $attributesData,
                $selectedKeywords,
                $additionalPrompt
            );
        } 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 product data
     *
     * @param object $product
     * @param int $productId
     * @param int $storeId
     * @param string $productName
     *
     * @return array
     */
    private function getProductData(
        $product,
        $productId,
        $storeId,
        $productName
    ) {
        $currentUser = $this->apiSession->getCurrentUser();

        $optionValues = array_values($this->storesFilter->toOptionArray());
        $productStoreIds = $product->getStoreIds();
        $storesForProduct = $this->filterStoresByProduct($optionValues, $productStoreIds);

        $previewStoreViewId = (int) $storeId;
        if ($previewStoreViewId === 0) {
            $previewStoreViewId = $this->getFirstEnabledStoreViewIdFromOptions($storesForProduct, (int) $productId);
        }

        $statusStoreId = $previewStoreViewId;
        $statusProduct = $product;
        if ($statusStoreId > 0 && (int) $storeId !== $statusStoreId) {
            try {
                $statusProduct = $this->productHelper->getProduct((int) $productId, (int) $statusStoreId);
            } catch (\Exception $e) {
                $statusProduct = $product;
            }
        }

        $isDisabledInStore = ((int) $statusProduct->getStatus() === Status::STATUS_DISABLED);

        $frontendStoreId = $this->storeHelper->getFrontendStoreId($previewStoreViewId);

        $_product = $product;

        $useStoreSwitchUrl = ((int) $storeId === 0);
        if (!$useStoreSwitchUrl) {
            try {
                $defaultStoreView = $this->storeManager->getDefaultStoreView();
                if ($defaultStoreView) {
                    $selectedStore = $this->storeManager->getStore((int) $frontendStoreId);

                    $defaultGroupId = (int) $defaultStoreView->getGroupId();
                    $selectedGroupId = (int) $selectedStore->getGroupId();

                    if ($defaultGroupId && $selectedGroupId && $defaultGroupId !== $selectedGroupId) {
                        $defaultBaseUrl =
                            (string) $this->storeHelper->getFrontendStoreBaseUrl((int) $defaultStoreView->getId());
                        $selectedBaseUrl =
                            (string) $this->storeHelper->getFrontendStoreBaseUrl((int) $frontendStoreId);
                        // phpcs:disable Magento2.Functions.DiscouragedFunction.Discouraged
                        $defaultHost = (string) (parse_url($defaultBaseUrl, PHP_URL_HOST) ?? '');
                        $selectedHost = (string) (parse_url($selectedBaseUrl, PHP_URL_HOST) ?? '');
                        // phpcs:enable Magento2.Functions.DiscouragedFunction.Discouraged
                        if ($defaultHost !== '' && $selectedHost !== '' && $defaultHost === $selectedHost) {
                            $useStoreSwitchUrl = true;
                        }
                    }
                }
            } catch (\Exception $e) {
                $useStoreSwitchUrl = false;
            }
        }

        $productUrl = $_product->setStoreId($frontendStoreId)->getUrlInStore();
        $productUrl = $useStoreSwitchUrl
            ? $this->normalizeFrontendUrl((int) $frontendStoreId, (string) $productUrl)
            : $productUrl;
        $productUrlForSwitch = $useStoreSwitchUrl
            ? $this->buildFrontendStoreSwitchUrl((int) $frontendStoreId, (string) $productUrl)
            : $productUrl;

        $languageCode = $this->storeHelper->getRegionIndependentLanguage($frontendStoreId);
        $languageCode = strtoupper($languageCode);

        $typeId = (string) $product->getTypeId();
        $typeLabel = ProductType::DEFAULT_TYPE;
        $typeLabels = $this->productType->getOptionArray();
        if (isset($typeLabels[$typeId])) {
            $typeLabel = $typeLabels[$typeId];
        }

        $previewChangesUrl = $_product->setStoreId($frontendStoreId)->getUrlInStore([
            '_query' => [
                'wtai-preview' => base64_encode($currentUser->getId())
            ]
        ]);
        $previewChangesUrl = $this->normalizeFrontendUrl((int) $frontendStoreId, (string) $previewChangesUrl);
        $previewChangesUrlForSwitch = $useStoreSwitchUrl
            ? $this->buildFrontendStoreSwitchUrl((int) $frontendStoreId, (string) $previewChangesUrl)
            : $previewChangesUrl;

        return [
            'product_name' => $productName,
            'sku' => $product->getSku(),
            'product_id' => $productId,
            'visibility' => $product->getVisibility() != Visibility::VISIBILITY_NOT_VISIBLE,
            'is_disabled_in_store' => $isDisabledInStore,
            'store_id' => $storeId,
            'store_scope' => $this->storeHelper->getStoreScope($storeId),
            'product_type' => $typeId,
            'product_type_label' => $typeLabel,
            'has_product_type' => !empty($typeLabel),
            'child_products' => $this->getChildProductsData($product, (int) $storeId),
            'customizable_option_titles' => $this->getCustomizableOptionTitles($product),
            'customizable_options' => $this->getCustomizableOptionsDataWithoutValue($product),
            'stores' => $storesForProduct,
            'product_url' => $productUrl,
            'link_preview_url' => $productUrlForSwitch,
            'preview_changes_url' => $previewChangesUrlForSwitch,
            'language' => $languageCode,
            'country' => $this->keywordIdeaFiltersManager->getCountryCode($frontendStoreId),
        ];
    }

    /**
     * Get first enabled store view id from nested store switcher options.
     *
     * @param array $options
     * @param int $productId
     * @return int
     */
    private function getFirstEnabledStoreViewIdFromOptions(array $options, int $productId): int
    {
        foreach ($options as $option) {
            if (isset($option['value']) && is_array($option['value'])) {
                $childId = $this->getFirstEnabledStoreViewIdFromOptions($option['value'], $productId);
                if ($childId > 0) {
                    return $childId;
                }
                continue;
            }

            $storeViewId = (int) ($option['value'] ?? 0);
            if ($storeViewId <= 0) {
                continue;
            }

            try {
                $storeProduct = $this->productHelper->getProduct($productId, $storeViewId);
                if ((int) $storeProduct->getStatus() === Status::STATUS_ENABLED) {
                    return $storeViewId;
                }
            } catch (\Exception $e) {
                continue;
            }
        }

        return 0;
    }

    /**
     * Build frontend store switch URL
     *
     * @param int $storeId
     * @param string $targetUrl
     * @return string
     */
    private function buildFrontendStoreSwitchUrl($storeId, $targetUrl)
    {
        $storeCode = $this->storeHelper->getFrontendStoreCode($storeId);
        $baseUrl = rtrim($this->storeHelper->getFrontendStoreBaseUrl($storeId), '/');

        return $baseUrl
            . '/stores/store/switch'
            . '?___store=' . urlencode($storeCode)
            . '&uenc=' . urlencode(base64_encode($targetUrl));
    }
    // phpcs:disable Magento2.Functions.DiscouragedFunction.Discouraged
    
    /**
     * Normalize frontend URL
     *
     * @param int $storeId
     * @param string $url
     * @return string
     */
    private function normalizeFrontendUrl($storeId, $url)
    {
        $baseUrl = rtrim($this->storeHelper->getFrontendStoreBaseUrl($storeId), '/');
        if ($baseUrl === '') {
            return $url;
        }

        $baseParts = parse_url($baseUrl);
        if (is_array($baseParts) && !empty($baseParts['scheme']) && !empty($baseParts['host'])) {
            $cleanBaseUrl = $baseParts['scheme'] . '://' . $baseParts['host'];
            if (!empty($baseParts['port'])) {
                $cleanBaseUrl .= ':' . $baseParts['port'];
            }
            $baseUrl = $cleanBaseUrl;
        }

        $parts = parse_url($url);
        if (!is_array($parts) || empty($parts['path'])) {
            return $url;
        }

        $path = (string) $parts['path'];
        $backendFrontName = '';
        if (isset($this->_backendUrl) && method_exists($this->_backendUrl, 'getAreaFrontName')) {
            $backendFrontName = (string) $this->_backendUrl->getAreaFrontName();
        }
        if ($backendFrontName !== '') {
            $frontName = trim($backendFrontName, '/');
            $needles = [
                '/' . $frontName . '/',
                '/index.php/' . $frontName . '/',
                '/' . $frontName,
                '/index.php/' . $frontName,
            ];

            foreach ($needles as $needle) {
                if (strpos($path, $needle) === 0) {
                    $path = '/' . ltrim(substr($path, strlen($needle)), '/');
                    break;
                }
            }
        }

        $normalized = $baseUrl . '/' . ltrim($path, '/');
        if (!empty($parts['query'])) {
            $normalized .= '?' . $parts['query'];
        }
        if (!empty($parts['fragment'])) {
            $normalized .= '#' . $parts['fragment'];
        }

        return $normalized;
    }
    // phpcs:enable Magento2.Functions.DiscouragedFunction.Discouraged

    /**
     * Get enabled child products for configurable/grouped/bundle.
     *
     * @param \Magento\Catalog\Api\Data\ProductInterface $product
     * @param int $storeId
     * @return array
     */
    private function getChildProductsData($product, $storeId)
    {
        try {
            $typeId = (string) $product->getTypeId();
            $childIds = [];

            if ($typeId === ConfigurableType::TYPE_CODE) {
                $childIds = $product->getTypeInstance()->getUsedProductIds($product);
            } elseif ($typeId === GroupedType::TYPE_CODE) {
                $childIds = $product->getTypeInstance()->getAssociatedProductIds($product);
            } elseif ($typeId === 'bundle') {
                $childIds = $product->getTypeInstance()->getChildrenIds((int) $product->getId(), false);
                $flattened = [];
                foreach ($childIds as $optionChildren) {
                    foreach ((array) $optionChildren as $childId) {
                        $flattened[] = (int) $childId;
                    }
                }
                $childIds = $flattened;
            }

            $childIds = array_values(array_unique(array_filter($childIds)));
            if (empty($childIds)) {
                return [];
            }

            $items = [];
            foreach ($childIds as $childId) {
                try {
                    $child = $this->productHelper->getProduct((int) $childId, (int) $storeId);
                } catch (\Exception $e) {
                    continue;
                }

                if ((int) $child->getStatus() !== Status::STATUS_ENABLED) {
                    continue;
                }

                $items[] = [
                    'id' => (int) $child->getId(),
                    'name' => (string) $child->getName(),
                    'sku' => (string) $child->getSku()
                ];
            }

            usort($items, static function ($a, $b) {
                return strcmp($a['name'], $b['name']);
            });

            return $items;
        } catch (\Exception $e) {
            return [];
        }
    }

    /**
     * Get customizable options data
     *
     * @param \Magento\Catalog\Model\Product $product
     * @return array
     */
    private function getCustomizableOptionsDataWithValue($product): array
    {
        try {
            if (!$product || !method_exists($product, 'getOptions')) {
                return [];
            }

            $options = $product->getOptions();
            if (empty($options) && method_exists($product, 'getOptionInstance')) {
                $optionInstance = $product->getOptionInstance();
                if ($optionInstance && method_exists($optionInstance, 'getOptions')) {
                    $options = $optionInstance->getOptions($product);
                }
            }

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

            $data = [];
            foreach ($options as $option) {
                if (!$option || !method_exists($option, 'getOptionId')) {
                    continue;
                }

                $valuesData = [];
                $values = [];
                if (method_exists($option, 'getValues')) {
                    $values = $option->getValues();
                }
                
                // If getValue is true, only include options that have values
                if (!is_array($values) || empty($values)) {
                    continue;
                }
                
                if (is_array($values)) {
                    foreach ($values as $value) {
                        if (!$value) {
                            continue;
                        }
                        $valuesData[] = [
                            'option_type_id' => (int) ($value->getOptionTypeId() ?? 0),
                            'title' => (string) ($value->getTitle() ?? ''),
                            'price' => (float) ($value->getPrice() ?? 0),
                            'price_type' => (string) ($value->getPriceType() ?? ''),
                            'sku' => (string) ($value->getSku() ?? ''),
                            'sort_order' => (int) ($value->getSortOrder() ?? 0)
                        ];
                    }
                }

                $data[] = [
                    'option_id' => (int) ($option->getOptionId() ?? 0),
                    'title' => (string) ($option->getTitle() ?? ''),
                    'type' => (string) ($option->getType() ?? ''),
                    'is_require' => (bool) ($option->getIsRequire() ?? false),
                    'sort_order' => (int) ($option->getSortOrder() ?? 0),
                    'values' => $valuesData
                ];
            }

            usort($data, static function ($a, $b) {
                return ($a['sort_order'] <=> $b['sort_order']);
            });

            return $data;
        } catch (\Exception $e) {
            return [];
        }
    }

     /**
      * Get customizable options data
      *
      * @param \Magento\Catalog\Model\Product $product
      * @return array
      */
    private function getCustomizableOptionsDataWithoutValue($product): array
    {
        try {
            if (!$product || !method_exists($product, 'getOptions')) {
                return [];
            }

            $options = $product->getOptions();
            if (empty($options) && method_exists($product, 'getOptionInstance')) {
                $optionInstance = $product->getOptionInstance();
                if ($optionInstance && method_exists($optionInstance, 'getOptions')) {
                    $options = $optionInstance->getOptions($product);
                }
            }

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

            $data = [];
            foreach ($options as $option) {
                if (!$option || !method_exists($option, 'getOptionId')) {
                    continue;
                }

                $valuesData = [];
                $values = [];
                if (method_exists($option, 'getValues')) {
                    $values = $option->getValues();
                }
                
                // Skip options that have values
                if (is_array($values) && !empty($values)) {
                    continue;
                }
                
                if (is_array($values)) {
                    foreach ($values as $value) {
                        if (!$value) {
                            continue;
                        }
                        $valuesData[] = [
                            'option_type_id' => (int) ($value->getOptionTypeId() ?? 0),
                            'title' => (string) ($value->getTitle() ?? ''),
                            'price' => (float) ($value->getPrice() ?? 0),
                            'price_type' => (string) ($value->getPriceType() ?? ''),
                            'sku' => (string) ($value->getSku() ?? ''),
                            'sort_order' => (int) ($value->getSortOrder() ?? 0)
                        ];
                    }
                }

                $data[] = [
                    'option_id' => (int) ($option->getOptionId() ?? 0),
                    'title' => (string) ($option->getTitle() ?? ''),
                    'type' => (string) ($option->getType() ?? ''),
                    'is_require' => (bool) ($option->getIsRequire() ?? false),
                    'sort_order' => (int) ($option->getSortOrder() ?? 0),
                    'values' => $valuesData
                ];
            }

            usort($data, static function ($a, $b) {
                return ($a['sort_order'] <=> $b['sort_order']);
            });

            return $data;
        } catch (\Exception $e) {
            return [];
        }
    }

    /**
     * Get customizable option titles
     *
     * @param \Magento\Catalog\Model\Product $product
     * @return array
     */
    private function getCustomizableOptionTitles($product): array
    {
        try {
            if (!$product || !method_exists($product, 'getOptions')) {
                return [];
            }

            $options = $product->getOptions();
            if (empty($options) && method_exists($product, 'getOptionInstance')) {
                $optionInstance = $product->getOptionInstance();
                if ($optionInstance && method_exists($optionInstance, 'getOptions')) {
                    $options = $optionInstance->getOptions($product);
                }
            }

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

            $titles = [];
            foreach ($options as $option) {
                if (!$option || !method_exists($option, 'getTitle')) {
                    continue;
                }

                $title = trim((string) $option->getTitle());
                if ($title !== '') {
                    $titles[] = $title;
                }
            }

            $titles = array_values(array_unique($titles));
            sort($titles);

            return $titles;
        } catch (\Exception $e) {
            return [];
        }
    }

    /**
     * Get user preferences
     *
     * @return array
     */
    private function getUserPreferences()
    {
        
            $userDescMin = $this->helper->getDescriptionSettings('min');
            $userDescMax = $this->helper->getDescriptionSettings('max');
            $userExcMin = $this->helper->getExcerptSettings('min');
            $userExcMax = $this->helper->getExcerptSettings('max');

        $searchIntent = $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_SEARCH_INTENT,
            'product',
            ''
        );
        if ($searchIntent) {
            $searchIntent = explode(',', $searchIntent);
        } else {
            $searchIntent = explode(',', 'transactional');
        }

        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,
                'product',
                'edit'
            ),
            'highlight_pronouns' => $this->userFieldsSelected->getUserFieldsSelected(
                UserFieldsSelectedManager::ACTION_TYPE_HIGHLIGHT_PRONOUNS,
                '',
                'edit'
            ),

            'gallery' => $this->userFieldsSelected->getUserFieldsSelected(
                UserFieldsSelectedManager::ACTION_TYPE_GALLERY,
                'product',
                '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,
            'exc_min' => $userExcMin,
            'exc_max' => $userExcMax,
            'search_intent_selected' => $searchIntent
        ];
    }

    /**
     * Get attributes data
     *
     * @param object $aiProduct
     * @param object $product
     *
     * @return array
     */
    private function getAttributesData(
        $aiProduct,
        $product
    ) {
        $productAttributes = $this->productAttributesHelper->getProductAttributes($product);

        $customOptionAttributeCodes = [];

        $getCustomizableOptionsDataWithValue = $this->getCustomizableOptionsDataWithValue($product);
        $getCustomizableOptionsDataWithoutValue = $this->getCustomizableOptionsDataWithoutValue($product);

        if (!empty($getCustomizableOptionsDataWithValue)) {
            foreach ($getCustomizableOptionsDataWithValue as $opt) {
                $optTitle = trim(strip_tags((string) ($opt['title'] ?? '')));
                if ($optTitle === '') {
                    continue;
                }

                $valueTitles = [];
                $values = $opt['values'] ?? [];
                if (is_array($values)) {
                    foreach ($values as $val) {
                        $valueTitle = trim(strip_tags((string) ($val['title'] ?? '')));
                        if ($valueTitle !== '') {
                            $valueTitles[] = $valueTitle;
                        }
                    }
                }

                $valueTitles = array_values(array_unique(array_filter($valueTitles)));
                
                // Create individual attribute for each option
                $attributeCode = 'wtai_custom_option_' . strtolower(str_replace(' ', '_', $optTitle));
                $details = !empty($valueTitles) ? implode(', ', $valueTitles) : $optTitle;

                $customOptionAttributeCodes[] = $attributeCode;
 
                $productAttributes[] = [
                    'attribute_code' => $attributeCode,
                    'attribute' => $optTitle,
                    'value' => '',
                    'details' => $details
                ];
            }
        }

        if (!empty($getCustomizableOptionsDataWithoutValue)) {
            $customOptionParts = [];
            foreach ($getCustomizableOptionsDataWithoutValue as $opt) {
                $optTitle = trim(strip_tags((string) ($opt['title'] ?? '')));
                if ($optTitle === '') {
                    continue;
                }

                $valueTitles = [];
                $values = $opt['values'] ?? [];
                if (is_array($values)) {
                    foreach ($values as $val) {
                        $valueTitle = trim(strip_tags((string) ($val['title'] ?? '')));
                        if ($valueTitle !== '') {
                            $valueTitles[] = $valueTitle;
                        }
                    }
                }

                $valueTitles = array_values(array_unique(array_filter($valueTitles)));
                if (!empty($valueTitles)) {
                    $customOptionParts[] = $optTitle . ': ' . implode(', ', $valueTitles);
                } else {
                    $customOptionParts[] = $optTitle;
                }
            }

            $customOptionParts = array_values(array_filter($customOptionParts));
            $details = implode(' | ', $customOptionParts);
            if ($details === '') {
                $details = implode(', ', $this->getCustomizableOptionTitles($product));
            }

            $productAttributes[] = [
               'attribute_code' => 'wtai_customizable_options',
               'attribute' => __('Customizable options'),
               'value' => '',
               'details' => $details
            ];
        }

        $productAttributesSelected = $this->productAttributesHelper
            ->getProductAttributesSelected($aiProduct);
        if (!is_array($productAttributesSelected)) {
            $productAttributesSelected = [];
        }
        if (!empty($customOptionAttributeCodes)) {
            $productAttributesSelected = array_values(array_unique(array_merge(
                $productAttributesSelected,
                $customOptionAttributeCodes
            )));
        }

        return [
            'product_attributes' => $productAttributes,
            'product_attributes_selected' => $productAttributesSelected,
            'other_details_checked' => (bool) $aiProduct->getOtherDetailsChecked(),
            'other_details' => $aiProduct->getOtherDetails()
        ];
    }

    /**
     * Get additional prompt
     *
     * @param object $aiProduct
     *
     * @return array
     */
    private function getAdditionalPrompt($aiProduct)
    {
        return [
            'additional_prompt' => $aiProduct->getAdditionalPrompt()
        ];
    }

    /**
     * Get settings parameters
     *
     * @param int $storeId
     * @param int $productId
     * @param string $productName
     * @param array $selectedKeywords
     *
     * @return array
     */
    private function getSettingsData($storeId, $productId, $productName, $selectedKeywords)
    {
        $tonesOptions = $this->generateOptionsManager->getOptions('tones');
        $stylesOptions = $this->generateOptionsManager->getOptions('styles');
        $audienceOptions = $this->generateOptionsManager->getOptions('audience');

        $userTones = $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_TONES,
            'global',
            'grid'
        );

        if (empty($userTones)) {
            $defaultTones = array_filter($tonesOptions, function ($tone) {
                return !empty($tone['default']);
            });
            $userTones = array_column($defaultTones, 'id');
        }

        $tones = $this->generateHelper->updateDefault(
            $tonesOptions,
            $userTones
        );

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

        if (empty($userStyles)) {
            $defaultStyles = array_filter($stylesOptions, function ($style) {
                return !empty($style['default']);
            });
            $styleIds = array_column($defaultStyles, 'id');
            $userStyles = array_shift($styleIds);
        }

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

        $userAudiences = $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_AUDIENCES,
            'global',
            'grid'
        );

        if (empty($userAudiences)) {
            $defaultAudiences = array_filter($audienceOptions, function ($audience) {
                return !empty($audience['default']);
            });
            $userAudiences = array_column($defaultAudiences, 'id');
        }

        $audiences = $this->generateHelper->updateDefault(
            $audienceOptions,
            $userAudiences
        );

        $audience = [];
        $keywords = [$productName];
        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, $productId, $keywords);
        }

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

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

        $formalLanguages = [];
        if (in_array($langCode, $formalLanguageSupport)) {
            $formalLanguages = $this->settings->getFormalLanguages($langCode);
        }
        $customTone = $this->getCustomTones($tones);
        $customStyle = $this->getCustomStyles($styles);
        return [
            'user_tones' => $userTones,
            'user_styles' => $userStyles,
            'tones' => $tones,
            'styles' => $styles,
            'audience' => $audiences,
            'custom_tone' => $customTone,
            'custom_style' => $customStyle,
            'selected_audience' => $audience['selected'] ?? [],
            'suggested_audience' => $audience['values'] ?? [],
            'formal_language_support' => $formalLanguageSupport,
            'formal_languages' => $formalLanguages,
            'disallowed_combinations' => $this->settings->getSettings('disallowedCombinations'),
            'credits' => $this->settings->getSettings('credits'),
            'global_triggers' => $this->optimizationHelper->getGlobalTriggers('Product')
        ];
    }

    /**
     * Get texts parameters
     *
     * @param object $product
     * @param int $productId
     * @param int $storeId
     *
     * @return array
     */
    private function getTextsData($product, $productId, $storeId)
    {
        $generatedText = $this->generatedText->getGenerated($productId, $storeId);

        $mapping = $this->fieldHelper->getMappingSettingsValue();
        $customOpenGraph = $this->helper->getCustomOpenGraph();

        $pageTitle = $this->fieldHelper->getAttributesValues($product, 'page_title');
        $pageDescription = $this->fieldHelper->getAttributesValues($product, 'page_description');
        $productDescription = $this->fieldHelper->getAttributesValues($product, 'product_description');
        $shortProductDescription = $this->fieldHelper->getAttributesValues(
            $product,
            'short_product_description'
        );
        $openGraph = $this->fieldHelper->getAttributesValues($product, 'open_graph');

        $aiModelsUsed = $this->generatedText->getTextFieldsModel(
            $productId,
            $storeId,
            $generatedText
        );
        $datesGenerated = $this->generatedText->getTextFieldsDate(
            $productId,
            $storeId,
            $generatedText
        );
        $lastModelUsed = $this->getLastGenerated($aiModelsUsed, $datesGenerated);

        if ($this->aiModelsViewModel && !$this->aiModelsViewModel->hasAiModels()) {
            $lastModelUsed = '';
        }

        return [
            'api_texts' => $generatedText,
            'text_fields' => $this->generatedText->getTextFields($productId, $storeId, false, $generatedText),
            'product_description' => $productDescription,
            'product_short_description' => $shortProductDescription,
            'product_meta_title' => $pageTitle,
            'product_meta_description' => $pageDescription,
            'open_graph' => $customOpenGraph ? $openGraph : '',
            'directiveRegex' => $this->getDirectivePatterns(),
            'product_description_directive_exists' => $this->fieldHelper->isDirectiveExists(
                $product,
                'product_description'
            ),
            'product_short_description_directive_exists' => $this->fieldHelper->isDirectiveExists(
                $product,
                'short_product_description'
            ),
            'textfields_statuses' => $this->generatedText->getTextFieldsStatuses(
                $productId,
                $storeId,
                $generatedText
            ),
            'use_default' => [
                'page_title' => $this->fieldHelper->isUsingDefaultValues(
                    $product,
                    $storeId,
                    $mapping['page_title']
                ),
                'page_description' => $this->fieldHelper->isUsingDefaultValues(
                    $product,
                    $storeId,
                    $mapping['page_description']
                ),
                'product_description' => $this->fieldHelper->isUsingDefaultValues(
                    $product,
                    $storeId,
                    $mapping['product_description']
                ),
                'short_product_description' => $this->fieldHelper->isUsingDefaultValues(
                    $product,
                    $storeId,
                    $mapping['short_product_description']
                ),
                'open_graph' => isset($mapping['open_graph']) ?
                    $this->fieldHelper->isUsingDefaultValues($product, $storeId, $mapping['open_graph']) : false
            ],
            'reviewed' => $this->markReview->getReviewed($productId, $storeId, $generatedText),
            'review_status' => $this->reviewHelper->getReviewStatus($productId, $storeId),
            'feedback' => $this->generatedText->getTextsFeedback($generatedText),
            'keywords_used' => $this->generatedText->getTextsKeywordsUsed($generatedText),
            'templates_used' => $this->generatedText->getTextFieldsTemplate($productId, $storeId, $generatedText),
            'ai_models_used' => $aiModelsUsed,
            'last_brandvoice_used' => $lastModelUsed
        ];
    }

    /**
     * Get images parameters
     *
     * @param object $product
     * @param int $productId
     * @param int $storeId
     * @param array $optimizationData
     *
     * @return array
     */
    private function getImageData(
        $product,
        $productId,
        $storeId,
        $optimizationData
    ) {
        $language = $this->storeHelper->getFormattedLanguage($storeId);
        $origImageHelper = $this->imageHelper->init($product, 'product_listing_thumbnail_preview');
        $thumbnail = $origImageHelper->getUrl();

        return [
            'thumbnail' => $thumbnail,
            'thumbnail_id' => $this->wtaImageHelper->getImageValue($product),
            'images' => $this->productHelper->getImages($product, $storeId, $language),
            'api_thumbnail' => $optimizationData['imageId'] ?? ''
        ];
    }

    /**
     * Get directives regular expression
     *
     * @return array
     * @see \Magento\Framework\Filter\Template
     */
    private function getDirectivePatterns()
    {
        $patterns = [];
        foreach ($this->directivePatterns as $pattern) {
            $pattern = ltrim($pattern, '/');
            $pattern = rtrim($pattern, '/si');
            $patterns[] = $pattern;
        }

        $patterns[] = FieldHelper::MEDIA_PATTERN;
        return $patterns;
    }
    
    /**
     * Get last generated
     *
     * @param array $aiModelsUsed
     * @param array $datesGenerated
     * @return string
     */
    public function getLastGenerated($aiModelsUsed, $datesGenerated)
    {
        $latestDate = null;
        $latestModel = '';
        $latestField = '';

        foreach ($datesGenerated as $field => $date) {
            if (!empty($date)) {
                try {
                    $dateTime = new \DateTime($date);
                } catch (\Exception $e) {
                    $dateTime = false;
                }
                if ($dateTime && (!$latestDate || $dateTime > $latestDate)) {
                    $latestDate = $dateTime;
                    $latestModel = $aiModelsUsed[$field] ?? '';
                    $latestField = $field;
                }
            }
        }

        return $latestModel;
    }

    /**
     * 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;
    }

    /**
     * Get selected keywords
     *
     * @param array $optimizationData
     * @param string $productName
     * @param int $storeId
     * @param int $productId
     */
    private function getSelectedKeywords($optimizationData, $productName, $storeId, $productId)
    {
        /**
         * Get selected keywords for optimizationData
         */
        $keywords = [];
        $optimizingKeywords = [];
        if (!empty($optimizationData)) {
            $keywords = $optimizationData['manualKeywords'] ?? [];
            $optimizingKeywords = $optimizationData['optimizingKeywords'] ?? [];
        }

        return [
            'selected_keywords' => $keywords,
            'optimizing_keywords' => $optimizingKeywords
        ];
    }

    /**
     * Filter stores by product
     *
     * @param array $options
     * @param array $productStoreIds
     * @return array
     */
    public function filterStoresByProduct($options, $productStoreIds)
    {
        $filtered = [];

        foreach ($options as $option) {
            if (isset($option['value']) && is_array($option['value'])) {
                // Recursively filter children
                $children = $this->filterStoresByProduct($option['value'], $productStoreIds);

                if (!empty($children)) {
                    $option['value'] = $children;
                    $filtered[] = $option;
                }
            } else {
                // Leaf node (store view)
                if (in_array($option['value'], $productStoreIds)) {
                    $filtered[] = $option;
                }
            }
        }

        return $filtered;
    }

    /**
     * Get custom tones
     *
     * @param array $tones
     * @return string
     */
    public function getCustomTones($tones)
    {
        $customTone = '';
        foreach ($tones as $tone) {
            if (isset($tone['id']) && $tone['id'] === 'custom') {
                if (!$tone['default']) {
                    return '';
                }
            }
        }
        
        $customTone = $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_CUSTOM_TONE,
            'global',
            'grid'
        );
        
        if (isset($customTone)) {
            return $customTone;
        }
        
        return $this->generateOptionsManager->getCustomTones();
    }
    /**
     * Get custom styles
     *
     * @param array $styles
     * @return array
     */
    public function getCustomStyles($styles)
    {
        foreach ($styles as $style) {
            if (isset($style['id']) && $style['id'] === 'custom') {
                if (!$style['default']) {
                    return '';
                }
            }
        }
        
        $customStyle = $this->userFieldsSelected->getUserFieldsSelected(
            UserFieldsSelectedManager::ACTION_TYPE_CUSTOM_STYLE,
            'global',
            'grid'
        );
  
        if (isset($customStyle)) {
            return $customStyle;
        }
        
        return $this->generateOptionsManager->getCustomStyles();
    }
}
