<?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;

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 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 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,
        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;

        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' => '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'])) {
                                $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'])) {
                                $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;
            }
        } 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);
        } else if ($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

    /**
     * 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();

        /**
         * 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();

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

        $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
        );
        $generated = $this->generatedText->getGeneratedByStoreId(implode(",", $categoryIds ?? []), $storeId);

        $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();

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

            $category = $categories[$entityId];

            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['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();
            
            $item['view_url'] = $this->getUrlByCategoryId($category, $entityId, $storeId);

            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($item['edited_at'])) {
                $staticEDate = new \DateTime($item['edited_at']);
                $formattedEDate = $this->timezone->formatDate(
                    $staticEDate,
                    \IntlDateFormatter::SHORT,
                    $locale
                );
                $item['edited_at'] = $formattedEDate;
            }

            $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
     * @return string
     */
    public function getUrlByCategoryId($category, $categoryId, $storeId)
    {
        $rewrite = $this->urlFinder->findOneByData([
            UrlRewriteData::ENTITY_ID => $categoryId,
            UrlRewriteData::ENTITY_TYPE => 'category',
            UrlRewriteData::STORE_ID => $storeId
        ]);
        
        $category->getUrlInstance()->setScope($storeId);
        
        $targetPath = (!$rewrite) ? $category->getUrl() :
            $this->storeManager->getStore($storeId)->getBaseUrl() . $rewrite->getRequestPath();

        return $targetPath;
    }

    /**
     * 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' => '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;
                } else if ($textGenerateStatus === 'failed-transfer') {
                    $ids = $result['failedTransferIds'] ?? [];
                }  else {
                    if ($resultStatus === 'Pending' ||
                        $resultStatus === 'Running' ||
                        $resultStatus === 'Cancelling' ||
                        $resultStatus === 'Cancelled') {
                        $ids = $result['failedIds'] ?? [];
                    } else if ($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;
    }
}
