Source: database/repositories/environmentRepo.js

import { getDatabase } from "../sqlite.js";

// `credentials` is stored as a JSON string in the DB — better-sqlite3 only
// accepts primitive bound parameters, so we serialise on write and parse
// on read. Mirrors the projectRepo pattern (projectRepo.js:17-42).
function rowToEnv(row) {
  if (!row) return row;
  return {
    ...row,
    credentials: row.credentials ? JSON.parse(row.credentials) : null,
  };
}

function envToRow(env) {
  return {
    ...env,
    credentials: env.credentials ? JSON.stringify(env.credentials) : null,
  };
}

export function create(env) {
  const db = getDatabase();
  db.prepare(`INSERT INTO environments (id, projectId, name, baseUrl, credentials, createdAt, workspaceId)
    VALUES (@id, @projectId, @name, @baseUrl, @credentials, @createdAt, @workspaceId)`).run(envToRow(env));
}

export function listByProject(projectId) {
  const db = getDatabase();
  return db.prepare("SELECT * FROM environments WHERE projectId = ? ORDER BY createdAt ASC").all(projectId).map(rowToEnv);
}

/**
 * Batch-fetch environments for a set of project IDs in one SQL round-trip.
 * Returns rows in the same order SQLite produces them; callers that need a
 * per-project map can group on `row.projectId`.
 *
 * Added for the dashboard's per-environment pass-rate aggregation
 * (`routes/dashboard.js`) — the previous per-project loop issued N+1
 * `listByProject` queries which scaled poorly on workspaces with many
 * projects. Mirrors the pattern in `githubCheckSettingsRepo.listByProjectIds`.
 *
 * @param {string[]} projectIds
 * @returns {Object[]} environment rows (credentials JSON-parsed, still
 *   AES-encrypted — call `decryptCredentials()` to peel that layer).
 */
export function listByProjectIds(projectIds) {
  if (!projectIds?.length) return [];
  const db = getDatabase();
  const placeholders = projectIds.map(() => "?").join(", ");
  return db
    .prepare(`SELECT * FROM environments WHERE projectId IN (${placeholders}) ORDER BY projectId, createdAt ASC`)
    .all(...projectIds)
    .map(rowToEnv);
}

export function getById(id) {
  const db = getDatabase();
  return rowToEnv(db.prepare("SELECT * FROM environments WHERE id = ?").get(id));
}

export function update(id, fields) {
  const db = getDatabase();
  const allowed = ["name", "baseUrl", "credentials"];
  const keys = Object.keys(fields || {}).filter((k) => allowed.includes(k));
  if (!keys.length) return;
  const params = { id };
  for (const k of keys) {
    params[k] = k === "credentials" && fields[k] ? JSON.stringify(fields[k]) : fields[k];
  }
  const setSql = keys.map((k) => `${k}=@${k}`).join(", ");
  db.prepare(`UPDATE environments SET ${setSql} WHERE id=@id`).run(params);
}

export function remove(id) {
  const db = getDatabase();
  db.prepare("DELETE FROM environments WHERE id = ?").run(id);
}