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

namespace WriteTextAI\WriteTextAI\Ui\DataProvider\Categories;

use Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider;
use WriteTextAI\WriteTextAI\Helper\Categories\Fields as FieldHelper;
use Magento\Store\Model\Store;
use Magento\Framework\Api\FilterBuilder;
use Magento\Framework\Api\Search\ReportingInterface;
use Magento\Framework\Api\Search\SearchCriteriaBuilder;
use Magento\Framework\App\RequestInterface;
use Magento\Catalog\Helper\Output as OutputHelper;
use WriteTextAI\WriteTextAI\Model\OptionSource\Filter\AiStatus;
use WriteTextAI\WriteTextAI\Model\ApiManager;
use WriteTextAI\WriteTextAI\Model\Api\Keywords;
use WriteTextAI\WriteTextAI\Model\Config\Source\AutomaticTextOptimization;
use Magento\Framework\Api\Search\FilterGroupBuilder;
use WriteTextAI\WriteTextAI\Helper\Store as StoreHelper;
use WriteTextAI\WriteTextAI\Helper\Grid as GridHelper;
use WriteTextAI\WriteTextAI\ViewModel\Premium;
use WriteTextAI\WriteTextAI\Model\OptionSource\Filter\Fields;
use WriteTextAI\WriteTextAI\Model\Categories\GeneratedText;
use WriteTextAI\WriteTextAI\Model\Api\Session as ApiSession;
use WriteTextAI\WriteTextAI\Model\Magento\User as MagentoUser;
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
use WriteTextAI\WriteTextAI\Helper\Filters as FiltersHelper;
use WriteTextAI\WriteTextAI\Api\Data\AiCategoryInterface;
use WriteTextAI\WriteTextAI\Helper\Categories\Data as CategoriesDataHelper;
use Magento\Store\Model\StoreManagerInterface;
use WriteTextAI\WriteTextAI\Model\Magento\Category as MagentoCategory;
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite as UrlRewriteData;
use Magento\UrlRewrite\Model\UrlFinderInterface;
use WriteTextAI\WriteTextAI\WtaiTrait\PremiumDataTrait;
use WriteTextAI\WriteTextAI\Helper\Image as WtaImageHelper;

class ListingDataProvider extends DataProvider
{
    use PremiumDataTrait;

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

    /**
     * @var FilterGroupBuilder
     */
    protected $filterGroupBuilder;

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

    /**
     * @var GridHelper
     */
    protected $gridHelper;

    /**
     * @var Premium
     */
    protected $premium;

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

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

    /**
     * @var MagentoUser
     */
    protected $magentoUser;

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

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

    /**
     * @var TimezoneInterface
     */
    protected $timezone;

    /**
     * @var FiltersHelper
     */
    protected $filtersHelper;

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

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

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

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

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

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

    /**
     * @var string
     */
    protected $errorMessage = '';

    /**
     * Constructor
     *
     * @param string $name
     * @param string $primaryFieldName
     * @param string $requestFieldName
     * @param ReportingInterface $reporting
     * @param SearchCriteriaBuilder $searchCriteriaBuilder
     * @param RequestInterface $request
     * @param FilterBuilder $filterBuilder
     * @param FieldHelper $fieldHelper
     * @param FilterGroupBuilder $filterGroupBuilder
     * @param StoreHelper $storeHelper
     * @param GridHelper $gridHelper
     * @param Premium $premium
     * @param GeneratedText $generatedText
     * @param ApiSession $apiSession
     * @param MagentoUser $magentoUser
     * @param OutputHelper $outputHelper
     * @param ApiManager $apiManager
     * @param TimezoneInterface $timezone
     * @param FiltersHelper $filtersHelper
     * @param CategoriesDataHelper $categoriesDataHelper
     * @param StoreManagerInterface $storeManager
     * @param MagentoCategory $magentoCategory
     * @param UrlFinderInterface $urlFinder
     * @param Keywords $keywords
     * @param WtaImageHelper $wtaImageHelper
     * @param array $meta
     * @param array $data
     */
    public function __construct(
        $name,
        $primaryFieldName,
        $requestFieldName,
        ReportingInterface $reporting,
        SearchCriteriaBuilder $searchCriteriaBuilder,
        RequestInterface $request,
        FilterBuilder $filterBuilder,
        FieldHelper $fieldHelper,
        FilterGroupBuilder $filterGroupBuilder,
        StoreHelper $storeHelper,
        GridHelper $gridHelper,
        Premium $premium,
        GeneratedText $generatedText,
        ApiSession $apiSession,
        MagentoUser $magentoUser,
        OutputHelper $outputHelper,
        ApiManager $apiManager,
        TimezoneInterface $timezone,
        FiltersHelper $filtersHelper,
        CategoriesDataHelper $categoriesDataHelper,
        StoreManagerInterface $storeManager,
        MagentoCategory $magentoCategory,
        UrlFinderInterface $urlFinder,
        Keywords $keywords,
        WtaImageHelper $wtaImageHelper,
        array $meta = [],
        array $data = []
    ) {
        $this->fieldHelper = $fieldHelper;
        $this->filterGroupBuilder = $filterGroupBuilder;
        $this->storeHelper = $storeHelper;
        $this->gridHelper = $gridHelper;
        $this->premium = $premium;
        $this->generatedText = $generatedText;
        $this->apiSession = $apiSession;
        $this->magentoUser = $magentoUser;
        $this->outputHelper = $outputHelper;
        $this->apiManager = $apiManager;
        $this->timezone = $timezone;
        $this->filtersHelper = $filtersHelper;
        $this->categoriesDataHelper = $categoriesDataHelper;
        $this->storeManager = $storeManager;
        $this->magentoCategory = $magentoCategory;
        $this->urlFinder = $urlFinder;
        $this->keywords = $keywords;
        $this->wtaImageHelper = $wtaImageHelper;

        parent::__construct(
            $name,
            $primaryFieldName,
            $requestFieldName,
            $reporting,
            $searchCriteriaBuilder,
            $request,
            $filterBuilder,
            $meta,
            $data
        );
    }

