<?php
/**
 * Copyright © 2016 Filoblu S.r.l. All rights reserved.
 */

namespace FiloBlu\Esb\Model\Rest;

use FiloBlu\Esb\Helper\LoggerProvider;
use FiloBlu\Esb\Model\Order\OrderWriteLock;
use FiloBlu\Esb\Helper\SerializerHelper;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Phrase;
use FiloBlu\Esb\Api\AcknowledgeManagementInterface;
use FiloBlu\Esb\Api\Data\AcknowledgeInterface;
use Magento\Framework\Exception\NotFoundException;
use Magento\Framework\Exception\ConfigurationMismatchException;
use Magento\Sales\Model\OrderRepository;
use Monolog\Logger;

/**
 * REST Api to save acknowledgedata
 */
class AcknowledgeManagement implements AcknowledgeManagementInterface {
	
    /**
     * @var OrderRepository
     */ 	
    protected $_orderRepository;
   
    /**
     * @var ScopeConfigInterface
     */  
    protected $_scopeConfig;

    /**
     * @var Logger
     */ 
    protected $_logger;
    
    /** 
     * @var SerializerHelper
     */
    protected $_serializer;

    /**
     * @var OrderWriteLock
     */
    protected $_orderWriteLock;
    /**
     * @var SearchCriteriaBuilder
     */
    private $_searchCriteriaBuilder;

    /**
     * AcknowledgeManagement constructor.
     * @param ScopeConfigInterface $scopeConfig
     * @param OrderRepository $orderRepository
     * @param SearchCriteriaBuilder $searchCriteriaBuilder
     * @param LoggerProvider $loggerProvider
     * @param SerializerHelper $serializer
     * @param OrderWriteLock $orderWriteLock
     */
    public function __construct(
            ScopeConfigInterface $scopeConfig,
            OrderRepository $orderRepository,
            SearchCriteriaBuilder $searchCriteriaBuilder,
            LoggerProvider $loggerProvider,
            SerializerHelper $serializer,
            OrderWriteLock $orderWriteLock
    ){
        $this->_scopeConfig = $scopeConfig;
        $this->_orderRepository = $orderRepository;
        $this->_searchCriteriaBuilder = $searchCriteriaBuilder;   
        $this->_logger = $loggerProvider->getLogger();
        $this->_serializer = $serializer;
        $this->_orderWriteLock = $orderWriteLock;
    }

    /**
     * Save Acknowledge data.
     *
     * @param AcknowledgeInterface $ack_data
     * @return string
     * @throws NotFoundException
     * @throws ConfigurationMismatchException
     * @throws NotFoundException
     */
     public function save(AcknowledgeInterface $ack_data){
        $orderIncrementId=$ack_data->getOrderIncrementId();

        // Talend chiama questo endpoint e /V1/externalinvoice/save in parallelo sullo stesso
        // ordine e non puo' serializzarle a monte: senza lock i due save si sovrascrivono a
        // vicenda, perche' OrderRepository::save() riscrive tutta la riga sales_order.
        return $this->_orderWriteLock->execute($orderIncrementId, function () use ($ack_data, $orderIncrementId) {
            return $this->applyAcknowledge($ack_data, $orderIncrementId);
        });
    }

    /**
     * Carica l'ordine, ne aggiorna lo status secondo il mapping esb/ack/flows e lo salva.
     *
     * Va invocato SEMPRE dentro OrderWriteLock::execute().
     *
     * @param AcknowledgeInterface $ack_data
     * @param string $orderIncrementId
     * @return string
     * @throws NotFoundException
     * @throws ConfigurationMismatchException
     */
    private function applyAcknowledge(AcknowledgeInterface $ack_data, $orderIncrementId){
        $searchCriteria = $this->_searchCriteriaBuilder
            ->addFilter('increment_id', $orderIncrementId, 'eq')->create();
        $orderList = $this->_orderRepository->getList($searchCriteria);
        if(count($orderList)<>1){
            $message=__('Cannot find order %1', $orderIncrementId);
            throw new NotFoundException(new Phrase($message->render()));
        }
        $order=$orderList->getFirstItem();
        $ack_flow=$ack_data->getFlow();
        $config_flows=$this->_serializer->unserialize($this->_scopeConfig->getValue(
            'esb/ack/flows', 
            \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
            $order->getStoreId()
        )); 
        $status=false;
        foreach($config_flows as $config_flow){
            if($config_flow['ack_flow']==$ack_flow){
                $status=$config_flow['ack_set_status'];
                break;
            }
        }
        if($status!==false){
            $message=$ack_data->getMessage();
            if($ack_data->getDescription()){
                $message.= '<br>' .$ack_data->getDescription();
            }
            $order->addStatusHistoryComment($message, $status);
            $order->save();
            return (string) __('Flow %1. Order %2 successfully updated.', $ack_flow, $order->getIncrementId());
        }else{
            $message=__('Missing configuration for flow %1.', $ack_flow);
            throw new ConfigurationMismatchException(new Phrase($message->render()));
        }                     
    }
}


