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

namespace WriteTextAI\WriteTextAI\Model;

use WriteTextAI\WriteTextAI\Model\GeneratedText;
use WriteTextAI\WriteTextAI\Model\ApiManager;
use WriteTextAI\WriteTextAI\Helper\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\Helper\Product as ProductHelper;
use WriteTextAI\WriteTextAI\Model\OptionSource\Filter\Fields;

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 ProductHelper
     */
    protected $productHelper;

    /**
     * @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 ProductHelper $productHelper
     */
    public function __construct(
        GeneratedText $generatedText,
        ApiManager $apiManager,
        FieldsHelper $fieldsHelper,
        DataHelper $dataHelper,
        StoreManagerInterface $storeManager,
        AttributeFactory $attributeFactory,
        ProductHelper $productHelper
    ) {
        $this->generatedText = $generatedText;
        $this->apiManager = $apiManager;
        $this->fieldsHelper = $fieldsHelper;
        $this->dataHelper = $dataHelper;
        $this->storeManager = $storeManager;
        $this->attributeFactory = $attributeFactory;
        $this->productHelper = $productHelper;
    }
    
    /**
     * Update review
     *
     * @param array $textTypes
     * @param int $productId
     * @param array $selectedStores
     * @param array $products
     *
     * @return void
     */
    public function updateReview($textTypes, $productId, $selectedStores, $products = [])
    {
        $this->reviewsToUpdate = [];

        $fieldConfig = [
            'page_title' => Fields::PAGE_TITLE,
            'page_description' => Fields::PAGE_DESCRIPTION,
            'product_description' => Fields::PRODUCT_DESCRIPTION,
            'short_product_description' => Fields::EXCERPT,
            'open_graph' => Fields::OPEN_GRAPH,
        ];

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

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

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

        if (in_array(Store::DEFAULT_STORE_ID, $selectedStores)) {
            $this->updateFieldsUsingDefaultValue($textTypes, $productId, $products, $selectedStores);
        } else {
            $this->getReviewsToUpdate($textTypes, $productId, $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' => 'Product',
                'reviews' => array_values($uniqueReviews)
            ];
    
            $this->apiManager->batchUpdateReviews(json_encode($reviewsToUpdate));
        }
    }

    /**
     * Update review for global attributes
     *
     * @param array $textTypes
     * @param int $productId
     *
     * @return void
     */
    public function updateReviewForGlobalAttributes($textTypes, $productId)
    {
        $mappingSettings = $this->dataHelper->getMappingSettings();

        $globalTextTypes = [];
        foreach ($textTypes as $textType) {
            $fieldTextType = $this->fieldsHelper->getFieldTextType($textType);

            if (!isset($mappingSettings[$fieldTextType])) {
                continue;
            }

            $attributeCode = $mappingSettings[$fieldTextType];
            $attribute = $this->attributeFactory->create();
            $attribute->loadByCode(\Magento\Catalog\Model\Product::ENTITY, $attributeCode);

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

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

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

    /**
     * Get store ids
     *
     * @return array
     */
    public 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 $productId
     * @param array $products
     * @param array $selectedStores
     *
     * @return void
     */
    public function updateFieldsUsingDefaultValue(
        $textTypes,
        $productId,
        $products,
        $selectedStores
    ) {
        $mappingSettings = $this->dataHelper->getMappingSettings();

        foreach ($textTypes as $textType) {
            $fieldTextType = $this->fieldsHelper->getFieldTextType($textType);

            if (!isset($mappingSettings[$fieldTextType])) {
                continue;
            }
            
            $attributeCode = $mappingSettings[$fieldTextType];
            $attribute = $this->attributeFactory->create();
            $attribute->loadByCode(\Magento\Catalog\Model\Product::ENTITY, $attributeCode);

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

            $storeIds = $this->getStoreIds();
            try {
                foreach ($storeIds as $storeId) {
                    if (!empty($products) && isset($products[$storeId])) {
                        $product = $products[$storeId];
                    } else {
                        $product = $this->productHelper->getProduct($productId, $storeId);
                    }
                    $isUsingDefault = $this->fieldsHelper->isUsingDefaultValues($product, $storeId, $attributeCode);
                    if ($isUsingDefault) {
                        $this->getReviewsToUpdate([$textType], $productId, [$storeId]);
                    } else {
                        if (in_array($storeId, $selectedStores)) {
                            $this->getReviewsToUpdate([$textType], $productId, [$storeId]);
                        }
                    }
                }
            } catch (\Exception $e) {
                continue;
            }
        }
    }

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

        foreach ($selectedStores as $storeId) {
            if (!isset($this->reviewStatuses[$storeId])) {
                $reviewStatuses = $this->generatedText->getReviewStatus($productId, $storeId);
                $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" => $productId,
                    "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;
            }
        }
    }
}
