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

namespace WriteTextAI\WriteTextAI\Model\Categories;

use WriteTextAI\WriteTextAI\Model\Categories\GeneratedText;
use WriteTextAI\WriteTextAI\Model\ApiManager;
use WriteTextAI\WriteTextAI\Helper\Categories\Fields as FieldsHelper;
use WriteTextAI\WriteTextAI\Helper\Data as DataHelper;
use Magento\Store\Model\Store;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory;
use WriteTextAI\WriteTextAI\Model\OptionSource\Filter\Fields;
use Magento\Catalog\Model\CategoryRepository;

class ReviewStatus
{
    /**
     * @var GeneratedText
     */
    protected $generatedText;

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

    /**
     * @var FieldsHelper
     */
    protected $fieldsHelper;

    /**
     * @var DataHelper
     */
    protected $dataHelper;

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

    /**
     * @var AttributeFactory
     */
    protected $attributeFactory;

    /**
     * @var CategoryRepository
     */
    protected $categoryRepository;

    /**
     * @var array
     */
    protected $storeIds = [];

    /**
     * @var array
     */
    protected $reviewsToUpdate = [];

    /**
     * @var array
     */
    protected $reviewStatuses = [];

    /**
     * Constructor
     *
     * @param GeneratedText $generatedText
     * @param ApiManager $apiManager
     * @param FieldsHelper $fieldsHelper
     * @param DataHelper $dataHelper
     * @param StoreManagerInterface $storeManager
     * @param AttributeFactory $attributeFactory
     * @param CategoryRepository $categoryRepository
     */
    public function __construct(
        GeneratedText $generatedText,
        ApiManager $apiManager,
        FieldsHelper $fieldsHelper,
        DataHelper $dataHelper,
        StoreManagerInterface $storeManager,
        AttributeFactory $attributeFactory,
        CategoryRepository $categoryRepository
    ) {
        $this->generatedText = $generatedText;
        $this->apiManager = $apiManager;
        $this->fieldsHelper = $fieldsHelper;
        $this->dataHelper = $dataHelper;
        $this->storeManager = $storeManager;
        $this->attributeFactory = $attributeFactory;
        $this->categoryRepository = $categoryRepository;
    }
    
    /**
     * Update review
     *
     * @param array $textTypes
     * @param int $categoryId
     * @param array $selectedStores
     * @param array $categories
     *
     * @return void
     */
    public function updateReview($textTypes, $categoryId, $selectedStores, $categories = [])
    {
        $this->reviewsToUpdate = [];

        if (empty($textTypes)) {
            return;
        }
        $convertedTextTypes = [];
        foreach ($textTypes as $selectedField) {
            if (isset(Fields::CATEGORY_MAPPING[$selectedField])) {
                $convertedTextTypes[] = Fields::CATEGORY_MAPPING[$selectedField];
            }
        }

        if ($convertedTextTypes) {
            $textTypes = $convertedTextTypes;
        }

        $this->updateReviewForGlobalAttributes($textTypes, $categoryId);

        if (in_array(Store::DEFAULT_STORE_ID, $selectedStores)) {
            $this->updateFieldsUsingDefaultValue($textTypes, $categoryId, $categories);
        } else {
            $this->getReviewsToUpdate($textTypes, $categoryId, $selectedStores);
        }

        $this->batchUpdateReviews();
    }

    /**
     * Batch update reviews
     */
    public function batchUpdateReviews()
    {
        $reviews = $this->reviewsToUpdate;

        $uniqueReviews = array_reduce($reviews, function ($carry, $item) {
            if (!isset($carry[$item['id']])) {
                $carry[$item['id']] = $item;
            }
            return $carry;
        }, []);

        if (!empty($uniqueReviews)) {
            $reviewsToUpdate = [
                'type' => 'Category',
                'reviews' => array_values($uniqueReviews)
            ];
    
            $this->apiManager->batchUpdateReviews(json_encode($reviewsToUpdate));
        }
    }

