<?php

declare(strict_types=1);

namespace Flowaxy\Infrastructure\Persistence\Database;

use Flowaxy\Support\Facades\Log;
use Throwable;

/**
 * Менеджер транзакций базы данных
 *
 * @package Flowaxy\Infrastructure\Persistence\Database
 */
final class TransactionManager
{
    private Database $database;

    public function __construct(Database $database)
    {
        $this->database = $database;
    }

    /**
     * Выполнить операцию в транзакции
     *
     * @param callable $callback Функция для выполнения
     * @return mixed
     * @throws \Throwable
     */
    public function transaction(callable $callback): mixed
    {
        $connection = $this->database->getConnection();

        if ($connection === null) {
            throw new \RuntimeException('Database connection not available');
        }

        try {
            $connection->beginTransaction();
            $result = $callback();
            $connection->commit();
            return $result;
        } catch (Throwable $e) {
            if ($connection->inTransaction()) {
                $connection->rollBack();
            }

            try {
                Log::Error('Transaction rolled back', [
                    'exception' => $e,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }

            throw $e;
        }
    }

    /**
     * Начать транзакцию
     *
     * @return bool
     */
    public function begin(): bool
    {
        $connection = $this->database->getConnection();
        if ($connection === null) {
            return false;
        }
        return $connection->beginTransaction();
    }

    /**
     * Подтвердить транзакцию
     *
     * @return bool
     */
    public function commit(): bool
    {
        $connection = $this->database->getConnection();
        if ($connection === null) {
            return false;
        }
        return $connection->commit();
    }

    /**
     * Откатить транзакцию
     *
     * @return bool
     */
    public function rollBack(): bool
    {
        $connection = $this->database->getConnection();
        if ($connection === null) {
            return false;
        }
        return $connection->rollBack();
    }

    /**
     * Проверить, находится ли соединение в транзакции
     *
     * @return bool
     */
    public function inTransaction(): bool
    {
        $connection = $this->database->getConnection();
        if ($connection === null) {
            return false;
        }
        return $connection->inTransaction();
    }
}
