<?php

define('DBP', SRC . '/../database');

/**
 * Open a connection to a database.
 */
function db_open($path)
{
	$db = new SQLite3($path);

	// Increase cache size to 32MB
	$db->exec('PRAGMA cache_size = 32000');
	// Enable WAL mode
	$db->exec('PRAGMA journal_mode = WAL');
	// Move temp store to memory
	$db->exec('PRAGMA temp_store = MEMORY');

	return $db;
}

/**
 * Return a connection to the auth database.
 */
function db_auth()
{
	return $GLOBALS['db_auth'] ??= db_open(DBP . '/auth.db');
}

/**
 * Return a connection to the live database.
 */
function db_live()
{
	return $GLOBALS['db_live'] ??= db_open(DBP . '/live.db');
}


/**
 * Return a connection to the fights database.
 */
function db_fights()
{
	return $GLOBALS['db_fights'] ??= db_open(DBP . '/fights.db');
}


/**
 * Return a connection to the blueprints database.
 */
function db_blueprints()
{
	return $GLOBALS['db_blueprints'] ??= db_open(DBP . '/blueprints.db');
}

/**
 * Take a SQLite3 database connection, a query string, and an array of parameters. Prepare the query and
 * bind the parameters with proper type casting. Then execute the query and return the result.
 */
function db_query(SQLite3 $db, string $query, array $params = []): SQLite3Result|false
{
	$p = strpos($query, '?') !== false; // are generic placeholders?
	$stmt = $db->prepare($query);
	if (!empty($params)) {
		foreach ($params as $k => $v) $stmt->bindValue($p ? $k + 1 : $k, $v, getSQLiteType($v));
	}
	$start = microtime(true);
	$r = $stmt->execute();
	db_log($query, microtime(true) - $start);
	return $r;
}

/**
 * Take a SQLite3 database connection and a query string. Execute the query and return the result.
 */
function db_exec($db, $query)
{
	$start = microtime(true);
	$r = $db->exec($query);
	db_log($query, microtime(true) - $start);
	return $r;
}

/**
 * Take a SQLite3 database connection, a column name, and a value. Execute a SELECT query to see if the value
 * exists in the column. Return true if the value exists, false otherwise.
 */
function db_exists(SQLite3 $db, string $table, string $column, mixed $value, bool $caseInsensitive = true): bool
{
	if ($caseInsensitive) {
		$query = "SELECT 1 FROM $table WHERE $column = :v COLLATE NOCASE LIMIT 1";
	} else {
		$query = "SELECT 1 FROM $table WHERE $column = :v LIMIT 1";
	}

	$result = db_query($db, $query, [':v' => $value]);
	return $result->fetchArray(SQLITE3_NUM) !== false;
}

/**
 * Return the appropriate SQLite type casting for the value.
 */
function getSQLiteType($value): int
{
    return match (true) {
        is_int($value)   => SQLITE3_INTEGER,
        is_float($value) => SQLITE3_FLOAT,
        is_null($value)  => SQLITE3_NULL,
        default          => SQLITE3_TEXT
    };
}

/**
 * Log the given query string to the db debug log.
 */
function db_log($query, $timeTaken = 0)
{
	$GLOBALS['queries']++;
	$GLOBALS['query_time'] += $timeTaken;
	if (env('debug', false)) $GLOBALS['query_log'][] = [$query, $timeTaken];
}
