<?php
/**
 * 2026 Paysera
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@prestashop.com so we can send you a copy immediately.
 *
 * @author Paysera <plugins@paysera.com>
 * @copyright 2026 Paysera
 * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
 * International Registered Trademark & Property of Paysera
 */

declare(strict_types=1);

namespace Paysera\PrestashopPayments\Service;

use Paysera\PrestashopPayments\Enum\OrderPaymentState;
use Paysera\PrestashopPayments\Provider\SettingsProvider;
use Paysera\PrestashopPayments\Repository\OrderRepository;
use Psr\Log\LoggerInterface;

if (!defined('_PS_VERSION_')) {
    exit;
}

class OrderStatusManager
{
    public function __construct(
        private SettingsProvider $settingsProvider,
        private OrderRepository $orderRepository,
        private OrderStateMachine $stateMachine,
        private LoggerInterface $logger
    ) {
    }

    public function setToAwaitingPayment(\Order $order): void
    {
        $statusId = $this->settingsProvider->getStatusAwaitingPayment();
        $this->setStatusIfConfigured($order, $statusId, 'awaiting payment');
    }

    public function setToAwaitingConfirmation(\Order $order): void
    {
        $statusId = $this->settingsProvider->getStatusAwaitingConfirmation();
        $this->setStatusIfConfigured($order, $statusId, 'awaiting confirmation');
    }

    public function setToConfirmed(\Order $order): void
    {
        $statusId = $this->settingsProvider->getStatusConfirmedPayment();
        $this->setStatusIfConfigured($order, $statusId, 'confirmed');
    }

    public function setToFailed(\Order $order): void
    {
        $statusId = $this->settingsProvider->getStatusFailed();
        $this->setStatusIfConfigured($order, $statusId, 'failed');
    }

    public function setToCancelled(\Order $order): void
    {
        $statusId = $this->settingsProvider->getStatusCancelled();
        $this->setStatusIfConfigured($order, $statusId, 'cancelled');
    }

    private function setStatusIfConfigured(\Order $order, ?int $statusId, string $statusName): void
    {
        if ($statusId === null) {
            $this->logger->warning("Cannot set order to {$statusName}: status not configured", [
                'order_id' => $order->id,
            ]);

            return;
        }

        $this->setStatus($order, $statusId);
    }

    private function setStatus(\Order $order, int $newStatusId): void
    {
        $currentStatusId = (int) $order->getCurrentState();

        if ($currentStatusId === $newStatusId) {
            $this->logger->debug('Order already in target status', [
                'order_id' => $order->id,
                'status_id' => $newStatusId,
            ]);

            return;
        }

        if (!$this->isTransitionAllowed($order, $newStatusId)) {
            $this->logger->warning('Invalid status transition prevented', [
                'order_id' => $order->id,
                'current_status' => $currentStatusId,
                'target_status' => $newStatusId,
            ]);

            return;
        }

        $history = new \OrderHistory();
        $history->id_order = $order->id;
        $history->changeIdOrderState($newStatusId, $order->id);

        $this->logger->info('Order status updated', [
            'order_id' => $order->id,
            'old_status' => $currentStatusId,
            'new_status' => $newStatusId,
        ]);
    }

    private function isTransitionAllowed(\Order $order, int $newStatusId): bool
    {
        $currentState = $this->resolvePayseraState($order);
        $targetState = $this->getStateByStatusId($newStatusId);

        if ($targetState === null) {
            return true;
        }

        return $this->stateMachine->canTransition($currentState, $targetState);
    }

    private function resolvePayseraState(\Order $order): ?string
    {
        $currentState = $this->getStateByStatusId((int) $order->getCurrentState());

        if ($currentState !== null) {
            return $currentState;
        }

        return $this->getLastPayseraStateFromHistory($order);
    }

    private function getLastPayseraStateFromHistory(\Order $order): ?string
    {
        $statusHistory = $this->orderRepository->getStatusHistory($order);

        foreach ($statusHistory as $statusId) {
            $state = $this->getStateByStatusId($statusId);

            if ($state !== null) {
                return $state;
            }
        }

        return null;
    }

    private function getStateByStatusId(int $statusId): ?string
    {
        return match ($statusId) {
            $this->settingsProvider->getStatusAwaitingPayment() => OrderPaymentState::AWAITING_PAYMENT,
            $this->settingsProvider->getStatusAwaitingConfirmation() => OrderPaymentState::AWAITING_CONFIRMATION,
            $this->settingsProvider->getStatusConfirmedPayment() => OrderPaymentState::CONFIRMED,
            $this->settingsProvider->getStatusFailed() => OrderPaymentState::FAILED,
            $this->settingsProvider->getStatusCancelled() => OrderPaymentState::CANCELLED,
            default => null,
        };
    }
}
