<?php

namespace Sibs\Sibs\Setup\Seeders;

use Magento\Framework\Exception\AlreadyExistsException;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Sales\Model\Order\StatusFactory;
use Magento\Sales\Model\ResourceModel\Order\StatusFactory as StatusResourceFactory;
use Sibs\Sibs\DB\SibsDB;
use Sibs\Sibs\Model\SibsConstants;
use Sibs\Sibs\Model\SibsOrder;
use Sibs\Sibs\Setup\SibsUpgradeStatusInterface;
use Sibs\Sibs\Utils\SibsLog;

class UpgradeData221 implements SibsUpgradeStatusInterface
{
    private $upgradeVersion = '2.2.1';

    private $context;

    private $statusFactory;

    private $statusResourceFactory;

    public function __construct(ModuleContextInterface $context, StatusFactory $statusFactory, StatusResourceFactory $statusResourceFactory)
    {
        $this->context               = $context;
        $this->statusFactory         = $statusFactory;
        $this->statusResourceFactory = $statusResourceFactory;

        SibsLog::setNameFile(SibsConstants::SIBS_LOG_INSTALL);
    }

    public function getUpgradeVersion()
    {
        return $this->upgradeVersion;
    }

    public function validateVersion()
    {
        return version_compare($this->context->getVersion(), $this->getUpgradeVersion(), '<');
    }

    public function upgrade(ModuleDataSetupInterface $setup)
    {
        if (! $this->validateVersion()) {
            SibsLog::warn('Will not Update Data on ' . $this->context->getVersion() . ' to version ' . $this->getUpgradeVersion());

            return;
        }

        SibsLog::warn('Try to Update Data to version ' . $this->getUpgradeVersion());

        /* Update PBL Payment Type from PURS to AUTH */
        $this->updatePblPaymentType();

        /* Authorized Status */
        $this->addStatus(
            SibsConstants::MAGENTO_STATE_PROCESSING,
            SibsConstants::SIBS_STATUS_AUTHORIZED,
            'Authorized'
        );

        /* Refunded Status */
        $this->addStatus(
            SibsConstants::MAGENTO_STATE_CLOSED,
            SibsConstants::SIBS_STATUS_REFUNDED,
            'Refunded'
        );

        /* Capture On Hold Status */
        $this->addStatus(
            SibsConstants::MAGENTO_STATE_HOLDED,
            SibsConstants::SIBS_STATUS_CAPTURE_HOLDED,
            'Capture On Hold'
        );

        /* Refund On Hold Status */
        $this->addStatus(
            SibsConstants::MAGENTO_STATE_HOLDED,
            SibsConstants::SIBS_STATUS_REFUND_HOLDED,
            'Refund On Hold'
        );

        $this->updateSibsOrderStatus();
    }

    private function updatePblPaymentType()
    {
        $table_name = SibsDB::getTableName('sales_order');
        $orders_ids = SibsDB::fetchCol("SELECT `entity_id` FROM `$table_name`");

        foreach ($orders_ids as $order_id) {
            $sibsOrder = new SibsOrder($order_id);

            $isSibsOrder = $sibsOrder->isSibsOrder();
            $isPbl       = $sibsOrder->getPaymentMethod() == SibsConstants::SIBS_API_METHOD_PAY_BY_LINK_KEVIN;
            $isAuth      = $sibsOrder->getPaymentType() == SibsConstants::SIBS_PAYMENT_TYPE_AUTH;

            if ($isSibsOrder && $isPbl && $isAuth) {
                $sibsOrder->setPaymentType(SibsConstants::SIBS_PAYMENT_TYPE_PURS);
                $sibsOrder->save();
            }
        }
    }

    protected function addStatus($state, $status, $label, $isDefault = false, $visibleOnFront = true)
    {
        /** @var StatusResource $statusResource */
        $statusResource = $this->statusResourceFactory->create();
        /** @var Status $statusObject */
        $statusObject = $this->statusFactory->create();
        $statusObject->setData([
            'status' => $status,
            'label'  => $label,
        ]);

        try {
            $statusResource->save($statusObject);
        } catch (AlreadyExistsException $e) {
            SibsLog::warn("Status $label not added because: " . $e->getMessage());

            return;
        }

        $statusObject->assignState($state, $isDefault, $visibleOnFront);
    }

