<?php


namespace FiloBlu\Storelocator\Model\PickUpInStore;

use Exception;
use FiloBlu\Storelocator\Api\PickUpInStoreManagementInterface;
use FiloBlu\Storelocator\Helper\Data;
use Magento\Framework\App\Area;
use Magento\Framework\Event\ManagerInterface;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Mail\Template\TransportBuilder;
use Magento\Framework\Stdlib\DateTime\DateTime;
use Magento\Framework\Translate\Inline\StateInterface;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Address\Renderer;
use Magento\Store\Model\StoreManagerInterface;

/**
 * Class PickUpInStoreManagement
 * @package FiloBlu\Storelocator\Model\PickUpInStore
 */
class PickUpInStoreManagement implements PickUpInStoreManagementInterface
{

    /**
     * @var Data
     */
    private $storelocatorHelper;
    /**
     * @var ManagerInterface
     */
    private $eventManager;
    /**
     * @var DateTime
     */
    private $date;
    /**
     * @var TransportBuilder
     */
    private $transportBuilder;
    /**
     * @var StoreManagerInterface
     */
    private $storeManager;
    /**
     * @var StateInterface
     */
    private $inlineTranslation;
    /**
     * @var \Magento\Payment\Helper\Data
     */
    private $paymentHelper;
    /**
     * @var Renderer
     */
    private $addressRenderer;
    /**
     * @var \Psr\Log\LoggerInterface
     */
    private $logger;

    /**
     * PickUpInStoreManagement constructor.
     * @param Data $storelocatorHelper
     * @param ManagerInterface $eventManager
     * @param DateTime $date
     * @param TransportBuilder $transportBuilder
     * @param StoreManagerInterface $storeManager
     * @param StateInterface $inlineTranslation
     * @param \Magento\Payment\Helper\Data $paymentHelper
     * @param Renderer $addressRenderer
     * @param \Psr\Log\LoggerInterface $logger
     */
    public function __construct(
        Data $storelocatorHelper,
        ManagerInterface $eventManager,
        DateTime $date,
        TransportBuilder $transportBuilder,
        StoreManagerInterface $storeManager,
        StateInterface $inlineTranslation,
        \Magento\Payment\Helper\Data $paymentHelper,
        Renderer $addressRenderer,
        \Psr\Log\LoggerInterface $logger
    ) {
        $this->storelocatorHelper = $storelocatorHelper;
        $this->eventManager = $eventManager;
        $this->date = $date;
        $this->transportBuilder = $transportBuilder;
        $this->storeManager = $storeManager;
        $this->inlineTranslation = $inlineTranslation;
        $this->paymentHelper = $paymentHelper;
        $this->addressRenderer = $addressRenderer;
        $this->logger = $logger;
    }

    /**
     * @param string $hash
     * @return bool
     * @throws NoSuchEntityException
     */
    public function checkCompleted(string $hash): bool
    {
        $order = $this->storelocatorHelper->getOrderByHash($hash);
        return $order->getState() === Order::STATE_COMPLETE || $order->getStatus() === 'sent_to_logistics';
    }


    /**
     * @param string $hash
     * @return bool
     * @throws NoSuchEntityException
     */
    public function checkReceived(string $hash): bool
    {
        $order = $this->storelocatorHelper->getOrderByHash($hash);
        return $order->getPickupInStoreConfirmReceivedDate() != null;
    }

    /**
     * @param string $hash
     * @return bool
     * @throws NoSuchEntityException
     */
    public function checkConfirmed(string $hash): bool
    {
        $order = $this->storelocatorHelper->getOrderByHash($hash);
        return $order->getPickupInStoreConfirmDate() != null;
    }

    /**
     * @param string $hash
     * @return void
     * @throws NoSuchEntityException
     * @throws Exception
     */
    public function confirm(string $hash)
    {
        if (!$this->storelocatorHelper->getConfig(self::XML_CONFIG_PICKUP_IN_STORE_ENABLED)) {
            return;
        }

        $order = $this->storelocatorHelper->getOrderByHash($hash);
        $order->setPickupInStoreConfirmDate($this->date->gmtDate());
        $this->storelocatorHelper->saveOrder($order);
        $this->updateOrderConfirmation($order);

        if ($this->storelocatorHelper->getConfig('carriers/pickupinstore/email_after_collect_enabled')) {
            $templateIdentifier = $this->storelocatorHelper->getConfig(
                'carriers/pickupinstore/order_collected_by_customer_template'
            );

            $from = $this->storelocatorHelper->getConfig(
                'carriers/pickupinstore/sender_email_afer_collect_identity'
            );

            $this->sendMail($order, $templateIdentifier, $from);
        }


        $this->eventManager->dispatch(self::EVENT_PICKUP_IN_STORE_CONFIRM, ['order' => $order]);
    }

