<?php
namespace App\Core;
use PDO, PDOException;

class Database
{
    private static ?PDO $pdo = null;

    public static function pdo(): PDO
    {
        if (!self::$pdo) {
            $c = config('app.db');
            $dsn = "mysql:host={$c['host']};port={$c['port']};dbname={$c['name']};charset=utf8mb4";
            try {
                self::$pdo = new PDO($dsn, $c['user'], $c['pass'], [
                    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                    PDO::ATTR_EMULATE_PREPARES   => false,
                ]);
                self::$pdo->exec("SET NAMES utf8mb4");
            } catch (PDOException $e) {
                if (config('app.debug')) die('DB: ' . $e->getMessage());
                die('Erro de ligação à base de dados. Verifica o ficheiro .env');
            }
        }
        return self::$pdo;
    }

    public static function run(string $sql, array $p = []): \PDOStatement
    {
        $st = self::pdo()->prepare($sql);
        $st->execute($p);
        return $st;
    }

    public static function all(string $sql, array $p = []): array  { return self::run($sql,$p)->fetchAll(); }
    public static function one(string $sql, array $p = []): ?array { $r=self::run($sql,$p)->fetch(); return $r?:null; }
    public static function val(string $sql, array $p = []): mixed  { $r=self::one($sql,$p); return $r?reset($r):null; }
    public static function id(string $sql, array $p = []): int     { self::run($sql,$p); return (int)self::pdo()->lastInsertId(); }
    public static function exec(string $sql, array $p = []): int   { return self::run($sql,$p)->rowCount(); }

    public static function tx(callable $fn): mixed
    {
        self::pdo()->beginTransaction();
        try { $r = $fn(); self::pdo()->commit(); return $r; }
        catch (\Throwable $e) { self::pdo()->rollBack(); throw $e; }
    }
}
