<?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\Repository;

use Paysera\PrestashopPayments\Dto\PaymentStatusTransition;
use Paysera\PrestashopPayments\Installer\DatabaseInstaller;
use Psr\Clock\ClockInterface;
use Psr\Log\LoggerInterface;

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

class PaymentStatusTransitionRepository
{
    public function __construct(
        private LoggerInterface $logger,
        private ClockInterface $clock
    ) {
    }

    public function append(int $orderId, string $toStatus): bool
    {
        if ($orderId <= 0 || $toStatus === '') {
            return false;
        }

        $lastStatus = $this->getLastStatus($orderId);

        if ($lastStatus === $toStatus) {
            return false;
        }

        $inserted = \Db::getInstance()->insert(
            DatabaseInstaller::TABLE_STATUS_TRANSITION,
            [
                'id_order' => $orderId,
                'from_status' => pSQL($lastStatus ?? ''),
                'to_status' => pSQL($toStatus),
                'date_add' => $this->clock->now()->format('Y-m-d H:i:s'),
            ],
            false,
            true,
            \Db::INSERT_IGNORE
        );

        if (!$inserted) {
            $this->logger->debug('Payment status transition skipped (duplicate or concurrent)', [
                'order_id' => $orderId,
                'from' => $lastStatus,
                'to' => $toStatus,
            ]);

            return false;
        }

        $this->logger->debug('Payment status transition recorded', [
            'order_id' => $orderId,
            'from' => $lastStatus,
            'to' => $toStatus,
        ]);

        return true;
    }

    /**
     * @return PaymentStatusTransition[]
     */
    public function findByOrderId(int $orderId): array
    {
        if ($orderId <= 0) {
            return [];
        }

        $rows = \Db::getInstance()->executeS($this->buildSelectByOrder('`from_status`, `to_status`, `date_add`', $orderId));

        if (!is_array($rows)) {
            return [];
        }

        return array_map(
            static fn (array $row): PaymentStatusTransition => new PaymentStatusTransition(
                isset($row['from_status']) && $row['from_status'] !== '' ? (string) $row['from_status'] : null,
                (string) $row['to_status'],
                (string) $row['date_add']
            ),
            $rows
        );
    }

    private function getLastStatus(int $orderId): ?string
    {
        $value = \Db::getInstance()->getValue($this->buildSelectByOrder('`to_status`', $orderId));

        if ($value === false || $value === null || $value === '') {
            return null;
        }

        return (string) $value;
    }

    private function buildSelectByOrder(string $columns, int $orderId): string
    {
        $table = _DB_PREFIX_ . DatabaseInstaller::TABLE_STATUS_TRANSITION;

        return 'SELECT ' . $columns . '
                FROM `' . $table . '`
                WHERE `id_order` = ' . $orderId . '
                ORDER BY `date_add` DESC, `id_transition` DESC';
    }
}