    // phpcs:disable Generic.Metrics.NestingLevel.TooHigh
    /**
     * @inheritdoc
     */
    public function addFilter(\Magento\Framework\Api\Filter $filter)
    {
        $filters = $this->request->getParam('filters');
        $storeId = !isset($filters['store_id']) ? Store::DEFAULT_STORE_ID : $filters['store_id'];

        if ($filter->getField() == 'writetextai_status') {
            if (!isset($filters['writetextai_status'])) {
                $filters['writetextai_status'] = [
                    'ai_fields' => [
                        'category page title',
                        'category page description',
                        'category description'
                    ],
                    'status' => 'all',
                    'no_activity_days' => 7,
                    'auto_text_optimizations' => AutomaticTextOptimization::SHOW_ALL,
                    'templates_fields' => AiStatus::TEMPLATES_SHOW_ALL,
                    'filter_by' => 'text_status',
                ];
            }
            $filters = $filters['writetextai_status'];
            $filters['store_id'] = $storeId;
            $status = $filters['status'];

            switch ($filters['filter_by']) {
                case 'text_status':
                    switch ($status) {
                        case AiStatus::WRITETEXTAI:
                            if (isset($filters['ai_fields']) && isset($filters['ai_status'])) {
                                $categoryIds = $this->getFilterByAiStatus($filters);
                                $filter = $this->filterBuilder->setField('entity_id')
                                    ->setValue($categoryIds)
                                    ->setConditionType('in')
                                    ->create();
                                $this->searchCriteriaBuilder->addFilter($filter);
                            }
                            break;
                        case AiStatus::NO_ACTIVITY:
                            if (!isset($filters['no_activity_days'])) {
                                break;
                            }
                            
                            $dates = $this->filtersHelper->getLastNumberOfDays($filters['no_activity_days']);
                            $actions = [
                                AiCategoryInterface::GENERATED_AT,
                                AiCategoryInterface::TRANSFERRED_AT,
                                AiCategoryInterface::EDITED_AT,
                                AiCategoryInterface::REVIEWED_AT
                            ];
                            foreach ($actions as $action) {
                                $filterLt = $this->filterBuilder->setField($action)
                                    ->setValue($dates['start_date'])
                                    ->setConditionType('lt')
                                    ->create();
                                $filterNull = $this->filterBuilder->setField($action)
                                    ->setConditionType('null')
                                    ->create();
                                $filtergroup = $this->filterGroupBuilder
                                    ->addFilter($filterLt)
                                    ->addFilter($filterNull)
                                    ->create();
                                $this->searchCriteriaBuilder->addFilterGroup($filtergroup);
                            }
                            break;
                        case AiStatus::NOT_GENERATED:
                            if (!isset($filters['ai_fields'])) {
                                break;
                            }
                            
                            $filters['ai_status'] = [
                                AiStatus::GENERATED,
                                AiStatus::TRANSFERRED,
                                AiStatus::EDITED,
                                AiStatus::REVIEWED,
                                AiStatus::FOR_TRANSFERRING
                            ];
                            $categoryIds = $this->getFilterByAiStatus($filters);
                            if (!empty($categoryIds)) {
                                $filter = $this->filterBuilder->setField('entity_id')
                                    ->setValue($categoryIds)
                                    ->setConditionType('nin')
                                    ->create();
                                $this->searchCriteriaBuilder->addFilter($filter);
                            }
                            break;
                        case 'review_status':
                            if (isset($filters['review_status'])) {
                                $categoryIds = $this->getFilterByReviewStatus($filters);
                                $filter = $this->filterBuilder->setField('entity_id')
                                    ->setValue($categoryIds)
                                    ->setConditionType('in')
                                    ->create();
                                $this->searchCriteriaBuilder->addFilter($filter);
                            }
                            break;
                    }
                    break;
                case 'keyword_status':
                    if (isset($filters['auto_text_optimizations']) &&
                        $filters['auto_text_optimizations'] !== AutomaticTextOptimization::SHOW_ALL
                    ) {
                        if ($filters['auto_text_optimizations'] !== AutomaticTextOptimization::NOT_OPTIMIZED) {
                            $categoryIds = $this->getFilterByKeywordState($filters);
                            $filter = $this->filterBuilder->setField('entity_id')
                                ->setValue($categoryIds)
                                ->setConditionType('in')
                                ->create();
                            $this->searchCriteriaBuilder->addFilter($filter);
                        } else {
                            $categoryIds = $this->getFilterByKeywordState($filters, true);
                            if (!empty($categoryIds)) {
                                $filter = $this->filterBuilder->setField('entity_id')
                                    ->setValue($categoryIds)
                                    ->setConditionType('nin')
                                    ->create();
                                $this->searchCriteriaBuilder->addFilter($filter);
                            }
                        }
                    }
                    break;
                case 'templates':
                    $this->applyGeneratedStatusFilter(
                        $filters,
                        'templates_fields',
                        'template_selected',
                        AiStatus::TEMPLATES_SHOW_ALL,
                        AiStatus::TEMPLATES_ALL,
                        'templateId'
                    );
                    break;
            }
        } elseif ($filter->getField() === 'status' && in_array(2, $filter->getValue())) {
            $nullFilter = $this->filterBuilder->setField('status')
                ->setValue(null)
                ->setConditionType('null')
                ->create();
            $zeroFilter = $this->filterBuilder->setField('status')
                ->setValue(0)
                ->setConditionType('eq')
                ->create();

            if (in_array(1, $filter->getValue())) {
                $enabledFilter = $this->filterBuilder->setField('status')
                    ->setValue(1)
                    ->setConditionType('eq')
                    ->create();
                $filtergroup = $this->filterGroupBuilder
                    ->addFilter($nullFilter)
                    ->addFilter($zeroFilter)
                    ->addFilter($enabledFilter)
                    ->create();
            } else {
                $filtergroup = $this->filterGroupBuilder
                    ->addFilter($nullFilter)
                    ->addFilter($zeroFilter)
                    ->create();
            }

            $this->searchCriteriaBuilder->addFilterGroup($filtergroup);
        } elseif ($filter->getField() == 'record_ids') {
            $recordIds = explode(',', $filters['record_ids'] ?? '');
            $filter = $this->filterBuilder->setField('entity_id')
                ->setValue($recordIds)
                ->setConditionType('in')
                ->create();
            $this->searchCriteriaBuilder->addFilter($filter);
        } elseif ($filter->getField() == 'request_id') {
            $recordIds = $this->getFilterByRequestId($filters);
            $filter = $this->filterBuilder->setField('entity_id')
                ->setValue($recordIds)
                ->setConditionType('in')
                ->create();
            $this->searchCriteriaBuilder->addFilter($filter);
        } else {
            $this->searchCriteriaBuilder->addFilter($filter);
        }
    }
    // phpcs:enable Generic.Metrics.NestingLevel.TooHigh
    
