<?php
declare(strict_types=1);

namespace PayPo\Payment\Controller\Checkout;

use Magento\Checkout\Model\Session;
use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\Controller\Result\Redirect;
use Magento\Framework\Controller\Result\RedirectFactory;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Sales\Model\Order;
use PayPo\Payment\Helper\Data;
use PayPo\Payment\Logger\Logger;
use PayPo\Payment\Model\Payment\PayPo;

/**
 * Landing page the customer returns to after abandoning the PayPo payment.
 *
 * Cancels the order when configured to do so, restores the cart and sends the
 * customer back to the basket.
 */
class Cancel implements HttpGetActionInterface
{
    /**
     * @param Session $checkoutSession
     * @param RedirectFactory $resultRedirectFactory
     * @param OrderRepositoryInterface $orderRepository
     * @param Logger $logger
     * @param Data $payPoHelper
     */
    public function __construct(
        private readonly Session $checkoutSession,
        private readonly RedirectFactory $resultRedirectFactory,
        private readonly OrderRepositoryInterface $orderRepository,
        private readonly Logger $logger,
        private readonly Data $payPoHelper
    ) {
    }

    /**
     * @return Redirect
     */
    public function execute()
    {
        if ($this->payPoHelper->autoCancel()) {
            $this->cancelCurrentOrder(__('You have successfully canceled your order')->render());
        }

        $this->restoreQuote();

        return $this->resultRedirectFactory->create()->setPath('checkout/cart');
    }

    /**
     * Cancel the order the customer was paying for.
     *
     * @param string $comment
     * @return bool True when the order has actually been cancelled
     */
    public function cancelCurrentOrder($comment): bool
    {
        $order = $this->getCheckoutSession()->getLastRealOrder();

        if (!$order->getId() || $order->getState() === Order::STATE_CANCELED) {
            return false;
        }

        if ($order->getPayment()->getMethod() !== PayPo::METHOD_CODE) {
            return false;
        }

        if ($order->getState() !== 'pending') {
            return false;
        }

        try {
            $order->registerCancellation((string)$comment);
            $this->orderRepository->save($order);
        } catch (\Exception $e) {
            $this->logger->addError(
                sprintf('Cancel, order %s: %s', $order->getIncrementId(), $e->getMessage())
            );

            return false;
        }

        return true;
    }

    /**
     * @return Session
     */
    protected function getCheckoutSession(): Session
    {
        return $this->checkoutSession;
    }

    /**
     * Put the items back into the cart so the customer can retry.
     *
     * @return bool
     */
    public function restoreQuote(): bool
    {
        return $this->getCheckoutSession()->restoreQuote();
    }
}
