<?php

declare(strict_types=1);

namespace Resursbank\MerchantApi\Controller\Admin\Order;

use Order;
use PrestaShopDatabaseException;
use PrestaShopException;
use Resursbank\Ecom\Module\Payment\Enum\Status;
use Resursbank\Ecom\Module\Payment\Repository;
use Resursbank\MerchantApi\Repository\ResursbankOrderRepositoryFrontend;
use Resursbank\MerchantApi\Util\Log;
use Resursbank\MerchantApi\Service\Order as OrderService;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Throwable;

/**
 * Override for admin order controller.
 *
 * Intercepts carrier and cart rule changes and updates the Resurs Bank payment
 * to match the change.
 */
class OrderController extends \PrestaShopBundle\Controller\Admin\Sell\Order\OrderController
{
    /**
     * Handle carrier update.
     *
     * @param int $orderId
     * @param Request $request
     * @return RedirectResponse
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function updateShippingAction(
        int $orderId,
        Request $request
    ): RedirectResponse {
        $order = new Order(id: $orderId);
        $shippingCost = $order->getShipping()[0]['shipping_cost_tax_incl'];

        $result = parent::updateShippingAction(
            orderId: $orderId,
            request: $request
        );

        if (!OrderService::isResursbank(orderReference: $order->reference)) {
            return $result;
        }

        try {
            $newOrder = new Order(id: $orderId);
            $newShippingCost = $newOrder
                ->getShipping()[0]['shipping_cost_tax_incl'];
            if ($shippingCost === $newShippingCost) {
                return $result;
            }

            return $this->updatePayment(
                orderId: $orderId,
                order: $newOrder,
                result: $result
            );
        } catch (Throwable $error) {
            Log::error(message: $error);
            $this->addFlash(
                type: 'error',
                message: 'An error occurred while updating the payment at ' .
                'Resurs Bank, please check payment status in the Merchant Portal'
            );
        }

        return $result;
    }

    /**
     * Handle new cart rules.
     *
     * @param int $orderId
     * @param Request $request
     * @return RedirectResponse
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function addCartRuleAction(
        int $orderId,
        Request $request
    ): RedirectResponse {
        $order = new Order(id: $orderId);
        $totalDiscounts = (float)$order->total_discounts;

        $result = parent::addCartRuleAction($orderId, $request);

        return $this->updateCartRule(
            order: $order,
            result: $result,
            orderId: $orderId,
            totalDiscounts: $totalDiscounts
        );
    }

    /**
     * Handle cart rule removals.
     *
     * @param int $orderId
     * @param int $orderCartRuleId
     * @return RedirectResponse
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function removeCartRuleAction(
        int $orderId,
        int $orderCartRuleId
    ): RedirectResponse {
        $order = new Order(id: $orderId);
        $totalDiscounts = (float)$order->total_discounts;

        $result = parent::removeCartRuleAction(
            orderId: $orderId,
            orderCartRuleId: $orderCartRuleId
        );

        return $this->updateCartRule(
            order: $order,
            result: $result,
            orderId: $orderId,
            totalDiscounts: $totalDiscounts
        );
    }

    /**
     * Handle cart rule updates.
     *
     * @param Order $order
     * @param RedirectResponse $result
     * @param int $orderId
     * @param float $totalDiscounts
     * @return RedirectResponse
     */
    private function updateCartRule(
        Order $order,
        RedirectResponse $result,
        int $orderId,
        float $totalDiscounts
    ): RedirectResponse {
        if (!OrderService::isResursbank(orderReference: $order->reference)) {
            return $result;
        }

        try {
            $newOrder = new Order(id: $orderId);
            $newTotalDiscounts = $newOrder->total_discounts;
            if ($totalDiscounts === $newTotalDiscounts) {
                return $result;
            }

            return $this->updatePayment(
                orderId: $orderId,
                order: $newOrder,
                result: $result
            );
        } catch (Throwable $error) {
            Log::error(message: $error);
            $this->addFlash(
                type: 'error',
                message: 'An error occurred while updating the payment at ' .
                'Resurs Bank, please check payment status in the Merchant Portal'
            );
        }

        return $result;
    }

    /**
     * Update Resurs Bank payment.
     *
     * @param int $orderId
     * @param Order $order
     * @param RedirectResponse $result
     * @return RedirectResponse
     */
    private function updatePayment(
        int $orderId,
        Order $order,
        RedirectResponse $result
    ): RedirectResponse {
        try {
            $resursbankOrder = ResursbankOrderRepositoryFrontend::findByOrderId(
                orderId: $orderId
            );
            $payment = Repository::get(
                paymentId: $resursbankOrder->getMapiId()
            );

            if ($payment->status === Status::TASK_REDIRECTION_REQUIRED ||
                !OrderService::modificationPossible(
                    payment: $payment,
                    order: $order
                ) ||
                !$payment->canCancel()
            ) {
                return $result;
            }

            Repository::cancel(paymentId: $payment->id);

            $products = $order->getProducts();
            $orderLines = OrderService::convert(
                order: $order
            );

            if (count($products) > 0) {
                Repository::addOrderLines(
                    paymentId: $payment->id,
                    orderLines: $orderLines
                );
            }
        } catch (Throwable $error) {
            Log::error(message: $error);
            $this->addFlash(
                type: 'error',
                message: 'An error occurred while updating the payment at ' .
                'Resurs Bank, please check payment status in the Merchant Portal'
            );
        }

        return $result;
    }
}