<?php
/**
 * Mageplaza
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Mageplaza.com license that is
 * available through the world-wide-web at this URL:
 * https://www.mageplaza.com/LICENSE.txt
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade this extension to newer
 * version in the future.
 *
 * @category    Mageplaza
 * @package     Mageplaza_EditOrder
 * @copyright   Copyright (c) Mageplaza (https://www.mageplaza.com/)
 * @license     https://www.mageplaza.com/LICENSE.txt
 */

namespace Mageplaza\EditOrder\Controller\Adminhtml\Shipment;

use Exception;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\Result\Json;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Framework\Controller\Result\RedirectFactory;
use Magento\Framework\Controller\ResultInterface;
use Magento\Framework\View\Layout;
use Magento\Sales\Api\ShipmentRepositoryInterface;
use Magento\Sales\Model\Convert\Order;
use Magento\Sales\Model\Order as ModelOrder;
use Magento\Sales\Model\Order\Email\Sender\ShipmentSender;
use Magento\Sales\Model\Order\Shipment;
use Magento\Sales\Model\Order\Shipment\TrackFactory;
use Magento\Sales\Model\OrderRepository;

/**
 * Class AddTrack
 * @package Mageplaza\EditOrder\Controller\Adminhtml\Order\Shipment
 */
class AddTrack extends Action
{
    /**
     * @var OrderRepository
     */
    protected $orderRepository;

    /**
     * @var Json
     */
    protected $_resultJson;

    /**
     * @var Layout
     */
    protected $layout;

    /**
     * @var Order
     */
    protected $convertOrder;

    /**
     * @var TrackFactory
     */
    protected $trackFactory;

    /**
     * @var ShipmentSender
     */
    protected $shipmentSender;

    /**
     * @var ShipmentRepositoryInterface
     */
    protected $shipmentRepository;

    /**
     * @var JsonFactory
     */
    protected $resultJsonFactory;

    /**
     * @var RedirectFactory
     */
    protected $resultRedirectFactory;

    /**
     * AddTrack constructor.
     *
     * @param Context $context
     * @param OrderRepository $orderRepository
     * @param Order $convertOrder
     * @param TrackFactory $trackFactory
     * @param ShipmentSender $shipmentSender
     * @param ShipmentRepositoryInterface $shipmentRepository
     * @param JsonFactory $resultJsonFactory
     * @param RedirectFactory $resultRedirectFactory
     * @param Json $resultJson
     * @param Layout $layout
     */
    public function __construct(
        Context $context,
        OrderRepository $orderRepository,
        Order $convertOrder,
        TrackFactory $trackFactory,
        ShipmentSender $shipmentSender,
        ShipmentRepositoryInterface $shipmentRepository,
        JsonFactory $resultJsonFactory,
        RedirectFactory $resultRedirectFactory,
        Json $resultJson,
        Layout $layout
    ) {
        $this->orderRepository       = $orderRepository;
        $this->convertOrder          = $convertOrder;
        $this->_resultJson           = $resultJson;
        $this->layout                = $layout;
        $this->trackFactory          = $trackFactory;
        $this->shipmentSender        = $shipmentSender;
        $this->shipmentRepository    = $shipmentRepository;
        $this->resultJsonFactory     = $resultJsonFactory;
        $this->resultRedirectFactory = $resultRedirectFactory;

        parent::__construct($context);
    }

    /**
     * @return ResponseInterface|Json|ResultInterface
     */
    public function execute()
    {
        $result       = $this->resultJsonFactory->create();
        $orderId      = $this->getRequest()->getParam('order_id');
        $trackNumber  = $this->getRequest()->getParam('tracking');
        $massShipment = $this->getRequest()->getParam('mass_shipment');
        $resultData  = [
            'success' => true,
        ];

        if ($orderId && $trackNumber) {
            try {
                /** @var  ModelOrder $order */
                $order               = $this->orderRepository->get($orderId);
                $shipmentsCollection = $order->getShipmentsCollection();

                if ($shipmentsCollection->getSize() >= 1) {
                    /** @var Shipment $shipment */
                    foreach ($shipmentsCollection->getItems() as $shipment) {
                        if ((int)$shipment->getShipmentStatus() !== 3) {
                            $this->updateTrackingInformation($shipment, $trackNumber);
                        }
                    }
                    $this->messageManager->addSuccessMessage(__('The tracking number of the shipment(s) has been updated.'));
                }
            } catch (Exception $e) {
                $resultData = [
                    'error'   => true,
                    'message' => $e->getMessage()
                ];
            }
        } else if ($massShipment) {
            $resultRedirect = $this->resultRedirectFactory->create();
            $resultRedirect->setPath($this->getUrl('sales/shipment/index', array('_current' => true)));
            try {
                foreach ($trackNumber as $shipmentId => $numbers) {
                    $shipment = $this->shipmentRepository->get($shipmentId);
                    $this->updateTrackingInformation($shipment, $numbers);
                }
                $this->messageManager->addSuccessMessage(__('The tracking number of the shipment(s) has been updated.'));
                return $resultRedirect;
            } catch (Exception $e) {
                $this->messageManager->addErrorMessage($e->getMessage());
                return $resultRedirect;
            }

        }

        $result->setData($resultData);

        return $result;
    }

    /**
     * @param Shipment $shipment
     * @param array $trackNumber
     */
    protected function updateTrackingInformation($shipment, $trackNumber)
    {
        foreach ($trackNumber as $number) {
            $track = $this->trackFactory->create()->addData($number);
            $shipment->addTrack($track)->save();
            $shipment->getOrder()->save();
        }
    }
}
