<?php
/**
 * PDO Singleton Database Connection with Concurrency Optimizations
 */
class Database {
    private static ?PDO $instance = null;
    private static int $queryCount = 0;
    private static array $queryLog = [];

    public static function getInstance(): PDO {
        if (self::$instance === null) {
            $dsn = "mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=".DB_CHARSET;
            $opts = [
                PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES   => false,
                PDO::ATTR_PERSISTENT         => true, // Enabled for enterprise scale
                PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci",
                PDO::ATTR_TIMEOUT            => 30, // Connection timeout
                PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, // Buffer queries for better concurrency
            ];
            try {
                self::$instance = new PDO($dsn, DB_USER, DB_PASS, $opts);

                // Set connection attributes for better concurrency
                self::$instance->exec("SET SESSION sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'");
                self::$instance->exec("SET SESSION wait_timeout = 28800"); // 8 hours
                self::$instance->exec("SET SESSION interactive_timeout = 28800");

            } catch (PDOException $e) {
                // Fallback to non-persistent if persistent fails
                $opts[PDO::ATTR_PERSISTENT] = false;
                try {
                    self::$instance = new PDO($dsn, DB_USER, DB_PASS, $opts);
                    self::$instance->exec("SET SESSION sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'");
                    self::$instance->exec("SET SESSION wait_timeout = 28800");
                    self::$instance->exec("SET SESSION interactive_timeout = 28800");
                } catch (PDOException $e2) {
                    $msg = APP_DEBUG ? $e2->getMessage() : 'Database connection failed.';
                    http_response_code(503);
                    die(json_encode(['error' => $msg]));
                }
            }
        }
        return self::$instance;
    }
    
    public static function getQueryCount(): int {
        return self::$queryCount;
    }
    
    public static function getQueryLog(): array {
        return self::$queryLog;
    }
    
    public static function logQuery(string $sql, array $params = []): void {
        if (APP_DEBUG && count(self::$queryLog) < 100) {
            self::$queryLog[] = [
                'sql' => $sql,
                'params' => $params,
                'time' => microtime(true)
            ];
        }
        self::$queryCount++;
    }
    
    public static function resetStats(): void {
        self::$queryCount = 0;
        self::$queryLog = [];
    }
    
    private function __construct() {}
    private function __clone() {}
    public function __wakeup() {
        throw new Exception("Cannot unserialize singleton");
    }
}

function db(): PDO { 
    $instance = Database::getInstance();
    return $instance; 
}
