import "dotenv/config";

function required(name: string, fallback?: string): string {
  const value = process.env[name] ?? fallback;
  if (value === undefined) {
    throw new Error(`Missing required environment variable: ${name}`);
  }
  return value;
}

function intEnv(name: string, fallback: number): number {
  const raw = process.env[name];
  if (raw === undefined || raw.trim() === "") return fallback;
  const parsed = Number.parseInt(raw, 10);
  if (Number.isNaN(parsed)) throw new Error(`Environment variable ${name} must be an integer`);
  return parsed;
}

export const config = {
  env: required("NODE_ENV", "development"),
  isProduction: process.env.NODE_ENV === "production",
  isTest: process.env.NODE_ENV === "test",
  port: intEnv("PORT", 4000),
  db: {
    host: required("PGHOST", "127.0.0.1"),
    port: intEnv("PGPORT", 5433),
    // HARD SAFETY: integration tests (NODE_ENV=test) are pinned to the isolated
    // _test database regardless of any ambient PGDATABASE — this permanently closes
    // the incident path where a test run reset the operations database.
    database:
      process.env.NODE_ENV === "test"
        ? "bousla_ops_test"
        : required("PGDATABASE", "bousla_ops"),
    user: required("PGUSER", "bousla_app"),
    password: required("PGPASSWORD", ""),
  },
  session: {
    cookieName: required("SESSION_COOKIE_NAME", "bousla_session"),
    ttlMinutes: intEnv("SESSION_TTL_MINUTES", 240),
  },
  loginRate: {
    windowMinutes: intEnv("LOGIN_RATE_WINDOW_MINUTES", 15),
    max: process.env.NODE_ENV === "test" ? 1000 : intEnv("LOGIN_RATE_MAX", 10),
  },
  lockout: {
    minutes: intEnv("LOCKOUT_MINUTES", 15),
    maxAttempts: intEnv("LOCKOUT_MAX_ATTEMPTS", 5),
  },
  bcryptRounds: intEnv("BCRYPT_ROUNDS", 12),
} as const;