    protected function updateSibsOrderStatus()
    {
        $table_name = SibsDB::getTableName('sales_order');
        $orders_ids = SibsDB::fetchCol("SELECT `entity_id` FROM `$table_name`");

        $message = 'Upgraded from SIBS plugin ' . $this->context->getVersion() . ' to ' . $this->getUpgradeVersion();

        foreach ($orders_ids as $order_id) {
            $sibsOrder = new SibsOrder($order_id);

            if (! $sibsOrder->isSibsOrder()) {
                continue;
            }

            if ($this->canUpdateStatusToAuthorized($sibsOrder)) {
                $sibsOrder->updateStatus(
                    SibsConstants::MAGENTO_STATE_PROCESSING,
                    SibsConstants::SIBS_STATUS_AUTHORIZED,
                    $message
                );
            } elseif ($this->canUpdateStatusToOnHold($sibsOrder)) {
                $sibsOrder->updateStatus(
                    SibsConstants::MAGENTO_STATE_HOLDED,
                    SibsConstants::SIBS_STATUS_HOLDED,
                    $message
                );
            } elseif ($this->canUpdateStatusToCaptureOnHold($sibsOrder)) {
                $sibsOrder->updateStatus(
                    SibsConstants::MAGENTO_STATE_HOLDED,
                    SibsConstants::SIBS_STATUS_CAPTURE_HOLDED,
                    $message
                );
            } elseif ($this->canUpdateStatusToRefundOnHold($sibsOrder)) {
                $sibsOrder->updateStatus(
                    SibsConstants::MAGENTO_STATE_HOLDED,
                    SibsConstants::SIBS_STATUS_REFUND_HOLDED,
                    $message
                );
            } elseif ($this->canUpdateStatusToRefunded($sibsOrder)) {
                $sibsOrder->updateStatus(
                    SibsConstants::MAGENTO_STATE_CLOSED,
                    SibsConstants::SIBS_STATUS_REFUNDED,
                    $message
                );
            }
        }
    }

    protected function canUpdateStatusToAuthorized($sibsOrder)
    {
        if (! in_array($sibsOrder->getPaymentMethod(), [SibsConstants::SIBS_API_METHOD_CREDITCARD])) {
            return false;
        }

        if (! in_array($sibsOrder->getPaymentCode(), [SibsConstants::SIBS_API_STATUS_SUCCESS])) {
            return false;
        }

        if (! in_array($sibsOrder->getPaymentType(), [SibsConstants::SIBS_PAYMENT_TYPE_AUTH])) {
            return false;
        }

        if (! in_array($sibsOrder->getSibsIsCapture(), ['FALSE'])) {
            return false;
        }

        // Capture Id can be any|null

        if (! in_array($sibsOrder->getCaptureStatus(), [SibsConstants::MAGENTO_STATE_HOLDED, SibsConstants::MAGENTO_STATE_CANCELED, null])) {
            return false;
        }

        if (! empty($sibsOrder->getRefundedId())) {
            return false;
        }

        if (! empty($sibsOrder->getRefundedStatus())) {
            return false;
        }

        SibsLog::warn('Order #' . $sibsOrder->getEntityId() . ' updated status to Authorized');

        return true;
    }

    protected function canUpdateStatusToOnHold($sibsOrder)
    {
        if (! in_array($sibsOrder->getPaymentMethod(), [
            SibsConstants::SIBS_API_METHOD_CREDITCARD,
            SibsConstants::SIBS_API_METHOD_BLIK,
            SibsConstants::SIBS_API_METHOD_PAY_BY_LINK_KEVIN,
            SibsConstants::SIBS_API_METHOD_XPAY,
        ])) {
            return false;
        }

        if (! in_array($sibsOrder->getPaymentCode(), [SibsConstants::SIBS_API_STATUS_PENDING, SibsConstants::SIBS_API_STATUS_PROCESSING])) {
            return false;
        }

        if (! in_array($sibsOrder->getPaymentType(), [SibsConstants::SIBS_PAYMENT_TYPE_AUTH, SibsConstants::SIBS_PAYMENT_TYPE_PURS])) {
            return false;
        }

        if (! in_array($sibsOrder->getSibsIsCapture(), ['TRUE', null])) {
            return false;
        }

        if (! empty($sibsOrder->getCaptureId())) {
            return false;
        }

        if (! empty($sibsOrder->getCaptureStatus())) {
            return false;
        }

        if (! empty($sibsOrder->getRefundedId())) {
            return false;
        }

        if (! empty($sibsOrder->getRefundedStatus())) {
            return false;
        }

        SibsLog::warn('Order #' . $sibsOrder->getEntityId() . ' updated status to On hold');

        return true;
    }

