<?php

namespace YSquare\Shipcloud\Application\Controller\Admin;

use OxidEsales\Eshop\Application\Model\Order;
use OxidEsales\Eshop\Core\Model\ListModel;
use OxidEsales\Eshop\Core\Registry;
use YSquare\Shipcloud\Application\Model\Shipcloud;
use YSquare\Shipcloud\Application\Model\Shipcloud2Orderarticle;

class ShipcloudOrder extends AdminController
{
    protected $_sThisTemplate = 'shipcloud_order.tpl';// phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
    protected $message;
    protected $packageTemplates;
    protected $order;
    protected $shipcloudPackages;
    protected $options;
    protected $order_articles;
    protected $pickupTime;
    protected $addressData = [];
    public function __construct()
    {
        parent::__construct('shipcloud_order');
    }

    public function getOrderArticles($shipcloudId = null)
    {
        if (!$shipcloudId) {
            return $this->order->getOrderArticles();
        } else {
            return $this->shipcloudPackages[$shipcloudId]->getOrderArticles();
        }
    }

    public function getSend($order_article_id)
    {
        $queryBuilder = $this->queryBuilderFactory->create();
        $result = $queryBuilder
            ->select('sum(s2oa.oxamount) as sm')
            ->from('ysshipcloud2orderarticles', 's2oa')
            ->innerJoin('s2oa', 'ysshipcloud', 's', 's.OXID = s2oa.YSSHCLID')
            ->where('s2oa.OXOARTID = :article_id')
            ->andWhere('s.YSCARRIERSERVICE != :service')
            ->setParameters(
                [
                    'article_id' => $order_article_id,
                    'service'    => 'returns',
                ]
            )
            ->execute()->fetch()['sm'];

        if ($result) {
            return $result;
        } else {
            return 0;
        }
    }

    public function getOrderArticle($shipcloud_id, $orderArticleId)
    {
        $queryBuilder = $this->queryBuilderFactory->create();
        $oxid = $queryBuilder
            ->select('s2oa.oxid')
            ->from('ysshipcloud2orderarticles', 's2oa')
            ->where('s2oa.YSSHCLID = :shipcloud_id')
            ->andWhere('s2oa.OXOARTID = :article_id')
            ->setParameters(
                [
                    "shipcloud_id" => $shipcloud_id,
                    "article_id"   => $orderArticleId,
                ]
            )->execute()->fetch()["oxid"];

        $shipcloud2orderArticle = oxNew(Shipcloud2Orderarticle::class);
        $shipcloud2orderArticle->load($oxid);

        return $shipcloud2orderArticle;
    }

    public function updateShipcloud2OrderarticleAmount()
    {
        $oxid = Registry::getRequest()->getRequestEscapedParameter('oxid');
        $amount = Registry::getRequest()->getRequestEscapedParameter('amount');

        $shipcloud2orderArticle = oxNew(Shipcloud2Orderarticle::class);
        $shipcloud2orderArticle->load($oxid);

        $shipcloud2orderArticle->assign(["ysshipcloud2orderarticles__oxamount" => $amount]);
        $result = $shipcloud2orderArticle->save();

        header('Content-Type: application/json; charset=UTF-8');
        echo json_encode(["exception" => null, "result" => json_encode($result)]);
        exit();
    }

    public function save()
    {
        $sessionParameter = Registry::getSession()->getVariable('session_shipcloud_order_params');
        if (!$sessionParameter) {
            $sessionParameter = [];
        }

        $sessionParameter = $this->updateSession('options', $sessionParameter);
        $this->options = $sessionParameter['options'];

        $oxid = $this->getEditObjectId();
        $this->order = oxNew(Order::class);
        $this->order->load($oxid);

        $this->order_articles = oxNew(ListModel::class);
        $this->order_articles->init('oxorderarticle');
        $visible_order_articles = Registry::getRequest()->getRequestEscapedParameter('order_articles');

        // Save weight to oxorderarticles if weight has changed
        foreach ($visible_order_articles as $orderaticle_id => $visible_order_article) {
            $orderArticle = oxNew('oxorderarticle');
            $orderArticle->load($orderaticle_id);
            if ($orderArticle->oxorderarticles__oxweight->value != $visible_order_article['weight']) {
                $orderArticle->assign(['oxorderarticles__oxweight' => $visible_order_article['weight']]);
                $orderaticle_id = $orderArticle->save();
                $orderArticle->load($orderaticle_id);
            }

            if ($visible_order_article['active']) {
                $orderArticle->assign(['oxamount' => $visible_order_article['amount']]);
                $this->order_articles->add($orderArticle);
            }
        }

        Registry::getSession()->setVariable('session_shipcloud_order_params', $sessionParameter);
    }

