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

namespace WriteTextAI\WriteTextAI\Model\Magento;

use Magento\Catalog\Model\ResourceModel\Product\Collection;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory as CategoryCollectionFactory;
use Magento\Catalog\Model\Category as MagentoCategory;
use Magento\Catalog\Model\Product\Visibility;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
use Magento\Store\Model\Store;
use Magento\Catalog\Helper\Image as ImageHelper;
use WriteTextAI\WriteTextAI\Helper\Image as WtaImageHelper;
use WriteTextAI\WriteTextAI\Helper\Data;
use WriteTextAI\WriteTextAI\Model\SettingManager;
use Magento\Framework\Stdlib\StringUtils;

class Category
{
    /**
     * @var int
     */
    public const RANDOM_PRODUCTS_LIMIT = 100;

    /**
     * @var MagentoCategory
     */
    protected $category;
    
    /**
     * @var CategoryCollectionFactory
     */
    protected $categoryCollectionFactory;

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

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

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

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

    /**
     * @var SettingManager
     */
    protected $settingManager;

    /**
     * @var StringUtils
     */
    protected $stringUtils;

    /**
     * Constructor
     *
     * @param CategoryCollectionFactory $categoryCollectionFactory
     * @param CollectionFactory $productCollectionFactory
     * @param ImageHelper $imageHelper
     * @param WtaImageHelper $wtaImageHelper
     * @param Data $helper
     * @param SettingManager $settingManager
     * @param StringUtils $stringUtils
     */
    public function __construct(
        CategoryCollectionFactory $categoryCollectionFactory,
        CollectionFactory $productCollectionFactory,
        ImageHelper $imageHelper,
        WtaImageHelper $wtaImageHelper,
        Data $helper,
        SettingManager $settingManager,
        StringUtils $stringUtils
    ) {
        $this->categoryCollectionFactory = $categoryCollectionFactory;
        $this->productCollectionFactory = $productCollectionFactory;
        $this->imageHelper = $imageHelper;
        $this->wtaImageHelper = $wtaImageHelper;
        $this->helper = $helper;
        $this->settingManager = $settingManager;
        $this->stringUtils = $stringUtils;
    }
    
    /**
     * Get category object
     *
     * @param int $categoryId
     * @param int $storeId
     *
     * @return MagentoCategory
     */
    public function getCategory($categoryId, $storeId)
    {
        if ($this->category
            && $this->category->getId() === $categoryId
            && $this->category->getStoreId() === $storeId
        ) {
            return $this->category;
        }

        $collection = $this->categoryCollectionFactory->create();
        $collection->setStoreId($storeId);
        $collection->addAttributeToSelect('*');
        $collection->addFieldToFilter('entity_id', $categoryId);
        
        $this->category = $collection->getFirstItem();

        return $this->category;
    }

    /**
     * Get all children categories IDs
     *
     * @param boolean $asArray
     * @param int $categoryId
     * @param int $storeId
     *
     * @return array|string
     */
    public function getAllChildren($asArray = false, $categoryId = null, $storeId = null)
    {
        $category;
        if ($this->category
            && $this->category->getId() === $categoryId
            && $this->category->getStoreId() === $storeId
        ) {
            $category = $this->category;
        } else {
            $category = $this->getCategory($categoryId, $storeId);
        }

        return $category->getAllChildren($asArray);
    }

    /**
     * Get all children of root category
     *
     * @param int $categoryId
     * @param int $storeId
     *
     * @return array|string
     */
    public function getRootChildren($categoryId, $storeId)
    {
        $category;
        if ($this->category
            && $this->category->getId() === $categoryId
            && $this->category->getStoreId() === $storeId
        ) {
            $category = $this->category;
        } else {
            $category = $this->getCategory($categoryId, $storeId);
        }
        
        $collection = $this->categoryCollectionFactory->create();
        $collection->addAttributeToFilter('path', ['like' => $category->getPath() . '/%']);
        return $collection->getAllIds();
    }

    /**
     * Get product collection
     *
     * @param array $categoryIds
     * @param int $storeId
     * @param int $page
     * @param string $search
     * @param int $limit
     *
     * @return array
     */
    public function getProductCollection($categoryIds, $storeId, $page = 1, $search = '', $limit = 10)
    {
        $storeId = (int) $storeId;
        $page = (int) $page;
        $limit = (int) $limit;

        if (!is_array($categoryIds) || empty($categoryIds)) {
            return [
                'all_options' => [],
                'options' => [],
                'total' => 0
            ];
        }

        $collection = $this->productCollectionFactory->create();
        $collection->setStoreId($storeId);
        $collection->addAttributeToSelect('*');
        $collection->addAttributeToSort('name', 'ASC');
        $collection->addCategoriesFilter(['in' => $categoryIds]);
        $collection->addFieldToFilter('status', Status::STATUS_ENABLED);

        if ($storeId !== Store::DEFAULT_STORE_ID) {
            $collection->addStoreFilter($storeId);
        }

        if ($search) {
            $collection->addFieldToFilter('name', ['like' => '%' . $search . '%']);
        }

        $productIds = $collection->getAllIds();

        $collection->setPageSize($limit * $page);
        $collection->addMediaGalleryData();

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

        return [
            'all_options' => $productIds,
            'options' => $options,
            'total' => $collection->getSize()
        ];
    }

    /**
     * Get all products name randomly
     *
     * @param int $categoryId
     * @param int $storeId
     * @param int $limit
     *
     * @return array
     */
    public function getAllProductsNameRandomly(
        $categoryId,
        $storeId,
        $limit = self::RANDOM_PRODUCTS_LIMIT
    ) {
        $productNames = [];
        try {
            $rules = $this->settingManager->getSettings('rules');
            $maxNameLength = $rules['maxNameLength'] ?? 100;
            $subCategories = $this->getAllChildren(true, $categoryId, $storeId);
            
            $collection = $this->productCollectionFactory->create();
            $collection->setStoreId($storeId);
            $collection->addStoreFilter($storeId);
            $collection->addAttributeToSelect('*');
            $collection->addAttributeToSort('name', 'ASC');
            $collection->addCategoriesFilter(['in' => $subCategories]);
            $collection->addFieldToFilter('status', Status::STATUS_ENABLED);
            $collection->addAttributeToFilter(
                'visibility',
                ['neq' => Visibility::VISIBILITY_NOT_VISIBLE]
            );
            
            $sampleData = $collection->getAllIds();

            if ($sampleData) {
                shuffle($sampleData);
                $randomIds = array_slice($sampleData, 0, $limit);
                $collection->addFieldToFilter('entity_id', ['in' => $randomIds]);
                $collection->addIdFilter($randomIds);

                $productNames = [];
                foreach ($collection as $product) {
                    $productNames[] = $this->stringUtils->substr($product->getName(), 0, $maxNameLength);
                }
                
                //clear memory
                $collection->clear();
                $collection = null;
                unset($collection);
            }
            //code...
        } catch (\Exception $e) {
            return [];
        }
        
        return $productNames;
    }
}
