<?php

declare(strict_types=1);

namespace Core;

use PDO;
use PDOException;
use Throwable;

final class Database
{
    private static array $config = [];
    private static ?PDO $connection = null;

    public static function boot(array $config): void
    {
        self::$config = $config;
    }

    public static function connection(): PDO
    {
        if (self::$connection instanceof PDO) {
            return self::$connection;
        }

        $dsn = sprintf(
            'mysql:host=%s;port=%s;dbname=%s;charset=%s',
            self::$config['host'],
            self::$config['port'],
            self::$config['database'],
            self::$config['charset'] ?? 'utf8mb4'
        );

        try {
            self::$connection = new PDO($dsn, self::$config['username'], self::$config['password'], [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            ]);
            return self::$connection;
        } catch (PDOException) {
            http_response_code(500);
            echo 'Erro ao conectar com o banco de dados. Verifique o arquivo .env.';
            exit;
        }
    }

    public static function transaction(callable $callback): mixed
    {
        $connection = self::connection();
        $ownsTransaction = !$connection->inTransaction();

        if ($ownsTransaction) {
            $connection->beginTransaction();
        }

        try {
            $result = $callback($connection);
            if ($ownsTransaction && $connection->inTransaction()) {
                $connection->commit();
            }
            return $result;
        } catch (Throwable $exception) {
            if ($ownsTransaction && $connection->inTransaction()) {
                $connection->rollBack();
            }
            throw $exception;
        }
    }
}
