const { Pool } = require('pg');

const parseBoolean = (value, fallback = false) => {
  if (typeof value !== 'string') return fallback;
  const normalized = value.trim().toLowerCase();
  if (['1', 'true', 'yes', 'on'].includes(normalized)) return true;
  if (['0', 'false', 'no', 'off'].includes(normalized)) return false;
  return fallback;
};

const buildDatabaseUrlFromParts = () => {
  const host = (process.env.POSTGRES_HOST || 'postgres').trim();
  const port = Number(process.env.POSTGRES_PORT || 5432);
  const database = (process.env.POSTGRES_DB || 'greenlns').trim();
  const user = (process.env.POSTGRES_USER || 'greenlns').trim();
  const password = process.env.POSTGRES_PASSWORD;
  if (!password) {
    return '';
  }

  return `postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${host}:${port}/${encodeURIComponent(database)}`;
};

const getDefaultDbPath = () => {
  return (process.env.DATABASE_URL || buildDatabaseUrlFromParts()).trim();
};

const getPoolConfig = () => {
  const connectionString = getDefaultDbPath();
  if (!connectionString) {
    throw new Error('DATABASE_URL or POSTGRES_* environment variables are required.');
  }

  const sslEnabled = parseBoolean(process.env.DATABASE_SSL, false);
  return {
    connectionString,
    max: Number(process.env.PGPOOL_MAX || 10),
    ssl: sslEnabled ? { rejectUnauthorized: false } : false,
  };
};

const translateSql = (sql) => {
  if (typeof sql !== 'string') return sql;

  let placeholderIndex = 0;
  return sql
    .replace(/\?/g, () => {
      placeholderIndex += 1;
      return `$${placeholderIndex}`;
    })
    .replace(/BEGIN\s+IMMEDIATE\s+TRANSACTION/gi, 'BEGIN')
    .replace(/datetime\('now'\)/gi, 'CURRENT_TIMESTAMP')
    .replace(/\s+COLLATE\s+NOCASE/gi, '');
};

const openDatabase = async () => {
  const pool = new Pool(getPoolConfig());
  await pool.query('SELECT 1');
  return pool;
};

const closeDatabase = async (db) => {
  if (!db || typeof db.end !== 'function') return;
  await db.end();
};

const run = async (db, sql, params = []) => {
  const result = await db.query(translateSql(sql), params);
  return {
    lastId: result.rows?.[0]?.id ?? null,
    changes: result.rowCount || 0,
    rows: result.rows || [],
  };
};

const get = async (db, sql, params = []) => {
  const result = await db.query(translateSql(sql), params);
  return result.rows[0] || null;
};

const all = async (db, sql, params = []) => {
  const result = await db.query(translateSql(sql), params);
  return result.rows || [];
};

module.exports = {
  all,
  closeDatabase,
  get,
  getDefaultDbPath,
  openDatabase,
  run,
};
