import { readFile } from "node:fs/promises";

export async function resolveDeviceDatabaseUrl(
  environment = process.env,
  readSecret = readFile,
) {
  const explicit = optionalValue(environment.DEVICE_DATABASE_URL);
  if (explicit) return explicit;

  const host = restrictedValue(
    environment.DEVICE_DATABASE_HOST,
    /^[A-Za-z0-9.-]{1,253}$/,
    "device_database_host_invalid",
  );
  const port = parsePort(environment.DEVICE_DATABASE_PORT, 5432);
  const database = restrictedValue(
    environment.DEVICE_DATABASE_NAME,
    /^[A-Za-z_][A-Za-z0-9_-]{0,62}$/,
    "device_database_name_invalid",
  );
  const user = restrictedValue(
    environment.DEVICE_DATABASE_USER,
    /^[A-Za-z_][A-Za-z0-9_-]{0,62}$/,
    "device_database_user_invalid",
  );
  const passwordFile = requiredValue(
    environment.DEVICE_DATABASE_PASSWORD_FILE,
    "device_database_password_file_required",
  );
  const password = (await readSecret(passwordFile, "utf8")).trim();
  if (password.length < 32 || password.length > 512) {
    throw new Error("device_database_password_invalid");
  }

  return [
    "postgresql://",
    encodeURIComponent(user),
    ":",
    encodeURIComponent(password),
    "@",
    host,
    ":",
    String(port),
    "/",
    encodeURIComponent(database),
    "?sslmode=disable",
  ].join("");
}

function optionalValue(value) {
  if (typeof value !== "string") return "";
  return value.trim();
}

function requiredValue(value, errorCode) {
  const normalized = optionalValue(value);
  if (!normalized) throw new Error(errorCode);
  return normalized;
}

function restrictedValue(value, pattern, errorCode) {
  const normalized = requiredValue(value, errorCode);
  if (!pattern.test(normalized)) throw new Error(errorCode);
  return normalized;
}

function parsePort(value, fallback) {
  const parsed = Number(value || fallback);
  if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 65535) {
    throw new Error("device_database_port_invalid");
  }
  return parsed;
}
