<?php
/**
 * Save quote at customer end.
 *
 * @category  Magetop Extensions
 * @package   Magetop_Quotesystem
 * @author    Magetop Developer
 * @copyright Copyright (c) Magetop (https://www.magetop.com)
 * @license   https://www.magetop.com/license.html
 */

namespace Magetop\Quotesystem\Controller\Buyerquote;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\RequestInterface;
use Magento\Catalog\Model\ProductFactory;
use Magetop\Quotesystem\Helper;
use Magento\MediaStorage\Model\File\UploaderFactory;
use Magento\Customer\Model\Url;
use Magetop\Quotesystem\Api\QuoteRepositoryInterface;
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;

class Savequote extends \Magento\Framework\App\Action\Action
{
    /**
     * @var \Magento\Customer\Model\Session
     */
    protected $_customerSession;

    /**
     * @var \Magento\Catalog\Model\Product
     */
    protected $_catalogProduct;

    /**
     * @var \Magento\Framework\Json\Helper\Data
     */
    protected $_jsonHelper;

    /**
     * @var \Magetop\Quotesystem\Model\QuotesFactory
     */
    protected $_quoteFactory;

    /**
     * @var \Magetop\Quotesystem\Helper\Mail
     */
    protected $_mailHelper;

    /**
     * @var \Magetop\Quotesystem\Helper\Data
     */
    protected $_helper;

    /**
     * @var Magetop\Quotesystem\Api\QuoteRepositoryInterface
     */
    protected $_quoteRepository;

    /**
     * @var \Magento\Framework\Stdlib\DateTime\DateTime
     */
    protected $_date;

    /**
     * @var TimezoneInterface
     */
    protected $_timezoneinterface;

    /**
     * @var Magento\Framework\Session\SessionManager
     */
    private $_session;

    /**
     * @var [StockItemRepository]
     */
    private $_stockItemRepository;

    /**
     * @var [Configurable]
     */
    private $_configurableProduct;

    /**
     * Constructor
     *
     * @param Context                                                   $context
     * @param ProductFactory                                            $catalogProduct
     * @param \Magento\Customer\Model\Session                           $customerSession
     * @param \Magento\Framework\Json\Helper\Data                       $jsonHelper
     * @param \Magetop\Quotesystem\Model\QuotesFactory                   $quotes
     * @param \Magetop\Quotesystem\Model\QuoteDetailsFactory             $quoteDetails
     * @param Helper\Mail                                               $helperMail
     * @param Helper\Data                                               $helper
     * @param QuoteRepositoryInterface                                  $quoteRepository
     * @param \Magento\Framework\Stdlib\DateTime\DateTime               $date
     * @param TimezoneInterface                                         $timezoneinterface
     * @param \Magento\CatalogInventory\Model\Stock\StockItemRepository $stockItemRepository
     * @param Configurable                                              $configurableProduct
     * @param \Magento\Store\Model\StoreManagerInterface                $storeManager
     */
    public function __construct(
        Context $context,
        ProductFactory $catalogProduct,
        \Magento\Customer\Model\Session $customerSession,
        \Magento\Framework\Json\Helper\Data $jsonHelper,
        \Magetop\Quotesystem\Model\QuotesFactory $quotes,
        \Magetop\Quotesystem\Model\QuoteDetailsFactory $quoteDetails,
        Helper\Mail $helperMail,
        Helper\Data $helper,
        QuoteRepositoryInterface $quoteRepository,
        \Magento\Framework\Stdlib\DateTime\DateTime $date,
        TimezoneInterface $timezoneinterface,
        \Magento\CatalogInventory\Model\Stock\StockItemRepository $stockItemRepository,
        Configurable $configurableProduct,
        \Magento\Store\Model\StoreManagerInterface $storeManager
    ) {
        $this->_customerSession = $customerSession;
        $this->_catalogProduct = $catalogProduct;
        $this->_quoteFactory = $quotes;
        $this->_quoteDetailsFactory = $quoteDetails;
        $this->_jsonHelper = $jsonHelper;
        $this->_mailHelper = $helperMail;
        $this->_helper = $helper;
        $this->_date = $date;
        $this->_timezoneinterface = $timezoneinterface;
        $this->_quoteRepository = $quoteRepository;
        $this->_stockItemRepository = $stockItemRepository;
        $this->_configurableProduct = $configurableProduct;
        $this->_storeManager = $storeManager;
        parent::__construct($context);
    }

