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

use Aitoc\PreOrders\Model\AttributesManagement;
use Aitoc\PreOrders\Model\OrderItemPreOrderSettingsRepository;
use Aitoc\PreOrders\Model\ResourceModel\OrderItemPreOrderSettings\CollectionFactory as OrderItemPreOrderSettingsCollectionFactory;
use Magento\CatalogInventory\Model\StockRegistry;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\Helper\Context;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Phrase;
use Magento\Framework\Stdlib\DateTime;
use Magento\Quote\Model\Quote\Item as QuoteItem;
use Magento\Sales\Model\ResourceModel\Order\Item\CollectionFactory as OrderItemCollectionFactory;
use Magento\Sales\Model\Order\ItemRepository as OrderItemRepository;

/**
 * Helper For Pre-Order functionality
 */
class PreOrder extends AbstractHelper
{
    /**
     * @var AttributesManagement
     */
    private $attributesManagement;

    /**
     * @var DateTime
     */
    private $dateTime;

    /**
     * @var OrderItemCollectionFactory
     */
    private $orderItemCollectionFactory;

    /**
     * @var OrderItemRepository
     */
    private $orderItemRepository;

    /**
     * @var OrderItemPreOrderSettingsRepository
     */
    private $orderItemPreOrderSettingsRepository;

    /**
     * @var OrderItemPreOrderSettingsCollectionFactory
     */
    private $orderItemPreOrderSettingsCollectionFactory;

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

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

    /**
     * @param Context $context
     * @param AttributesManagement $attributesManagement
     * @param DateTime $dateTime
     * @param OrderItemCollectionFactory $orderItemCollectionFactory
     * @param OrderItemRepository $orderItemRepository
     * @param OrderItemPreOrderSettingsRepository $orderItemPreOrderSettingsRepository
     * @param OrderItemPreOrderSettingsCollectionFactory $orderItemPreOrderSettingsCollectionFactory
     * @param StockRegistry $stockRegistry
     * @param Settings $settingsHelper
     */
    public function __construct(
        Context $context,
        AttributesManagement $attributesManagement,
        DateTime $dateTime,
        OrderItemCollectionFactory $orderItemCollectionFactory,
        OrderItemRepository $orderItemRepository,
        OrderItemPreOrderSettingsRepository $orderItemPreOrderSettingsRepository,
        OrderItemPreOrderSettingsCollectionFactory $orderItemPreOrderSettingsCollectionFactory,
        StockRegistry $stockRegistry,
        Settings $settingsHelper
    ) {
        $this->attributesManagement = $attributesManagement;
        $this->dateTime = $dateTime;
        $this->orderItemCollectionFactory = $orderItemCollectionFactory;
        $this->orderItemRepository = $orderItemRepository;
        $this->orderItemPreOrderSettingsRepository = $orderItemPreOrderSettingsRepository;
        $this->orderItemPreOrderSettingsCollectionFactory = $orderItemPreOrderSettingsCollectionFactory;
        $this->stockRegistry = $stockRegistry;
        $this->settingsHelper = $settingsHelper;
        parent::__construct($context);
    }

    /**
     * @param int $productId
     * @param int $storeId
     * @return array|mixed
     * @throws LocalizedException
     */
    public function getPreOrderSettingsByProductId($productId, $storeId = 0)
    {
        $preOrderSettings = $this->attributesManagement->getAttributesByProduct($productId, $storeId);
        return $preOrderSettings;
    }

    /**
     * @param int $productId
     * @param int $storeId
     * @return bool
     * @throws LocalizedException
     */
    public function isProductPreOrder($productId, $storeId = 0)
    {
        $settings = $this->getPreOrderSettingsByProductId($productId, $storeId);
        $stockItem = $this->stockRegistry->getStockItem($productId, $storeId);
        $qty = $stockItem->getQty();

        if ($settings &&
            $settings['pre_order_status'] == 1 &&
            ($settings['out_of_stock_qty'] === '' || $settings['out_of_stock_qty'] < $qty) &&
            $settings['pre_order_qty'] >= $qty
        ) {
            return true;
        }
        return false;
    }


    /**
     * @param int $productId
     * @param int $storeId
     * @return bool
     * @throws LocalizedException
     */
    public function isProductOutOfStockPreOrder($productId, $storeId = 0)
    {
        $settings = $this->getPreOrderSettingsByProductId($productId, $storeId);
        $stockItem = $this->stockRegistry->getStockItem($productId, $storeId);
        $qty = $stockItem->getQty();

        if ($settings &&
            $settings['pre_order_status'] == 1 &&
            $settings['out_of_stock_qty'] !== '' &&
            $settings['out_of_stock_qty'] >= $qty
        ) {
            return true;
        }
        return false;
    }