    protected function canUpdateStatusToCaptureOnHold($sibsOrder)
    {
        if (! in_array($sibsOrder->getPaymentMethod(), [SibsConstants::SIBS_API_METHOD_CREDITCARD])) {
            return false;
        }

        if (! in_array($sibsOrder->getPaymentCode(), [SibsConstants::SIBS_API_STATUS_SUCCESS])) {
            return false;
        }

        if (! in_array($sibsOrder->getPaymentType(), [SibsConstants::SIBS_PAYMENT_TYPE_AUTH])) {
            return false;
        }

        if (! in_array($sibsOrder->getSibsIsCapture(), ['TRUE'])) {
            return false;
        }

        if (empty($sibsOrder->getCaptureId())) {
            return false;
        }

        if (! in_array($sibsOrder->getCaptureStatus(), [SibsConstants::MAGENTO_STATE_HOLDED])) {
            return false;
        }

        if (! empty($sibsOrder->getRefundedId())) {
            return false;
        }

        if (! empty($sibsOrder->getRefundedStatus())) {
            return false;
        }

        SibsLog::warn('Order #' . $sibsOrder->getEntityId() . ' updated status to Capture On hold');

        return true;
    }

    protected function canUpdateStatusToRefundOnHold($sibsOrder)
    {
        if (! in_array($sibsOrder->getPaymentMethod(), [
            SibsConstants::SIBS_API_METHOD_CREDITCARD,
            SibsConstants::SIBS_API_METHOD_BLIK,
            SibsConstants::SIBS_API_METHOD_PAY_BY_LINK_KEVIN,
            SibsConstants::SIBS_API_METHOD_XPAY,
        ])) {
            return false;
        }

        if (! in_array($sibsOrder->getPaymentCode(), [SibsConstants::SIBS_API_STATUS_SUCCESS])) {
            return false;
        }

        if (! in_array($sibsOrder->getPaymentType(), [SibsConstants::SIBS_PAYMENT_TYPE_AUTH, SibsConstants::SIBS_PAYMENT_TYPE_PURS])) {
            return false;
        }

        if (! in_array($sibsOrder->getSibsIsCapture(), ['TRUE', null])) {
            return false;
        }

        // Capture Id can be any|null

        if (! in_array($sibsOrder->getCaptureStatus(), [SibsConstants::MAGENTO_STATE_COMPLETE, null])) {
            return false;
        }

        if (empty($sibsOrder->getRefundedId())) {
            return false;
        }

        if (! in_array($sibsOrder->getRefundedStatus(), [SibsConstants::MAGENTO_STATE_HOLDED])) {
            return false;
        }

        SibsLog::warn('Order #' . $sibsOrder->getEntityId() . ' updated status to Refund On hold');

        return true;
    }

    protected function canUpdateStatusToRefunded($sibsOrder)
    {
        if (! in_array($sibsOrder->getPaymentMethod(), [
            SibsConstants::SIBS_API_METHOD_CREDITCARD,
            SibsConstants::SIBS_API_METHOD_BLIK,
            SibsConstants::SIBS_API_METHOD_PAY_BY_LINK_KEVIN,
            SibsConstants::SIBS_API_METHOD_XPAY,
        ])) {
            return false;
        }

        if (! in_array($sibsOrder->getPaymentCode(), [SibsConstants::SIBS_API_STATUS_SUCCESS])) {
            return false;
        }

        if (! in_array($sibsOrder->getPaymentType(), [SibsConstants::SIBS_PAYMENT_TYPE_AUTH, SibsConstants::SIBS_PAYMENT_TYPE_PURS])) {
            return false;
        }

        if (! in_array($sibsOrder->getSibsIsCapture(), ['TRUE', null])) {
            return false;
        }

        // Capture Id can be any|null

        if (! in_array($sibsOrder->getCaptureStatus(), [SibsConstants::MAGENTO_STATE_COMPLETE, null])) {
            return false;
        }

        if (empty($sibsOrder->getRefundedId())) {
            return false;
        }

        if (! in_array($sibsOrder->getRefundedStatus(), [SibsConstants::MAGENTO_STATE_COMPLETE])) {
            return false;
        }

        SibsLog::warn('Order #' . $sibsOrder->getEntityId() . ' updated status to Refunded');

        return true;
    }
}