    /**
     * Save quote from buyer.
     *
     * @return \Magento\Framework\View\Result\Page
     */
    public function execute()
    {
        $result = [];
        if (!$this->getRequest()->isPost() || !$this->_customerSession->isLoggedIn()) {
            $redirectUrl = $this->_url->getUrl('quotesystem/buyerquote/index/');
            $this->messageManager->addError(
                __(
                    "Sorry some error occured!!!"
                )
            );
            return $this->goBack($redirectUrl);
        }
        $paramsData = $this->getRequest()->getParams();
        if (!is_array($paramsData)) {
            $this->messageManager->addError(
                __("Sorry!! Quote can't be saved.")
            );
            return $this->goBack($paramsData['current_url']);
        }
        $errors = $this->validateData($paramsData);
        if (empty($errors)) {
            $productId = $this->productIdByProductType($paramsData);
            $product = $this->_catalogProduct->create()->load($productId);
            $productQty = $this->selectedProductQty($product, $paramsData);
            $mainProductId = 0;
            if ($productId != $paramsData['product']) {
                $mainProductId = $paramsData['product'];
            }
            
            if ($this->_helper->isAllowAddOutOfStockProduct() == 0) {
                if ($productQty==0 && $product->getTypeId() != 'downloadable') {
                    $this->messageManager
                        ->addError(__("Sorry!! Quantity of this product in stock is zero."));
                    return $this->goBack($paramsData['current_url']);
                }
            }
            $finalPrice = $this->getProductPrice($paramsData, $product);
            $productOptions = [];
            $fileNames = [];
            $lastQuoteId = 0;
            $bundleOption = [];
            $request = new \Magento\Framework\DataObject($paramsData);
            $cartCandidates = $product->getTypeInstance()->prepareForCartAdvanced(
                $request,
                $product
            );
            if ($product->getTypeId() !== 'bundle') {
                if (is_string($cartCandidates) || $cartCandidates instanceof \Magento\Framework\Phrase) {
                    $result['error'] = 1;
                    $result['message'] = (string)__($cartCandidates);
                    $result['backUrl'] = $paramsData['current_url'];
                    $this->messageManager->addError(
                        $result['message']
                    );
                    return $this->goBack($paramsData['current_url']);
                }
            }
            
            if ($mainProductId != 0) {
                
                $mainProduct = $this->_helper->getProduct($mainProductId);
                $quoteMinimumQty = $mainProduct->getMinQuoteQty();
            } else {

                $quoteMinimumQty = $product->getMinQuoteQty();
            }
            // get config quote qty
            if (!$quoteMinimumQty) {
                $quoteMinimumQty = $this->_helper->getConfigMinQty();
            }
            if ($quoteMinimumQty <= $paramsData['quote_qty']) {
                $bundleOption = $this->setBundleOption($paramsData, $product);
                $paramsData['bundle_option_to_calculate'] = $bundleOption;
                $productOptions = $this->setProductOption($paramsData);
                $paramsData['quote_description'] = trim($paramsData['quote_description']);
                $paramsData['quote_description'] = strip_tags($paramsData['quote_description']);
                $attachments = '';
                if (isset($paramsData['attachments']) && is_array($paramsData['attachments'])) {
                    $attachments = implode(',', $paramsData['attachments']);
                }
                $quotePrice = $this->_helper->getBaseCurrencyPrice($paramsData['quote_price']);
                $customerId = $this->_customerSession->getCustomerId();
                $currentStoreId = $this->_storeManager->getStore()->getId();
                $quoteDetailsColl = $this->_quoteDetailsFactory->create()->getCollection()
                                                    ->addFieldToFilter('customer_id', $customerId)
                                                    ->addFieldToFilter('is_active', 1);
                if ($quoteDetailsColl->getSize()) {
                    $quoteId = $quoteDetailsColl->getFirstItem()->getId();
                } else {
                    $currentWebsiteId = $this->_storeManager->getStore()->getWebsiteId();
                    $quoteDetails = $this->_quoteDetailsFactory->create()
                        ->setCustomerId($customerId)
                        ->setCreatedAt(time())
                        ->setWebsitesId($currentWebsiteId)
                        ->setStoreId($currentStoreId)
                        ->setIsActive(1);
                    $quoteId = $quoteDetails->save()->getId();
                    
                }

                $quote = $this->_quoteFactory->create()
                    ->setProductId($paramsData['product'])
                    ->setProductName($product->getName())
                    ->setProductPrice($finalPrice)
                    ->setProductOption($this->_helper->convertStringAccToVersion($productOptions, 'encode'))
                    ->setCustomerId($customerId)
                    ->setQuoteQty($paramsData['quote_qty'])
                    ->setQuotePrice($paramsData['quote_price'])
                    ->setInitialQuotePrice($paramsData['quote_price'])
                    ->setQuoteDesc($paramsData['quote_description'])
                    ->setStatus(\Magetop\Quotesystem\Model\Quotes::STATUS_UNAPPROVED)//set pending status
                    ->setCreatedAt(time())
                    ->setAttachments($attachments)
                    ->setQuoteCurrency($this->_helper->getCurrentCurrency())
                    ->setQuoteId($quoteId);
                if (isset($paramsData['links'])) {
                    $quote->setLinks($this->_helper->convertStringAccToVersion($paramsData['links'], 'encode'));
                }
                if (isset($bundleOption)) {
                    $quote->setBundleOption($this->_helper->convertStringAccToVersion($bundleOption, 'encode'));
                }
                if (isset($paramsData['super_attribute'])) {
                    $quote->setSuperAttribute(
                        $this->_helper->convertStringAccToVersion($paramsData['super_attribute'], 'encode')
                    );
                }
                $lastQuoteId = $quote->save()->getEntityId();

                $this->_customerSession->setQuoteId($lastQuoteId);
                $cartCandidates = $product->getTypeInstance()->prepareForCartAdvanced(
                    $request,
                    $product
                );
                // send mail
                // $this->_mailHelper->newQuote($lastQuoteId);
                $this->messageManager
                    ->addSuccess(__("You added ".$product->getName()." to your quote cart"));
                return $this->goBack($paramsData['current_url']);
            } else {
                $this->messageManager
                    ->addError(__("Sorry you are not allowed to quote such a low quantity"));
                return $this->goBack($paramsData['current_url']);
            }
        } else {
            foreach ($errors as $message) {
                $this->messageManager->addError($message);
            }
            if (!array_key_exists('current_url', $paramsData)) {
                return $this->goBack('');
            }
            return $this->goBack($paramsData['current_url']);
        }
    }