    public function updateSession($parameter, $sessionParameter)
    {
        $parameterValue = Registry::getRequest()->getRequestEscapedParameter($parameter);

        if ($parameterValue) {
            $sessionParameter[$parameter] = $parameterValue;
        }

        return $sessionParameter;
    }

    public function getOrderShipcloudPackages()
    {
        if (!$this->shipcloudPackages) {
            // Select all shipcloud objects, which have order articles for the current order
            $queryBuilder = $this->queryBuilderFactory->create();
            $results = $queryBuilder
                ->select('s.oxid')
                ->from('ysshipcloud', 's')
                ->innerJoin('s', 'ysshipcloud2orderarticles', 's2oa', 's.OXID = s2oa.YSSHCLID')
                ->innerJoin('s2oa', 'oxorderarticles', 'oa', 's2oa.OXOARTID = oa.OXID')
                ->where('oa.OXORDERID = :order_id')
                ->setParameter("order_id", $this->getEditObjectId())
                ->orderBy('s.OXTIMESTAMP', 'ASC')
                ->execute()->fetchAll();

            $this->shipcloudPackages = [];

            foreach ($results as $result) {
                $oxid = $result['oxid'];
                $shipcloud = oxNew(Shipcloud::class);
                $shipcloud->load($oxid);
                $this->shipcloudPackages[$oxid] = $shipcloud;
            }
        }

        return $this->shipcloudPackages;
    }

    public function copyAsRetourLabel()
    {
        $ysshipcloud__oxid = Registry::getRequest()->getRequestEscapedParameter('options')['shipcloud_id'];
        $shipcloud = oxNew(Shipcloud::class);
        $shipcloud->load($ysshipcloud__oxid);

        $params = [];
        $params['ysshipcloud__yscarrierservice'] = 'returns';
        $newShipcloud = $shipcloud->copy($params);

        $sessionParameter = Registry::getSession()->getVariable('session_shipcloud_order_params');
        $this->options['shipcloud_id'] = $newShipcloud->ysshipcloud__oxid->value;
        $sessionParameter['options'] = $this->options;
        Registry::getSession()->setVariable('session_shipcloud_order_params', $sessionParameter);
    }

    public function deleteShipcloudPackage()
    {
        $ysshipcloud__oxid = Registry::getRequest()->getRequestEscapedParameter('options')['shipcloud_id'];

        $shipcloud = oxNew(Shipcloud::class);
        $shipcloud->load($ysshipcloud__oxid);

        if ($shipcloud->ysshipcloud__ysshipcloudid->value) {
            $oLang = Registry::getLang();
            $this->message[] = [
                "type" => "danger",
                "text" => $oLang->translateString('YS_DELETE_SHIPCLOUD_PACKAGE_FIRST'),
                "info" => "",
                "time" => 3000,
            ];
        } else {
            $shipcloud->deleteSelf();
        }
    }

    public function deleteShipcloudLabel()
    {
        $this->save();

        $ysshipcloud__oxid = Registry::getRequest()->getRequestEscapedParameter('options')['shipcloud_id'];

        $shipcloud = oxNew(Shipcloud::class);
        $shipcloud->load($ysshipcloud__oxid);
        $result = $shipcloud->deleteShipment();

        if ($result['exception']) {
            $this->message[] = [
                "type" => "danger",
                "text" => $result['exception']['message'],
                "info" => "",
                "time" => 6000,
            ];
        }
    }

    public function buyShipcloudLabel()
    {
        $this->save();

        $this->createShipcloudLabel(true);
    }

    public function createShipcloudLabel($buy = false)
    {
        $this->save();

        $shipcloudId = Registry::getRequest()->getRequestEscapedParameter('options')['shipcloud_id'];
        $shipcloud = oxNew(Shipcloud::class);
        $shipcloud->load($shipcloudId);

        $result = $shipcloud->createShipment($buy, $this->getAddressData($shipcloud, 'return'));
        if ($result['exception']) {
            $this->message[] = [
                "type" => "danger",
                "text" =>
                    $result['exception']['message'],
                "info" => "",
                "time" => 6000,
            ];
        }
    }

    public function getAddressData($shipcloud, $type)
    {
        if (array_key_exists($type, $this->addressData)) {
            return $this->addressData[$type];
        }

        $this->addressData[$type] = $this->adminSettings->getSettings('from', 'main_settings');
        if ($type === 'return' && $shipcloud && ($addressId = $shipcloud->getFieldData('ys_return_address'))) {
            $address = oxNew(\YSquare\Shipcloud\Application\Model\ShipcloudAddress::class);
            $loaded = $address->load($addressId);
            $this->addressData[$type] = $loaded ? $address->getData() : $this->addressData[$type];
        }

        return $this->addressData[$type];
    }