    /**
     * Apply generated status filter (templates or AI models)
     *
     * @param array $filters
     * @param string $fieldsKey
     * @param string $selectedKey
     * @param string $showAllValue
     * @param string $allValue
     * @param string $paramKey
     *
     * @return void
     */
    private function applyGeneratedStatusFilter(
        $filters,
        $fieldsKey,
        $selectedKey,
        $showAllValue,
        $allValue,
        $paramKey
    ) {
        if (isset($filters[$fieldsKey]) &&
            $filters[$fieldsKey] !== $showAllValue &&
            isset($filters[$selectedKey]) &&
            $filters[$selectedKey] !== $allValue &&
            $filters[$selectedKey] !== null &&
            $filters[$selectedKey] !== ''
        ) {
            $categoryIds = $this->getFilterByGeneratedStatus(
                $filters,
                $fieldsKey,
                $selectedKey,
                $paramKey
            );
            $filter = $this->filterBuilder->setField('entity_id')
                ->setValue($categoryIds)
                ->setConditionType('in')
                ->create();
            $this->searchCriteriaBuilder->addFilter($filter);
        }
    }

    /**
     * Get filter by generated status (generic method for templates and AI models)
     *
     * @param array $filters
     * @param string $fieldsKey
     * @param string $selectedKey
     * @param string $paramKey
     *
     * @return array
     */
    private function getFilterByGeneratedStatus($filters, $fieldsKey, $selectedKey, $paramKey)
    {
        $storeId = !isset($filters['store_id']) ? Store::DEFAULT_STORE_ID : $filters['store_id'];
        $language = $this->storeHelper->getFormattedLanguage($storeId);

        $params = [
            "type" => "Category",
            "storeId" => $storeId,
            "language" => $language,
            "fields" => [$filters[$fieldsKey]],
            $paramKey => $filters[$selectedKey]
        ];
        
        $result = $this->apiManager->getGeneratedStatus($params);
        $recordIds = array_column($result['records'], 'recordId');
        if (isset($result['continuationToken'])) {
            do {
                $params['continuationToken'] = $result['continuationToken'];
                $result = $this->apiManager->getGeneratedStatus($params);
                $recordIds = array_merge($recordIds, array_column($result['records'], 'recordId'));
            } while (isset($result['continuationToken']));
        }

        return $recordIds;
    }

