<?php
/**
 * @author Aitoc Team
 * @copyright Copyright (c) 2020 Aitoc (https://www.aitoc.com)
 * @package Aitoc_PreOrders
 */

/**
 * Copyright © 2018 Aitoc. All rights reserved.
 * Developed by Alex Yakimovich
 */

namespace Aitoc\PreOrders\Cron;

use Aitoc\PreOrders\Api\Data\ProductAttributesInterface;
use Aitoc\PreOrders\Model\NotificationManagement;
use Magento\Store\Model\StoreManagerInterface;
use Aitoc\PreOrders\Model\ProductAttributesRepository;
use Aitoc\PreOrders\Model\AttributesManagement;
use Aitoc\PreOrders\Helper\Settings as SettingsHelper;
use Magento\CatalogInventory\Api\Data\StockItemInterface;
use Magento\CatalogInventory\Api\StockRegistryInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\MailException;
use Magento\Framework\Exception\NoSuchEntityException;

class ReturnToStock
{
    /**
     * @var NotificationManagement
     */
    private $notificationManagement;

    /**
     * @var ProductAttributesRepository
     */
    private $productAttributesRepository;

    /**
     * @var array
     */
    private $productStocks = [];

    /**
     * @var SearchCriteriaBuilder
     */
    private $searchCriteriaBuilder;

    /**
     * @var StockRegistryInterface
     */
    private $stockRegistry;

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

    /**
     * @var AttributesManagement
     */
    private $attributesManagement;

    /**
     * @var SettingsHelper
     */
    private $settingsHelper;

    /**
     * @param NotificationManagement $notificationManagement
     * @param ProductAttributesRepository $productAttributesRepository
     * @param SearchCriteriaBuilder $searchCriteriaBuilder
     * @param StockRegistryInterface $stockRegistry
     * @param StoreManagerInterface $storeManager
     * @param AttributesManagement $attributesManagement
     */
    public function __construct(
        NotificationManagement $notificationManagement,
        ProductAttributesRepository $productAttributesRepository,
        SearchCriteriaBuilder $searchCriteriaBuilder,
        StockRegistryInterface $stockRegistry,
        StoreManagerInterface $storeManager,
        AttributesManagement $attributesManagement,
        SettingsHelper $settingsHelper
    ) {
        $this->notificationManagement = $notificationManagement;
        $this->productAttributesRepository = $productAttributesRepository;
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
        $this->stockRegistry = $stockRegistry;
        $this->storeManager = $storeManager;
        $this->attributesManagement = $attributesManagement;
        $this->settingsHelper = $settingsHelper;
    }

    /**
     * Return products to stock by date
     *
     * @throws CouldNotSaveException
     * @throws LocalizedException
     * @throws MailException
     * @throws NoSuchEntityException
     */
    public function execute()
    {
        if ($this->settingsHelper->getChangeToInStockByDateSetting()) {
            $stores = $this->storeManager->getStores(true);
            $currentDate = date('Y-m-d');
            foreach ($stores as $store) {
                $storeId = $store->getId();
                $searchCriteria = $this->searchCriteriaBuilder
                    ->addFilter(ProductAttributesInterface::ATTRIBUTE_CODE, 'in_stock_date')
                    ->addFilter(ProductAttributesInterface::VALUE, $currentDate, 'lteq')
                    ->addFilter(ProductAttributesInterface::STORE_ID, $storeId)
                    ->create();

                $list = $this->productAttributesRepository->getList($searchCriteria)->getItems();

                $productIds = [];
                foreach ($list as $item) {
                    $productIds[] = $item->getProductId();
                }

                $searchCriteria = $this->searchCriteriaBuilder
                    ->addFilter(ProductAttributesInterface::ATTRIBUTE_CODE, 'pre_order_status')
                    ->addFilter(ProductAttributesInterface::VALUE, '1')
                    ->addFilter(ProductAttributesInterface::STORE_ID, $storeId)
                    ->addFilter(ProductAttributesInterface::PRODUCT_ID, $productIds, 'in')
                    ->create();
                $list = $this->productAttributesRepository->getList($searchCriteria)->getItems();

                foreach ($list as $item) {
                    $productId = $item->getProductId();
                    $productStockItem = $this->getProductStockInfo($productId);
                    if ($productStockItem->getQty() > 0) {
                        if (!$productStockItem->getIsInStock()) {
                            $productStockItem->setIsInStock(1);
                            $productStockItem->save();
                        }
                        $this->processSuccess($productId, $storeId);
                    } else {
                        $this->processError($productId);
                    }
                }
            }
        }
    }

    /**
     * @param int $productId
     * @return StockItemInterface
     * @throws NoSuchEntityException
     */
    private function getProductStockInfo($productId)
    {
        if (!array_key_exists($productId, $this->productStocks)) {
            $this->productStocks[$productId] = $this->stockRegistry->getStockItem($productId);
        }
        return $this->productStocks[$productId];
    }

    /**
     * @param int $productId
     * @param int $storeId
     * @throws LocalizedException
     */
    private function processSuccess($productId, $storeId)
    {
        $this->attributesManagement->saveAttributeValue($productId, 'pre_order_status', '0', $storeId);
        $this->attributesManagement->saveAttributeValue($productId, 'in_stock_date', '', $storeId);
    }

    /**
     * @param int $productId
     * @throws LocalizedException
     * @throws MailException
     */
    private function processError($productId)
    {
        $this->notificationManagement->sendReturnToStockFailureNotification($productId);
    }
}