    public function sendPickupRequest()
    {
        $this->save();
        $options = Registry::getRequest()->getRequestEscapedParameter('options');
        $shipcloudId = $options['shipcloud_id'];

        $shipcloud = oxNew(Shipcloud::class);
        $shipcloud->load($shipcloudId);

        $pickupTime = Registry::getRequest()->getRequestEscapedParameter('pickupTime');
        $pickupAddress = $options['pickup_address'];
        if ($pickupAddress) {
            $oAddress = oxNew(\YSquare\Shipcloud\Application\Model\ShipcloudAddress::class);
            $loaded = $oAddress->load($pickupAddress);
            $address = $loaded ? $oAddress->getData() : $this->getAddressData($shipcloud, 'pickup');
        } else {
            $address = $this->getAddressData($shipcloud, 'pickup');
        }

        $result = $shipcloud->sendPickupRequest($pickupTime, $address);
        if ($result['exception']) {
            $this->message[] = [
                "type" => "danger",
                "text" => $result['exception']['message'],
                "info" => "",
                "time" => self::ERROR_MESSAGE_TIME["MEDIUM"],
            ];
        }
    }

    public function sendShipcloudPackageMail()
    {
        $this->save();

        $ysshipcloud__oxid = Registry::getRequest()->getRequestEscapedParameter('options')['shipcloud_id'];

        $shipcloud = oxNew(Shipcloud::class);
        $shipcloud->load($ysshipcloud__oxid);

        if (!$shipcloud->ysshipcloud__ysshipcloudid->value) {
            $oLang = Registry::getLang();
            $this->message[] = [
                "type" => "danger",
                "text" => $oLang->translateString('YS_BUY_SHIPCLOUD_PACKAGE_FIRST'),
                "info" => "",
                "time" => self::ERROR_MESSAGE_TIME["MEDIUM"],
            ];
        } else {
            $result = $shipcloud->sendShipmentMail();
        }
    }

    public function createNewShipcloudPackage()
    {
        $this->save();

        $shipcloud = oxNew(Shipcloud::class);
        $sUid = Registry::getUtilsObject()->generateUId();

        $shipcloud->assign(['oxid' => $sUid]);
        $shipcloud->save();

        $sessionParameter = Registry::getSession()->getVariable('session_shipcloud_order_params');
        $this->options['shipcloud_id'] = $shipcloud->ysshipcloud__oxid->value;
        $sessionParameter['options'] = $this->options;
        Registry::getSession()->setVariable('session_shipcloud_order_params', $sessionParameter);

        $packageTemplate = $this->options['packagetemplate'];
        if ($packageTemplate) {
            $shipcloud->setPackageTemplate($this->getPackageTemplates($packageTemplate));
        }

        $shipcloud->setOrderArticles($this->order_articles);
    }

    public function getPackageTemplates($packageTemplateKey = null)
    {
        if (!$this->packageTemplates) {
            $this->packageTemplates = $this->adminSettings->getSettings('package_templates', 'package_templates');
        }
        if ($packageTemplateKey and $this->packageTemplates) {
            foreach ($this->packageTemplates as $packageTemplate) {
                if ($packageTemplate['name'] == $packageTemplateKey) {
                    return $packageTemplate;
                }
            }
        }
        return $this->packageTemplates;
    }

    public function render()
    {
        $ret = parent::render();

        $this->_init();

        $soxId = $this->_aViewData["oxid"] = $this->getEditObjectId();
        if (isset($soxId) && $soxId != "-1") {
            // load object
            $this->order = oxNew(Order::class);
            $this->order->load($soxId);

            $this->_aViewData["edit"] = $this->order;
        }
        $this->_aViewData["order_message"] = json_encode($this->message);
        $this->_aViewData["options_string"] = json_encode($this->options);
        $this->_aViewData["options"] = $this->options;

        if (!$this->pickupTime) {
            $this->pickupTime = [
                'from' => date('Y-m-d\TH:i', time()),
                'to'   => date('Y-m-d\TH:i', strtotime("+2 hours")),
            ];
        }
        $this->_aViewData["pickupTime"] = $this->pickupTime;

        return $ret;
    }

    public function _init()
    {
        $sessionParameter = Registry::getSession()->getVariable('session_shipcloud_order_params');
        if (!$sessionParameter) {
            $sessionParameter = [];
        }
        $this->options = $sessionParameter['options'];
    }

    public function getPickupAddresses()
    {
        /** @var \YSquare\Shipcloud\Application\Model\ShipcloudAddress $shipcloud_address */
        $shipcloud_address = oxNew(\YSquare\Shipcloud\Application\Model\ShipcloudAddress::class);

        $shipcloud_addresses = oxNew(ListModel::class);
        $shipcloud_addresses->init(\YSquare\Shipcloud\Application\Model\ShipcloudAddress::class);
        $shipcloud_addresses->selectString($shipcloud_address->buildSelectString(['ys_pickup_address' => 1]));
        return $shipcloud_addresses;
    }
}