    /**
     * Get ProductPrice According to SpecialPrice, TierPrice and Custom Option.
     *
     * @param array  $paramsData
     * @param object $product
     * @return price
     */
    public function getProductPrice($paramsData, $product)
    {
        if (array_key_exists('bundle_option', $paramsData) && $paramsData['bundle_option']) {
            $bundleOption = $this->setBundleOption($paramsData, $product);
            $paramsData['bundle_option_to_calculate'] = $bundleOption;
        }
        $productPrice = $this->_helper->calculateProductPrice(
            $paramsData
        );
        return($productPrice);
    }

    /**
     * SetProductOption
     *
     * @param  array $paramsData
     * @return mixed
     */
    protected function setProductOption($paramsData)
    {
        if (isset($paramsData['options'])) {
            foreach ($paramsData['options'] as $key => $value) {
                if (empty($value)) {
                    unset($paramsData['options'][$key]);
                }
            }
            return $paramsData['options'];
        }
    }

    /**
     * SetBundleOption
     *
     * @param  array                          $paramsData
     * @param  \Magento\Catalog\Model\Product $product
     * @return array
     */
    protected function setBundleOption($paramsData, $product)
    {
        if (isset($paramsData['bundle_option'])) {
            $bundleOption = $this->getBundleProductData($paramsData, $product);
            return $bundleOption;
        }
    }

    /**
     * ProductIdByProductType
     *
     * @param  array $params
     * @return mixed
     */
    protected function productIdByProductType($params)
    {
        if (array_key_exists('selected_configurable_option', $params) &&
        $params['selected_configurable_option'] != "") {
            return $params['selected_configurable_option'];
        } elseif (array_key_exists('super_attribute', $params) && $params['super_attribute'] != "") {
            $product = $this->_catalogProduct->create()->load($params['product']);
            return $this->_configurableProduct
                ->getProductByAttributes(
                    $params['super_attribute'],
                    $product
                )->getId();
        } else {
            if (array_key_exists('product', $params) && $params['product'] != "") {
                return $params['product'];
            }
        }
    }

