import { Pool } from "pg";
import { isValidUUID } from "./api/helpers.js";
let activeConnections = 0;
let isShuttingDown = false;
let shutdownPromise = null;
function stripSSLParams(databaseUrl2) {
  if (!databaseUrl2) return databaseUrl2;
  try {
    const url = new URL(databaseUrl2);
    url.searchParams.delete("sslmode");
    url.searchParams.delete("uselibpqcompat");
    return url.toString();
  } catch {
    return databaseUrl2.replace(/[?&]sslmode=[^&]*/g, "").replace(/[?&]uselibpqcompat=[^&]*/g, "").replace(/\?&/, "?").replace(/\?$/, "");
  }
}
function parseSSLConfig(databaseUrl2) {
  var _a;
  const isProduction = process.env.NODE_ENV === "production";
  if (!databaseUrl2) {
    return isProduction ? { rejectUnauthorized: true } : false;
  }
  try {
    const url = new URL(databaseUrl2);
    const sslmode = (_a = url.searchParams.get("sslmode")) == null ? void 0 : _a.trim().toLowerCase();
    if (sslmode) {
      switch (sslmode) {
        case "disable":
          if (isProduction) {
            console.warn("[DB] WARNING: SSL disabled in production environment. This is insecure!");
          }
          return false;
        case "require":
        case "prefer":
        case "allow":
          return { rejectUnauthorized: false };
        case "verify-ca":
        case "verify-full":
          return { rejectUnauthorized: true };
        default:
          console.warn(`[DB] Unknown sslmode value: "${sslmode}". Using environment defaults.`);
      }
    }
    return isProduction ? { rejectUnauthorized: true } : false;
  } catch {
    if (databaseUrl2.includes("sslmode=disable")) {
      return false;
    }
    return isProduction ? { rejectUnauthorized: true } : false;
  }
}
const databaseUrl = process.env.DATABASE_URL || "";
const sslConfig = parseSSLConfig(databaseUrl);
const pool = new Pool({
  connectionString: stripSSLParams(databaseUrl),
  ssl: sslConfig,
  max: 20,
  idleTimeoutMillis: 3e4,
  connectionTimeoutMillis: 1e4
});
function validateUserId(userId) {
  const isProduction = process.env.NODE_ENV === "production";
  if (userId.includes("'") || userId.includes('"') || userId.includes("\\") || userId.includes(";")) {
    throw new Error("Invalid userId format: contains dangerous characters");
  }
  if (/[\x00-\x1f]/.test(userId)) {
    throw new Error("Invalid userId format: contains control characters");
  }
  if (userId.length > 255) {
    throw new Error("Invalid userId format: too long");
  }
  if (isProduction && !isValidUUID(userId) && !/^[a-zA-Z0-9_-]+$/.test(userId)) {
    throw new Error("Invalid userId format - must be valid UUID or alphanumeric");
  }
}
async function acquireClient() {
  if (isShuttingDown) {
    throw new Error("Database pool is shutting down. Cannot acquire new connections.");
  }
  const client = await pool.connect();
  activeConnections++;
  return client;
}
function releaseClient(client) {
  activeConnections = Math.max(0, activeConnections - 1);
  client.release();
}
async function queryWithRLS(query2, params = [], userId) {
  const client = await acquireClient();
  try {
    await client.query("BEGIN");
    if (userId) {
      validateUserId(userId);
      await client.query(`SET LOCAL app.user_id = '${userId.replace(/'/g, "''")}'`);
    }
    const result = await client.query(query2, params);
    await client.query("COMMIT");
    return result.rows;
  } catch (error) {
    await client.query("ROLLBACK");
    throw error;
  } finally {
    releaseClient(client);
  }
}
async function queryOneWithRLS(query2, params = [], userId) {
  const rows = await queryWithRLS(query2, params, userId);
  return rows[0] || null;
}
async function mutateWithRLS(query2, params = [], userId) {
  const client = await acquireClient();
  try {
    await client.query("BEGIN");
    if (userId) {
      validateUserId(userId);
      await client.query(`SET LOCAL app.user_id = '${userId.replace(/'/g, "''")}'`);
    }
    const result = await client.query(query2, params);
    await client.query("COMMIT");
    return {
      rows: result.rows,
      rowCount: result.rowCount || 0
    };
  } catch (error) {
    await client.query("ROLLBACK");
    throw error;
  } finally {
    releaseClient(client);
  }
}
async function getTransactionClient(userId) {
  const client = await acquireClient();
  try {
    await client.query("BEGIN");
    if (userId) {
      validateUserId(userId);
      await client.query(`SET LOCAL app.user_id = '${userId.replace(/'/g, "''")}'`);
    }
  } catch (error) {
    releaseClient(client);
    throw error;
  }
  return {
    query: (query2, params = []) => client.query(query2, params).then((r) => r.rows),
    queryOne: (query2, params = []) => client.query(query2, params).then((r) => r.rows[0] || null),
    mutate: (query2, params = []) => client.query(query2, params).then((r) => ({ rows: r.rows, rowCount: r.rowCount || 0 })),
    commit: async () => {
      await client.query("COMMIT");
      releaseClient(client);
    },
    rollback: async () => {
      await client.query("ROLLBACK");
      releaseClient(client);
    }
  };
}
async function query(text, params) {
  const result = await pool.query(text, params);
  return {
    rows: result.rows,
    rowCount: result.rowCount || 0
  };
}
async function queryRows(text, params) {
  const result = await pool.query(text, params);
  return result.rows;
}
async function queryOne(text, params) {
  const result = await pool.query(text, params);
  return result.rows[0] || null;
}
function getPool() {
  if (isShuttingDown) {
    throw new Error("Database pool is shutting down. Cannot acquire new connections.");
  }
  return pool;
}
function isPoolHealthy() {
  if (isShuttingDown) {
    console.warn("[DB] Pool health check failed: shutting down");
    return false;
  }
  const maxConnections = pool.options.max || 20;
  const isExhausted = pool.totalCount >= maxConnections && pool.idleCount === 0 && pool.waitingCount > 10;
  if (isExhausted) {
    console.warn("[DB] Pool health check failed: pool exhausted", {
      total: pool.totalCount,
      idle: pool.idleCount,
      waiting: pool.waitingCount
    });
    return false;
  }
  return true;
}
function getPoolStats() {
  return {
    total: pool.totalCount,
    idle: pool.idleCount,
    waiting: pool.waitingCount,
    activeConnections,
    isShuttingDown
  };
}
async function gracefulShutdown(timeoutMs = 3e4) {
  if (shutdownPromise) {
    return shutdownPromise;
  }
  isShuttingDown = true;
  console.log("[DB] Initiating graceful database shutdown...");
  shutdownPromise = new Promise((resolve) => {
    const startTime = Date.now();
    let timeoutId = null;
    const checkAndClose = async () => {
      const elapsed = Date.now() - startTime;
      if (activeConnections === 0 || elapsed >= timeoutMs) {
        if (timeoutId) {
          clearTimeout(timeoutId);
          timeoutId = null;
        }
        if (activeConnections > 0) {
          console.warn(`[DB] Shutdown timeout reached. Forcing close with ${activeConnections} active connections.`);
        } else {
          console.log("[DB] All connections released. Closing pool...");
        }
        try {
          await pool.end();
          console.log("[DB] Database pool closed successfully.");
        } catch (error) {
          console.error("[DB] Error closing database pool:", error);
        }
        resolve();
        return;
      }
      timeoutId = setTimeout(checkAndClose, 100);
    };
    checkAndClose();
  });
  return shutdownPromise;
}
process.on("SIGTERM", async () => {
  console.log("[DB] SIGTERM received, initiating graceful shutdown...");
  await gracefulShutdown();
});
process.on("SIGINT", async () => {
  console.log("[DB] SIGINT received, initiating graceful shutdown...");
  await gracefulShutdown();
});
async function checkDatabaseConnection() {
  if (isShuttingDown) {
    return false;
  }
  try {
    const client = await acquireClient();
    await client.query("SELECT 1");
    releaseClient(client);
    return true;
  } catch (error) {
    console.error("Database connection failed:", error);
    return false;
  }
}
export {
  checkDatabaseConnection,
  getPool,
  getPoolStats,
  getTransactionClient,
  gracefulShutdown,
  isPoolHealthy,
  mutateWithRLS,
  parseSSLConfig,
  pool,
  query,
  queryOne,
  queryOneWithRLS,
  queryRows,
  queryWithRLS,
  stripSSLParams,
  validateUserId
};