    /**
     * Update order-status
     * @throws Exception
     */
    public function updateOrderConfirmation($order)
    {
        $order->setState(Order::STATE_COMPLETE);
        $order->setStatus(self::STATUS_COMPLETE_IN_STORE);
        $order->addStatusToHistory($order->getStatus(), 'Pick Up In Store - Order processed successfully with reference: Complete');
        $this->storelocatorHelper->saveOrder($order);
    }

    /**
     * @param string $hash
     * @return void
     * @throws NoSuchEntityException
     * @throws Exception
     */
    public function confirmReceived(string $hash)
    {
        if (!$this->storelocatorHelper->getConfig(self::XML_CONFIG_PICKUP_IN_STORE_ENABLED)) {
            return;
        }

        $order = $this->storelocatorHelper->getOrderByHash($hash);
        $order->setPickupInStoreConfirmReceivedDate($this->date->gmtDate());
        $this->storelocatorHelper->saveOrder($order);
        $this->updateOrderReceived($order);
        // Send mail to customer to inform that the package is available in store.

        if ($this->storelocatorHelper->getConfig('carriers/pickupinstore/email_to_customer_enabled')) {

            $templateIdentifier = $this->storelocatorHelper->getConfig(
                'carriers/pickupinstore/email_to_customer_template'
            );

            $from = $this->storelocatorHelper->getConfig(
                'carriers/pickupinstore/sender_email_to_customer_identity'
            );

            $this->sendMail($order, $templateIdentifier, $from);
        }

        $this->eventManager->dispatch(self::EVENT_PICKUP_IN_STORE_CONFIRM_RECEIVED, ['order' => $order]);
    }

    /**
     * @throws Exception
     */
    public function updateOrderReceived($order)
    {

        $order->setState(Order::STATE_COMPLETE);
        $order->setStatus(self::STATUS_DELIVERED_IN_STORE);
        $order->addStatusToHistory($order->getStatus(), 'Pick Up In Store - The order arrived in the store');
        $this->storelocatorHelper->saveOrder($order);
    }

    /**
     * @param $order
     * @param $templateIdentifier
     * @param $from
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function sendMail($order, $templateIdentifier, $from)
    {

        $this->inlineTranslation->suspend();

        $billingAddress = $order->getBillingAddress();

        $templateVars = [
            'order'                => $order,
            'order_id'             => $order->getId(),
            'order_increment_id'   => $order->getIncrementId(),
            'order_store_id'       => $order->getStoreId(),
            'order_is_virtual'     => (bool)$order->getIsVirtual(),
            'order_is_not_virtual' => !$order->getIsVirtual(),
            'order_pickup_in_store_hash' => $order->getPickupInStoreHash(),
            'order_email_customer_note' => $order->getEmailCustomerNote(),
            'billing'              => $billingAddress,
            'payment_html'         => $this->getPaymentHtml($order),
            'store'                => $order->getStore(),
            'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
            'formattedBillingAddress' => $this->getFormattedBillingAddress($order),
            'order_data'              => [
                'pickup_in_store_hash' => $order->getData('pickup_in_store_hash'),
                'id'                   => $order->getId(),
                'increment_id'         => $order->getIncrementId(),
                'is_not_virtual'       => !$order->getIsVirtual(),
                'store_id'             => $order->getStoreId(),
                'email_customer_note'  => $order->getEmailCustomerNote(),
            ]
        ];

        $templateOptions = [
            'area' => Area::AREA_FRONTEND,
            'store' => $this->storeManager->getStore()->getStoreId(),
        ];

        try {
            $transport = $this->transportBuilder
                ->setTemplateIdentifier($templateIdentifier)
                ->setTemplateOptions($templateOptions)
                ->setTemplateVars($templateVars)
                ->setFrom($from)
                ->addTo($order->getCustomerEmail())
                ->getTransport();
            $transport->sendMessage();

            $this->inlineTranslation->resume();
        } catch (Exception $exception) {
            $this->inlineTranslation->resume();
            $this->logger->error($exception->getMessage(), ['exception' => $exception]);
        }
    }

    /**
     * @param $order
     * @return string
     * @throws NoSuchEntityException
     */
    protected function getPaymentHtml($order): string
    {
        return $this->paymentHelper->getInfoBlockHtml(
            $order->getPayment(),
            $this->storeManager->getStore()->getId()
        );
    }

    /**
     * @param $order
     * @return string|null
     */
    protected function getFormattedShippingAddress($order)
    {
        return $order->getIsVirtual()
            ? null
            : $this->addressRenderer->format($order->getShippingAddress(), 'html');
    }

    /**
     * @param $order
     * @return string|null
     */
    protected function getFormattedBillingAddress($order)
    {
        return $this->addressRenderer->format($order->getBillingAddress(), 'html');
    }
}