    /**
     * Get filter by WriteText.ai status
     *
     * @param array $filters
     * @return array
     */
    public function getFilterByAiStatus($filters)
    {
        $storeId = !isset($filters['store_id']) ? Store::DEFAULT_STORE_ID : $filters['store_id'];
        $language = $this->storeHelper->getFormattedLanguage($storeId);

        $params = [
            "type" => "Category",
            "storeId" => $storeId,
            "language" => $language,
            "fields" => $filters['ai_fields'],
            "status" => $filters['ai_status']
        ];

        if (isset($filters['start_date'])) {
            $params['startDate'] = $filters['start_date'];
        }

        if (isset($filters['end_date'])) {
            $params['endDate'] = $filters['end_date'];
        }

        $result = $this->apiManager->getGeneratedStatus($params);
        $recordIds = array_column($result['records'], 'recordId');
        if (isset($result['continuationToken'])) {
            do {
                $params['continuationToken'] = $result['continuationToken'];
                $result = $this->apiManager->getGeneratedStatus($params);
                $recordIds = array_merge($recordIds, array_column($result['records'], 'recordId'));
            } while (isset($result['continuationToken']));
        }

        return $recordIds;
    }

    /**
     * @inheritdoc
     */
    public function getData()
    {
        $isXmlHttpRequest = $this->request->isXmlHttpRequest();
        $params = $this->request->getParams();

        /**
         * Filter items by store to prevent duplicate
         */
        $storeId = $this->getStoreIdAndFilter($params);

        $data = parent::getData();

        $data['current_user'] = $this->apiSession->getCurrentUserData();

        /**
         * If not ajax request, return the basic getData
         *
         * This case is for initial page load. No need to process
         * since there will be another getData when the grid load
         */
        if (!$isXmlHttpRequest) {
            $categories = [];
            foreach ($data['items'] as &$item) {
                $entityId = $item['entity_id'];
                if (!isset($categories[$entityId])) {
                    $item['view_url'] = '';
                    continue;
                }
            }
            return $data;
        }

        $data['ids'] = $this->getAllIds();

        $data['users'] = $this->magentoUser->getUsers();

        $hasProAccess = false;
        
        /** Start premium check */
        $premiumData = $this->collectPremiumData();
        $data = array_merge($data, $premiumData);
        $hasProAccess = $this->premium->getHasProAccess();
        /** End premium check */

        if (empty($data['items'])) {
            if ($this->errorMessage) {
                $data['error_message'] = $this->errorMessage;
            }
            return $data;
        }

        $categoryIds = array_column($data['items'], 'entity_id');

        $optimizationList = $result = $this->keywords->getOptimizationList(
            $storeId,
            [],
            null,
            'Category',
            $categoryIds
        );
        $generatedTextRaw = $this->generatedText->getGenerated(implode(",", $categoryIds ?? []), $storeId, 'Category');
              $generated = $this->generatedText->getGeneratedByStoreId(implode(",", $categoryIds ?? []), $storeId);
        $generatedDates = $this->generatedText->getRecordsLatestTextDate(
            implode(",", $categoryIds ?? []),
            $storeId,
            'Category',
            $generatedTextRaw
        );
        $includeEditedDatesPayload = true;
        $editedDates = $this->generatedText->getRecordsEditedDates(
            implode(",", $categoryIds ?? []),
            $storeId,
            'Category',
            $generatedTextRaw,
            $includeEditedDatesPayload
        );
        if ($includeEditedDatesPayload && isset($editedDates['_payload'])) {
            $data['wtai_debug_edited_dates_payload'] = $editedDates['_payload'];
            unset($editedDates['_payload']);
        }

        $mappingSettings = $this->fieldHelper->getMappingSettings();

        $generatedKeys = [];
        foreach (Fields::CATEGORY_MAPPING as $field => $mapping) {
            $generatedKeys[$mapping] = 'ai_' . $field;
        }

        $defaultKeys = [
            'name' => 'default_name',
            'path' => 'default_path',
            'status' => 'default_status',
            'mg_page_title' => 'default_mg_page_title',
            'mg_page_description' => 'default_mg_page_description',
            'mg_category_description' => 'default_mg_category_description',
            'thumbnail' => 'default_thumbnail'
        ];

        $keys = [
            'name' => 'name',
            'path' => 'path',
            'status' => 'is_active',
            'mg_page_title' => $mappingSettings['page_title'],
            'mg_page_description' => $mappingSettings['page_description'],
            'mg_category_description' => $mappingSettings['category_description'],
            'thumbnail' => 'image'
        ];

        $categoryIds = array_column($data['items'], 'entity_id');

        $categories = $this->categoriesDataHelper->collectCategories($storeId, $categoryIds);

        $languageCode = $this->storeHelper->getLanguageCode($storeId);
        
        $locale = $this->apiSession->getCurrentUser()->getInterfaceLocale();

        $canShowViewUrl = ((int) $storeId !== (int) Store::DEFAULT_STORE_ID);
        $frontendStoreId = (int) $this->storeHelper->getFrontendStoreId($storeId);
        $useStoreSwitchUrl = ((int) $storeId === (int) Store::DEFAULT_STORE_ID);
        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;
            }
        }
        $rootCategoryChildren = [];
        $rootCategoryChildrenLookup = [];
        if ($canShowViewUrl) {
            $rootCategoryId = $this->storeManager->getStore($storeId)->getRootCategoryId();
            $rootCategoryChildren = $this->magentoCategory->getRootChildren($rootCategoryId, $storeId);
            $rootCategoryChildrenLookup = array_fill_keys($rootCategoryChildren, true);
        }

        foreach ($data['items'] as &$item) {
            $entityId = $item['entity_id'];

            $category = $categories[$entityId];

            $categoryImage = $item['thumbnail'];
            $item['thumbnail'] = $this->wtaImageHelper->getCategoryImageUri($category);

            if (isset($generated[$entityId])) {
                foreach ($generatedKeys as $generatedKey => $itemKey) {
                    if (isset($generated[$entityId][$generatedKey])) {
                        $item[$itemKey] = $generated[$entityId][$generatedKey];
                    }
                }
            }

            $item['wtai_thumbnail_src'] = $item['thumbnail'];
            $item['wtai_thumbnail_orig_src'] = $item['thumbnail'];

            // handle store switcher
            foreach ($defaultKeys as $itemKey => $defaultKey) {
                $isUsingDefault = $this->fieldHelper->isUsingDefaultValues($category, $storeId, $keys[$itemKey]);

                if ($storeId !== Store::DEFAULT_STORE_ID && $isUsingDefault) {
                    $item[$itemKey] = $item[$defaultKey];

                    if ($itemKey === 'thumbnail') {
                        $item[$defaultKey] = $this->wtaImageHelper->getCategoryImageUri($category);
                        $item[$itemKey] = $item[$defaultKey];
                        $item['wtai_thumbnail_src'] = $item[$defaultKey];
                        $item['wtai_thumbnail_orig_src'] = $item[$defaultKey];
                    }
                }
            }
            
            $item = $this->decodeHtmlEntities($category, $item, $mappingSettings);

            if ($item['status'] === null || (int)$item['status'] === 0) {
                $item['status'] = \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED;
                $item['default_status'] = \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED;
            }

            $item['language'] = $languageCode;

            $data['grid_settings'] = $this->gridHelper->getGridSettings();

            if ($canShowViewUrl && isset($rootCategoryChildrenLookup[$entityId])) {
                $item['view_url'] = $this->getUrlByCategoryId($category, $entityId, $storeId, $useStoreSwitchUrl);
            } else {
                $item['view_url'] = '';
            }

            if (isset($generatedDates[$entityId])) {
                $staticGDate = new \DateTime($generatedDates[$entityId]);
                $formattedGDate = $this->timezone->formatDate(
                    $staticGDate,
                    \IntlDateFormatter::SHORT,
                    $locale
                );
                $item['generated_at'] = $formattedGDate;
            }

            if (isset($item['transferred_at'])) {
                $staticTDate = new \DateTime($item['transferred_at']);
                $formattedTDate = $this->timezone->formatDate(
                    $staticTDate,
                    \IntlDateFormatter::SHORT,
                    $locale
                );
                $item['transferred_at'] = $formattedTDate;
            }
            if (isset($editedDates[$entityId]['edited_at']) && $editedDates[$entityId]['edited_at']) {
                $staticEDate = new \DateTime($editedDates[$entityId]['edited_at']);
                $formattedEDate = $this->timezone->formatDate(
                    $staticEDate,
                    \IntlDateFormatter::SHORT,
                    $locale
                );
                $item['edited_at'] = $formattedEDate;
            } else {
                $item['edited_at'] = '';
            }

            $item['breadcrumbs'] = $this->categoriesDataHelper->getBreadcrumbs($category, $storeId);
            $item['target_keywords'] = $this->getTargetKeywords($entityId, $storeId, $optimizationList['result'] ?? []);
            $item['traffic_potential'] = $this->getTrafficPotential(
                $entityId,
                $storeId,
                $hasProAccess,
                $optimizationList['result'] ?? []
            );
            $item['optimization_status'] = $this->getOptimizationDataStatus(
                $entityId,
                $storeId,
                $optimizationList['result'] ?? []
            );
        }

        if ($this->errorMessage) {
            $data['error_message'] = $this->errorMessage;
        }
        return $data;
    }

    /**
     * Get traffic potential
     *
     * @param int $entityId
     * @param int $storeId
     * @param bool $hasProAccess
     * @param array $optimizationList
     *
     * @return string
     */
    private function getTrafficPotential($entityId, $storeId, $hasProAccess, $optimizationList)
    {
        if (!$hasProAccess) {
            return __('Data available in Pro');
        }

        $optimizationData = array_filter(
            $optimizationList,
            function ($item) use ($entityId) {
                return isset($item['recordId']) && $item['recordId'] === $entityId;
            }
        );
        $optimizationData = reset($optimizationData) ?: null;

        if (isset($optimizationData['trafficPotentialDisplay'])) {
            return $optimizationData['trafficPotentialDisplay'] ?? __('No data');
        }

        return __('Pending analysis');
    }

    /**
     * Get target keywords
     *
     * @param int $entityId
     * @param int $storeId
     * @param array $optimizationList
     *
     * @return string
     */
    private function getTargetKeywords($entityId, $storeId, $optimizationList)
    {
        $optimizationData = array_filter(
            $optimizationList,
            function ($item) use ($entityId) {
                return isset($item['recordId']) && $item['recordId'] === $entityId;
            }
        );
        $optimizationData = reset($optimizationData) ?: null;

        if (isset($optimizationData['optimizingKeywords'])) {
            if (empty($optimizationData['optimizingKeywords'])) {
                return __('No data');
            }
            return implode(', ', $optimizationData['optimizingKeywords']);
        }

        return __('Pending analysis');
    }
    
    /**
     * Get optimization data status
     *
     * @param int $entityId
     * @param int $storeId
     * @param array $optimizationList
     *
     * @return string
     */
    private function getOptimizationDataStatus($entityId, $storeId, $optimizationList)
    {
        $optimizationData = array_filter(
            $optimizationList,
            function ($item) use ($entityId) {
                return isset($item['recordId']) && $item['recordId'] === $entityId;
            }
        );
        $optimizationData = reset($optimizationData) ?: null;

        if (isset($optimizationData['status'])) {
            return $optimizationData['status'];
        }

        return null;
    }

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

        $targetUrl = $useStoreSwitchUrl
            ? $this->normalizeFrontendUrl((int) $storeId, (string) $targetUrl)
            : $targetUrl;

        return $useStoreSwitchUrl
            ? $this->buildFrontendStoreSwitchUrl((int) $storeId, (string) $targetUrl)
            : $targetUrl;
    }
    /**
     * 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;
        }

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

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

    /**
     * Get store id and filter
     *
     * @param array $params
     * @return int
     */
    private function getStoreIdAndFilter($params)
    {
        $filters = $params['filters'] ?? [];

        if (!isset($filters['store_id'])) {
            $storeId = Store::DEFAULT_STORE_ID;
            $this->searchCriteriaBuilder->addFilter(
                $this->filterBuilder->setField('store_id')
                    ->setValue($storeId)
                    ->setConditionType('eq')
                    ->create()
            );
        } else {
            $storeId = $filters['store_id'];
        }

        // Set default writetextai_status filter when placeholder is true
        if (isset($filters['writetextai_status']) &&
            isset($filters['writetextai_status']['initial']) &&
            $filters['writetextai_status']['initial'] === true) {
            $defaultWritetextaiStatus = [
                'ai_fields' => [
                    'category page title',
                    'category page description',
                    'category description'
                ],
                'status' => 'all',
                'no_activity_days' => 7,
                'auto_text_optimizations' => AutomaticTextOptimization::SHOW_ALL,
                'templates_fields' => AiStatus::TEMPLATES_SHOW_ALL,
                'filter_by' => 'text_status'
            ];
            
            // Add the default writetextai_status filter
            $this->addFilter(
                $this->filterBuilder->setField('writetextai_status')
                    ->setValue(json_encode($defaultWritetextaiStatus))
                    ->setConditionType('eq')
                    ->create()
            );
        }
        
        $rootCategoryId = $this->storeManager->getStore($storeId)->getRootCategoryId();

        $rootCategoryChildren = $this->magentoCategory->getRootChildren($rootCategoryId, $storeId);

        if ($storeId !== Store::DEFAULT_STORE_ID) {
            $this->searchCriteriaBuilder->addFilter(
                $this->filterBuilder->setField('entity_id')
                    ->setValue($rootCategoryChildren)
                    ->setConditionType('in')
                    ->create()
            );
        }

        return $storeId;
    }

    /**
     * Get all ids in grid preserving sort and filter
     *
     * @return array
     */
    protected function getAllIds()
    {
        $ids = [];
        $collection = clone $this->getSearchResult();
        $collection->load();
        $select = $collection->getSelect()
            ->reset(\Magento\Framework\DB\Select::COLUMNS)
            ->columns(['entity_id'])
            ->reset(\Magento\Framework\DB\Select::LIMIT_COUNT)
            ->reset(\Magento\Framework\DB\Select::LIMIT_OFFSET);

        if (empty($select->getPart(\Magento\Framework\DB\Select::ORDER))) {
            $select->order('main_table.entity_id ASC');
        }

        $connection = $this->getSearchResult()->getResource()->getConnection();

        $ids = $connection->fetchCol($select);

        return $ids;
    }

    /**
     * Decode html entities
     *
     * @param \Magento\Catalog\Model\Category $category
     * @param array $item
     * @param array $mappingSettings
     * @return array
     */
    private function decodeHtmlEntities($category, $item, $mappingSettings)
    {
        $keys = [
            'mg_page_title' => 'page_title',
            'mg_page_description' => 'page_description',
            'mg_category_description' => 'category_description',
            'ai_page_title' => 'page_title',
            'ai_page_description' => 'page_description',
            'ai_category_description' => 'category_description'
        ];

        foreach ($keys as $key => $mapping) {
            if (isset($item[$key])) {
                $item[$key] = $this->outputHelper->categoryAttribute(
                    $category,
                    $item[$key],
                    $mappingSettings[$mapping] ?? $mapping
                );
            }
        }

        return $item;
    }

    /**
     * Get filter by keyword state
     *
     * @param array $filters
     * @param bool $isNotOptimized
     *
     * @return array
     */
    public function getFilterByKeywordState($filters, $isNotOptimized = false)
    {
        $storeId = !isset($filters['store_id']) ? Stpre::DEFAULT_STORE_ID : $filters['store_id'];

        $statuses = [];
        if (!$isNotOptimized) {
            $reviewStatus = $filters['keyword_analysis'];
            if (is_array($reviewStatus)) {
                foreach ($reviewStatus as $status) {
                    switch ($status) {
                        case AutomaticTextOptimization::GENERATED:
                            $statuses[] = 'Generated';
                            break;
                        case AutomaticTextOptimization::FOR_GENERATION:
                            $statuses[] = 'ForGeneration';
                            break;
                        case AutomaticTextOptimization::PUBLISHED:
                            $statuses[] = 'Published';
                            break;
                    }
                }
            }
        } else {
            $statuses[] = 'Generated';
            $statuses[] = 'ForGeneration';
            $statuses[] = 'Published';
        }

        $result = $this->keywords->getKeywordState($storeId, $statuses, null, 'Category');
        $recordIds = array_column($result['keywords'], 'recordId');
        if (isset($result['continuationToken'])) {
            do {
                $result = $this->keywords->getKeywordState(
                    $storeId,
                    $statuses,
                    $result['continuationToken'],
                    'Category'
                );
                $recordIds = array_merge($recordIds, array_column($result['keywords'], 'recordId'));
            } while (isset($result['continuationToken']));
        }

        return $recordIds;
    }

    /**
     * Get filter by WriteText.ai status
     *
     * @param array $filters
     * @return array
     */
    public function getFilterByReviewStatus($filters)
    {
        $storeId = !isset($filters['store_id']) ? Store::DEFAULT_STORE_ID : $filters['store_id'];
        $language = $this->storeHelper->getRegionIndependentLanguage($storeId);

        $statuses = [];
        $reviewStatus = $filters['review_status'];
        if (in_array('for_rewrite', $reviewStatus)) {
            $statuses[] = 'EditForRewrite';
            $statuses[] = 'EditForRewriteAndCorrection';
        }
        if (in_array('fact_check', $reviewStatus)) {
            $statuses[] = 'EditForCorrection';
            $statuses[] = 'EditForRewriteAndCorrection';
        }
        if (in_array('for_rewrite', $reviewStatus) && in_array('fact_check', $reviewStatus)) {
            $statuses[] = 'EditForRewriteAndCorrection';
        }

        $params = [
            "type" => "Category",
            "storeId" => $storeId,
            "language" => $language,
            "fields" => $filters['ai_fields'],
            "status" => $statuses
        ];

        $result = $this->apiManager->filterReviewStatus($params);
        $recordIds = array_column($result['records'], 'recordId');
        if (isset($result['continuationToken'])) {
            do {
                $params['continuationToken'] = $result['continuationToken'];
                $result = $this->apiManager->filterReviewStatus($params);
                $recordIds = array_merge($recordIds, array_column($result['records'], 'recordId'));
            } while (isset($result['continuationToken']));
        }

        return $recordIds;
    }

    /**
     * Get filter by request id
     *
     * @param array $filters
     * @return array
     */
    private function getFilterByRequestId($filters)
    {
        $result = [];
        $ids = [];
        try {
            $requestId = $filters['request_id'];
            $textGenerateStatus = isset($filters['text_generation_status'])
                ? $filters['text_generation_status'] : 'success';
            $result = $this->apiManager->getBulkRequestById($requestId);
            if (!empty($result)) {
                $resultStatus = $result['status'];
                if ($textGenerateStatus === 'success') {
                    $completedIds = $result['completedIds'] ?? [];
                    $failedIds = $result['failedIds'] ?? [];
                    $completedIds = array_values(array_diff($completedIds, $failedIds));
                    $ids = $completedIds;
                } elseif ($textGenerateStatus === 'skipped') {
                    $ids = $result['skippedIds'] ?? [];
                } elseif ($textGenerateStatus === 'failed-transfer') {
                    $ids = $result['failedTransferIds'] ?? [];
                } else {
                    if ($resultStatus === 'Pending' ||
                        $resultStatus === 'Running' ||
                        $resultStatus === 'Cancelling' ||
                        $resultStatus === 'Cancelled') {
                        $ids = $result['failedIds'] ?? [];
                    } elseif ($resultStatus === 'Completed' ||
                        $resultStatus === 'Failed' ||
                        $resultStatus === 'TimedOut') {
                        $ids = array_merge(
                            $result['failedIds'] ?? [],
                            $result['queuedIds'] ?? [],
                            $result['runningIds'] ?? []
                        );
                    }
                }
            }
        } catch (\WriteTextAI\WriteTextAI\Exception\ApiException $e) {
            if ($e->getCode() === 404) {
                $message =  __('The list of products you’re trying to view cannot be retrieved.'
                . ' This may happen if the link has expired or if there’s a typo in the URL.'
                . ' Please recheck the link. If the issue continues, the list no longer exists.');
                $this->errorMessage = $message;
                $ids = [];
            }
        } catch (\Exception $e) {
            $message = __(
                'A system error has occurred. Please try again. If the issue persists,'
                . ' please contact our support team at support@writetext.ai.'
            );
            $this->errorMessage = $message;
            $ids = [];
        }
        return $ids;
    }
}