    /**
     * Return $result with back url in json format.
     *
     * @param [type] $backUrl
     * @return \Magento\Framework\Json\Helper\Data
     */
    protected function goBack($backUrl = null)
    {
        $redirectUrl = '';
        if (!$this->getRequest()->isAjax()) {
            $redirectUrl = $this->_url->getUrl('customer/account');
            if ($backUrl || $backUrl = $redirectUrl) {
                $resultRedirect = $this->resultRedirectFactory->create();
                $resultRedirect->setUrl($backUrl);
                return $resultRedirect;
            }
        }
        $result = [];
        if ($backUrl || $backUrl = $redirectUrl) {
            $result['backUrl'] = $backUrl;
        }
        $this->getResponse()->representJson(
            $this->_jsonHelper->jsonEncode($result)
        );
    }

    /**
     * Validates quote's data added by customer.
     *
     * @param array $paramData
     * @return bool
     */
    public function validateData(&$paramData)
    {
        $errors = [];
        $data = [];
        foreach ($paramData as $code => $value) {
            switch ($code) {
                case 'quote_qty':
                    $validator = new \Zend_Validate_Int();
                    if (!$validator->isValid($value)) {
                        $errors[] = __('Quote Quantity can contain only integer value');
                    } else {
                        $value = preg_replace("/<script.*?\/script>/s", "", $value) ? : $value;
                        $paramData[$code] = $value;
                    }
                    break;
                case 'quote_price':
                    $validator = new \Zend_Validate_Float();
                    if (!$validator->isValid($value)) {
                        $errors[] = __('Quote Price can contain only decimal or integer value');
                    } else {
                        $value = preg_replace("/<script.*?\/script>/s", "", $value) ? : $value;
                        $paramData[$code] = $value;
                    }
                    break;
                case 'quote_description':
                    if (trim($value) == '') {
                        $errors[] = __('Please enter the quote description');
                    } else {
                        $value = preg_replace("/<script.*?\/script>/s", "", $value) ? : $value;
                        $paramData[$code] = $value;
                    }
                    break;
            }
        }

        return $errors;
    }

    /**
     * GetBundleProductData
     *
     * @param  array                          $params
     * @param  \Magento\Catalog\Model\Product $product
     * @return array
     */
    public function getBundleProductData($params, $product)
    {
        $bundleOption = [];
        if (array_key_exists('bundle_option', $params)) {
            $bundleOption['bundle_option'] = $params['bundle_option'];
        }
        if ($product->getEntityId() && $product->getTypeId() == 'bundle') {
            $selectionCollection = $product
                ->getTypeInstance(true)
                ->getSelectionsCollection(
                    $product->getTypeInstance(true)->getOptionsIds($product),
                    $product
                );
            foreach ($bundleOption['bundle_option'] as $optionkey => $optionValue) {
                foreach ($selectionCollection as $selectionValue) {
                    $selectedOption = $selectionValue->getOptionId();
                    $selectionId = $selectionValue->getSelectionId();
                    $selectionQty = $selectionValue->getSelectionQty();
                    if ($selectedOption == $optionkey && $selectionId == $optionValue) {
                        if (array_key_exists('bundle_option_qty', $params) &&
                        isset($params['bundle_option_qty']) &&
                        array_key_exists($optionkey, $params['bundle_option_qty'])) {
                            $bundleOption['bundle_option_qty'][$optionkey] = $params['bundle_option_qty'][$optionkey];
                        } else {
                            $bundleOption['bundle_option_qty'][$optionkey] = $selectionQty;
                        }
                        $bundleOption['bundle_option_price'][$optionkey] = $selectionValue->getPrice();
                        $bundleOption['bundle_option_product'][$optionkey] = $selectionValue->getEntityId();
                    }
                }
            }
        }
        return $bundleOption;
    }

    /**
     * SelectedProductQty
     *
     * @param  \Magento\Catalog\Model\Product $product
     * @param  array                          $params
     * @return int
     */
    public function selectedProductQty($product, $params)
    {
        if (isset($params['bundle_option']) && $params['bundle_option']) {
            $bundleOption = $this->setBundleOption($params, $product);
            $quantity = $this->_helper->getBundleProductQuatity(
                $product,
                $bundleOption
            );
            return $quantity;
        }
        if (isset($params['links'])) {
            $quantity = $params['quote_qty'];
            return $quantity;
        }
        $quantity = $product->getQuantityAndStockStatus()['qty'];
        return $quantity;
    }
}