    /**
     * Update review for global attributes
     *
     * @param array $textTypes
     * @param int $categoryId
     *
     * @return void
     */
    public function updateReviewForGlobalAttributes($textTypes, $categoryId)
    {
        $mappingSettings = $this->fieldsHelper->getMappingSettings();
        $globalTextTypes = [];
        foreach ($textTypes as $textType) {
            $fieldTextType = array_search($textType, Fields::CATEGORY_MAPPING);
            $attributeCode = $mappingSettings[$fieldTextType];
            $attribute = $this->attributeFactory->create();
            $attribute->loadByCode(\Magento\Catalog\Model\Category::ENTITY, $attributeCode);

            if ($attribute->isScopeGlobal()) {
                $globalTextTypes[] = $textType;
            }
        }

        if (empty($globalTextTypes)) {
            return;
        }
        
        $storeIds = $this->getStoreIds();

        $this->getReviewsToUpdate($globalTextTypes, $categoryId, $storeIds);
    }

    /**
     * Get store ids
     *
     * @return array
     */
    private function getStoreIds()
    {
        if (!empty($this->storeIds)) {
            return $this->storeIds;
        }

        $stores = $this->storeManager->getStores();
        foreach ($stores as $store) {
            $this->storeIds[] = $store->getId();
        }

        return $this->storeIds;
    }

    /**
     * Update fields using default value
     *
     * @param array $textTypes
     * @param int $categoryId
     * @param array $categories
     *
     * @return void
     */
    public function updateFieldsUsingDefaultValue($textTypes, $categoryId, $categories)
    {
        $mappingSettings = $this->fieldsHelper->getMappingSettings();
        foreach ($textTypes as $textType) {
            $fieldTextType = array_search($textType, Fields::CATEGORY_MAPPING);
            $attributeCode = $mappingSettings[$fieldTextType];
            $attribute = $this->attributeFactory->create();
            $attribute->loadByCode(\Magento\Catalog\Model\Category::ENTITY, $attributeCode);

            if ($attribute->isScopeGlobal()) {
                continue;
            }

            $storeIds = $this->getStoreIds();

            foreach ($storeIds as $storeId) {
                if (!empty($categories) && isset($categories[$storeId])) {
                    $category = $categories[$storeId];
                } else {
                    $category = $this->categoryRepository->get($categoryId, $storeId);
                }

                if ($this->fieldsHelper->isUsingDefaultValues($category, $storeId, $attributeCode)) {
                    $this->getReviewsToUpdate([$textType], $categoryId, [$storeId]);
                }
            }
        }
    }

    /**
     * Get reviews to update
     *
     * @param array $textTypes
     * @param int $categoryId
     * @param array $selectedStores
     *
     * @return void
     */
    public function getReviewsToUpdate($textTypes, $categoryId, $selectedStores)
    {
        $reviewsToUpdate = [];

        foreach ($selectedStores as $storeId) {
            if (!isset($this->reviewStatuses[$storeId])) {
                $reviewStatuses = $this->generatedText->getReviewStatus($categoryId, $storeId, 'Category');
                $this->reviewStatuses[$storeId] = $reviewStatuses;
            } else {
                $reviewStatuses = $this->reviewStatuses[$storeId];
            }
            
            if (empty($reviewStatuses)) {
                continue;
            }

            foreach ($reviewStatuses as $reviewStatus) {
                if (!isset($reviewStatus['fields']) || !is_array($reviewStatus['fields'])) {
                    continue;
                }

                $fieldsToUpdate = [];
                foreach ($reviewStatus['fields'] as $field) {
                    foreach ($textTypes as $textType) {
                        if (isset($field['field']) &&
                            $field['field'] === $textType &&
                            isset($field['status']) &&
                            $field['status'] !== -1
                        ) {
                            $field['status'] = -1;
                            $fieldsToUpdate[] = $field;
                        }
                    }
                }
                
                if (empty($fieldsToUpdate)) {
                    continue;
                }
    
                $params = [
                    "id" => $reviewStatus['id'],
                    "recordId" => $categoryId,
                    "comment" => $reviewStatus['comment'] ?? '',
                    "fields" => $fieldsToUpdate
                ];
    
                $reviewsToUpdate[] = $params;
            }
        }

        foreach ($reviewsToUpdate as $reviewToUpdate) {
            $found = false;
            foreach ($this->reviewsToUpdate as &$reviewStatus) {
                if ($reviewToUpdate['id'] === $reviewStatus['id']) {
                    $reviewStatus['fields'] = array_merge($reviewStatus['fields'], $reviewToUpdate['fields']);
                    $reviewStatus['fields'] = array_unique($reviewStatus['fields'], SORT_REGULAR);
                    $found = true;
                }
            }
            if (!$found) {
                $this->reviewsToUpdate[] = $reviewToUpdate;
            }
        }
    }
}