    /**
     * @param $quoteItem
     * @return bool
     * @throws LocalizedException
     */
    public function isQuoteItemPreOrder(QuoteItem $quoteItem)
    {
        $isPreOrder = false;
        switch ($quoteItem->getProductType()) {
            case 'bundle':
                foreach ($quoteItem->getChildren() as $child) {
                    $productId = $child->getProductId();
                    $isPreOrder = $this->isProductPreOrder($productId);
                    if ($isPreOrder) {
                        break;
                    }
                }
                break;

            case 'configurable':
                $option = $quoteItem->getOptionByCode('simple_product');
                $productId = $option->getProductId();
                $isPreOrder = $this->isProductPreOrder($productId);
                break;

            default:
                $productId = $quoteItem->getProductId();
                $isPreOrder = $this->isProductPreOrder($productId);
                break;
        }

        return $isPreOrder;
    }

    /**
     * @param int $orderId
     * @return bool
     */
    public function isOrderContainsPreOrderProducts($orderId)
    {
        $orderItemIds = $this->orderItemCollectionFactory->create()
            ->addFieldToFilter('order_id', $orderId)
            ->getAllIds();
        $orderItemPreOrderSettingsCollection = $this->orderItemPreOrderSettingsCollectionFactory->create();
        $preOrdersCount = $orderItemPreOrderSettingsCollection
            ->addFieldToFilter('order_item_id', ['in' => $orderItemIds])
            ->addFieldToFilter('is_pre_order', '1')
            ->getSize();

        return (bool)$preOrdersCount;
    }

    /**
     * @param int $orderItemId
     * @return bool
     */
    public function isOrderItemOnPreOrderState($orderItemId)
    {
        try {
            $orderItemPreOrderSettings = $this->orderItemPreOrderSettingsRepository->getByOrderItemId($orderItemId);
            return (bool)$orderItemPreOrderSettings->getIsPreOrder();
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * @param int $orderItemId
     * @return bool
     */
    public function isOrderItemCanBeShipped($orderItem, $orderItemId)
    {
        $isOrderItemPreOrdered = $this->isOrderItemOnPreOrderState($orderItemId);
        if (!$isOrderItemPreOrdered) {
            return true;
        } else {
            try {
                if (!empty($childrenItems = $orderItem->getChildrenItems())) {
                    $child = reset($childrenItems);
                    $productId = $child->getProductId();
                } else {
                    $productId = $orderItem->getProductId();
                }
                $isProductPreOrder = $this->isProductPreOrder($productId);
                return (!$isProductPreOrder);
            } catch (\Exception $e) {
                return true;
            }
        }
    }

    /**
     * @param int $productId
     * @param int $storeId
     * @return Phrase
     * @throws LocalizedException
     */
    public function getPreOrderStatusLabelByProductId($productId, $storeId = 0)
    {
        $settings = $this->getPreOrderSettingsByProductId($productId, $storeId);
        $result = __('Pre-Order');
        if (
            ($inStockDate = $settings['in_stock_date']) &&
            $this->settingsHelper->getChangeToInStockByDateSetting() == 1
        ) {
            $inStockDate = $this->dateTime->formatDate($inStockDate, false);
            $result = __("Arrival " . $inStockDate);
        } elseif ($preOrderNote = $settings['pre_order_note']) {
            $result = __($preOrderNote);
        }
        return $result;
    }

    /**
     * @param     $productId
     * @param     $qty
     * @param int $storeId
     *
     * @return bool
     * @throws LocalizedException
     */
    public function isQtyAvailable($productId, $qty, $storeId = 0) {
        $settings = $this->getPreOrderSettingsByProductId($productId, $storeId);
        $stockItem = $this->stockRegistry->getStockItem($productId, $storeId);
        $currentQty = $stockItem->getQty();

        if ($settings['pre_order_status'] == 1) {
            $preOrderQty = $settings['pre_order_qty'];
            $outOfStockQty = $settings['out_of_stock_qty'];
            $deltaQty = $currentQty - $qty;
            if ($currentQty > $preOrderQty && $preOrderQty !== '') {
                return $deltaQty >= (float)$preOrderQty;
            } elseif ($outOfStockQty !== ''){
                return $deltaQty >= (float)$outOfStockQty;
            } else {
                return true;
            }
        }
        return $currentQty >= $qty;
    }
}
