import { SybaseConnectionError } from "./errors.js";
/** Map isolation level names to Sybase numeric levels. */
const isolationLevelMap = {
    read_uncommitted: 0,
    read_committed: 1,
    repeatable_read: 2,
    serializable: 3
};
export class SybaseSession {
    pool;
    constructor(pool) {
        this.pool = pool;
    }
    /**
     * Execute raw SQL and return results.
     */
    async execute(rawSql, options) {
        const result = await this.pool.query(rawSql, options);
        return {
            rows: result.rows,
            rowCount: result.rowCount,
            affectedRows: result.affectedRows
        };
    }
    /**
     * Execute raw SQL and return the full result (including columns).
     */
    async executeRaw(rawSql, options) {
        return this.pool.query(rawSql, options);
    }
    /**
     * Run a transaction on a single connection.
     *
     * Acquires a connection, optionally sets isolation level, executes BEGIN TRAN,
     * runs the callback, then COMMIT or ROLLBACK. The connection is held for the duration.
     *
     * @example
     * ```ts
     * await session.transaction(async tx => {
     *   await tx.execute("INSERT INTO ...");
     * }, { isolationLevel: "serializable" });
     * ```
     */
    async transaction(fn, options) {
        const conn = await this.pool.acquire();
        const isolationChanged = !!options?.isolationLevel;
        try {
            // Set isolation level if specified (applies to the next transaction)
            if (options?.isolationLevel) {
                const level = isolationLevelMap[options.isolationLevel];
                await conn.query(`SET TRANSACTION ISOLATION LEVEL ${level}`);
            }
            await conn.query("BEGIN TRAN");
            const tx = new SybaseTransactionSession(conn, this.pool.logger);
            try {
                const result = await fn(tx);
                await conn.query("COMMIT TRAN");
                return result;
            }
            catch (err) {
                // Attempt rollback — ignore errors if connection is dead
                try {
                    await conn.query("ROLLBACK TRAN");
                }
                catch (_rollbackErr) {
                    // If rollback fails, connection is likely dead
                    // The pool will detect and discard it on release
                }
                throw err;
            }
        }
        finally {
            // Reset isolation level to default (read_committed = 1) to prevent leaking
            // session state to subsequent pool users.
            if (isolationChanged && conn.isConnected) {
                try {
                    await conn.query(`SET TRANSACTION ISOLATION LEVEL ${isolationLevelMap.read_committed}`);
                }
                catch {
                    // Ignore — connection may be dead, pool will discard it
                }
            }
            this.pool.release(conn);
        }
    }
}
// ---------------------------------------------------------------------------
// Transaction session — executes on a single held connection
// ---------------------------------------------------------------------------
export class SybaseTransactionSession {
    conn;
    logger;
    constructor(conn, logger) {
        this.conn = conn;
        this.logger = logger;
    }
    /**
     * Execute raw SQL within the transaction.
     */
    async execute(rawSql, options) {
        const result = await this.runWithLogging(rawSql, options);
        return {
            rows: result.rows,
            rowCount: result.rowCount,
            affectedRows: result.affectedRows
        };
    }
    async executeRaw(rawSql, options) {
        return this.runWithLogging(rawSql, options);
    }
    // ---------------------------------------------------------------------------
    // Private
    // ---------------------------------------------------------------------------
    async runWithLogging(rawSql, options) {
        if (!this.conn.isConnected) {
            throw new SybaseConnectionError("Transaction connection is dead");
        }
        const startTime = Date.now();
        try {
            const result = await this.conn.query(rawSql, options);
            if (this.logger) {
                this.logger.query({
                    sql: rawSql,
                    durationMs: Date.now() - startTime,
                    rowCount: result.rowCount,
                    timestamp: new Date(startTime)
                });
            }
            return result;
        }
        catch (err) {
            if (this.logger) {
                this.logger.query({
                    sql: rawSql,
                    durationMs: Date.now() - startTime,
                    rowCount: 0,
                    error: err instanceof Error ? err : new Error(String(err)),
                    timestamp: new Date(startTime)
                });
            }
            throw err;
        }
    }
}
//# sourceMappingURL=session.js.map