"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.__tsfTypeAliases = void 0;
exports.waitForTestDatabaseReady = waitForTestDatabaseReady;
const tslib_1 = require("tslib");
const _a = tslib_1.__importStar(require("@zyno-io/ts-server-foundation/type-metadata-runtime"));
const promises_1 = require("node:timers/promises");
const promise_1 = tslib_1.__importDefault(require("mysql2/promise"));
const pg_1 = require("pg");
const logger_1 = require("../services/logger");
const readiness = new Map();
async function waitForTestDatabaseReady(adapter, config, options = {}) {
    const key = readinessKey(adapter, config);
    let promise = readiness.get(key);
    if (!promise) {
        promise = waitForTestDatabaseReadyUncached(adapter, config, options).catch(error => {
            readiness.delete(key);
            throw error;
        });
        readiness.set(key, promise);
    }
    await promise;
}
async function waitForTestDatabaseReadyUncached(adapter, config, options) {
    const timeoutMs = options.timeoutMs ?? 30000;
    const intervalMs = options.intervalMs ?? 1000;
    const probe = options.probe ?? probeTestDatabase;
    const log = options.log ?? logDatabaseReadiness;
    log('Waiting for database to be ready...');
    const startedAt = Date.now();
    let lastError;
    while (Date.now() - startedAt < timeoutMs) {
        const attemptStartedAt = Date.now();
        try {
            await probe(adapter, config);
            return;
        }
        catch (error) {
            lastError = error;
        }
        const elapsed = Date.now() - startedAt;
        const remaining = timeoutMs - elapsed;
        if (remaining <= 0)
            break;
        const nextAttemptDelay = Math.max(0, intervalMs - (Date.now() - attemptStartedAt));
        await (0, promises_1.setTimeout)(Math.min(nextAttemptDelay, remaining));
    }
    throw new Error(`Timed out waiting for ${adapter} database to be ready after ${Math.ceil(timeoutMs / 1000)} seconds`, {
        cause: lastError
    });
}
function logDatabaseReadiness(message) {
    (0, logger_1.createLogger)('DatabaseReadiness').info(message);
}
async function probeTestDatabase(adapter, config) {
    if (adapter === 'mysql') {
        const connection = await promise_1.default.createConnection({
            host: config.MYSQL_HOST,
            port: config.MYSQL_PORT ?? 3306,
            user: config.MYSQL_USER,
            password: config.MYSQL_PASSWORD_SECRET,
            database: 'mysql',
            connectTimeout: 1000
        });
        try {
            await connection.query('SELECT 1');
        }
        finally {
            await connection.end();
        }
        return;
    }
    const client = new pg_1.Client({
        host: config.PG_HOST,
        port: config.PG_PORT ?? 5432,
        user: config.PG_USER,
        password: config.PG_PASSWORD_SECRET,
        database: 'postgres',
        ssl: resolvePostgresSsl(config),
        connectionTimeoutMillis: 1000
    });
    try {
        await client.connect();
        await client.query('SELECT 1');
    }
    finally {
        await client.end().catch(() => { });
    }
}
function readinessKey(adapter, config) {
    return adapter === 'mysql'
        ? ['mysql', config.MYSQL_HOST, config.MYSQL_PORT, config.MYSQL_USER].join(':')
        : ['postgres', config.PG_HOST, config.PG_PORT, config.PG_USER, config.PG_SSL, config.PG_SSL_REJECT_UNAUTHORIZED].join(':');
}
function resolvePostgresSsl(config) {
    if (!config.PG_SSL)
        return undefined;
    return {
        rejectUnauthorized: config.PG_SSL_REJECT_UNAUTHORIZED ?? true
    };
}
exports.__tsfTypeAliases = _a.decodeCompactMetadataV1("[1,{\"TestDatabaseReadyProbe\":{\"kind\":2,\"typeName\":\"(adapter: DatabaseDialect, config: BaseAppConfig) =\\u003e Promise\\u003cvoid\\u003e\",\"typeName\":\"TestDatabaseReadyProbe\"},\"WaitForTestDatabaseReadyOptions\":{\"kind\":18,\"typeName\":\"WaitForTestDatabaseReadyOptions\",\"types\":[{\"kind\":20,\"name\":\"timeoutMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"intervalMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"probe\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2,\"typeName\":\"(adapter: DatabaseDialect, config: BaseAppConfig) =\\u003e Promise\\u003cvoid\\u003e\",\"typeName\":\"TestDatabaseReadyProbe\"},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"log\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2,\"typeName\":\"(message: string) =\\u003e void\"},{\"kind\":4}]},\"optional\":true}]}}]", []);
//# sourceMappingURL=database-readiness.js.map