import { z } from "zod";
import { BoolEnv } from "./utils/boolEnv";
import { isValidDatabaseUrl } from "./utils/db";
import { isValidRegex } from "./utils/regex";

const GithubAppEnvSchema = z.preprocess(
  (val) => {
    const obj = val as any;
    if (!obj || !obj.GITHUB_APP_ENABLED) {
      return { ...obj, GITHUB_APP_ENABLED: "0" };
    }
    return obj;
  },
  z.discriminatedUnion("GITHUB_APP_ENABLED", [
    z.object({
      GITHUB_APP_ENABLED: z.literal("1"),
      GITHUB_APP_ID: z.string(),
      GITHUB_APP_PRIVATE_KEY: z.string(),
      GITHUB_APP_WEBHOOK_SECRET: z.string(),
      GITHUB_APP_SLUG: z.string(),
    }),
    z.object({
      GITHUB_APP_ENABLED: z.literal("0"),
    }),
  ])
);

// eventually we can make all S2 env vars required once the S2 OSS version is out
const S2EnvSchema = z.preprocess(
  (val) => {
    const obj = val as any;
    if (!obj || !obj.S2_ENABLED) {
      return { ...obj, S2_ENABLED: "0" };
    }
    return obj;
  },
  z.discriminatedUnion("S2_ENABLED", [
    z.object({
      S2_ENABLED: z.literal("1"),
      S2_ACCESS_TOKEN: z.string(),
      S2_DEPLOYMENT_LOGS_BASIN_NAME: z.string(),
    }),
    z.object({
      S2_ENABLED: z.literal("0"),
    }),
  ])
);

const EnvironmentSchema = z
  .object({
    NODE_ENV: z.union([z.literal("development"), z.literal("production"), z.literal("test")]),
    DATABASE_URL: z
      .string()
      .refine(
        isValidDatabaseUrl,
        "DATABASE_URL is invalid, for details please check the additional output above this message."
      ),
    DATABASE_CONNECTION_LIMIT: z.coerce.number().int().default(10),
    DATABASE_POOL_TIMEOUT: z.coerce.number().int().default(60),
    DATABASE_CONNECTION_TIMEOUT: z.coerce.number().int().default(20),
    DIRECT_URL: z
      .string()
      .refine(
        isValidDatabaseUrl,
        "DIRECT_URL is invalid, for details please check the additional output above this message."
      ),
    DATABASE_READ_REPLICA_URL: z.string().optional(),
    SESSION_SECRET: z.string(),
    MAGIC_LINK_SECRET: z.string(),
    ENCRYPTION_KEY: z
      .string()
      .refine(
        (val) => Buffer.from(val, "utf8").length === 32,
        "ENCRYPTION_KEY must be exactly 32 bytes"
      ),
    WHITELISTED_EMAILS: z
      .string()
      .refine(isValidRegex, "WHITELISTED_EMAILS must be a valid regex.")
      .optional(),
    ADMIN_EMAILS: z.string().refine(isValidRegex, "ADMIN_EMAILS must be a valid regex.").optional(),
    REMIX_APP_PORT: z.string().optional(),
    LOGIN_ORIGIN: z.string().default("http://localhost:3030"),
    LOGIN_RATE_LIMITS_ENABLED: BoolEnv.default(true),
    APP_ORIGIN: z.string().default("http://localhost:3030"),
    API_ORIGIN: z.string().optional(),
    STREAM_ORIGIN: z.string().optional(),
    ELECTRIC_ORIGIN: z.string().default("http://localhost:3060"),
    // A comma separated list of electric origins to shard into different electric instances by environmentId
    // example: "http://localhost:3060,http://localhost:3061,http://localhost:3062"
    ELECTRIC_ORIGIN_SHARDS: z.string().optional(),
    APP_ENV: z.string().default(process.env.NODE_ENV),
    SERVICE_NAME: z.string().default("trigger.dev webapp"),
    POSTHOG_PROJECT_KEY: z.string().default("phc_LFH7kJiGhdIlnO22hTAKgHpaKhpM8gkzWAFvHmf5vfS"),
    TRIGGER_TELEMETRY_DISABLED: z.string().optional(),
    AUTH_GITHUB_CLIENT_ID: z.string().optional(),
    AUTH_GITHUB_CLIENT_SECRET: z.string().optional(),
    AUTH_GOOGLE_CLIENT_ID: z.string().optional(),
    AUTH_GOOGLE_CLIENT_SECRET: z.string().optional(),
    EMAIL_TRANSPORT: z.enum(["resend", "smtp", "aws-ses"]).optional(),
    FROM_EMAIL: z.string().optional(),
    REPLY_TO_EMAIL: z.string().optional(),
    RESEND_API_KEY: z.string().optional(),
    SMTP_HOST: z.string().optional(),
    SMTP_PORT: z.coerce.number().optional(),
    SMTP_SECURE: BoolEnv.optional(),
    SMTP_USER: z.string().optional(),
    SMTP_PASSWORD: z.string().optional(),

    PLAIN_API_KEY: z.string().optional(),
    WORKER_SCHEMA: z.string().default("graphile_worker"),
    WORKER_CONCURRENCY: z.coerce.number().int().default(10),
    WORKER_POLL_INTERVAL: z.coerce.number().int().default(1000),
    WORKER_ENABLED: z.string().default("true"),
    GRACEFUL_SHUTDOWN_TIMEOUT: z.coerce.number().int().default(60000),
    DISABLE_SSE: z.string().optional(),
    OPENAI_API_KEY: z.string().optional(),

    // Redis options
    REDIS_HOST: z.string().optional(),
    REDIS_READER_HOST: z.string().optional(),
    REDIS_READER_PORT: z.coerce.number().optional(),
    REDIS_PORT: z.coerce.number().optional(),
    REDIS_USERNAME: z.string().optional(),
    REDIS_PASSWORD: z.string().optional(),
    REDIS_TLS_DISABLED: z.string().optional(),

    RATE_LIMIT_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    RATE_LIMIT_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    RATE_LIMIT_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    RATE_LIMIT_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    RATE_LIMIT_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    RATE_LIMIT_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    RATE_LIMIT_REDIS_TLS_DISABLED: z.string().default(process.env.REDIS_TLS_DISABLED ?? "false"),
    RATE_LIMIT_REDIS_CLUSTER_MODE_ENABLED: z.string().default("0"),

    CACHE_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    CACHE_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    CACHE_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    CACHE_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    CACHE_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    CACHE_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    CACHE_REDIS_TLS_DISABLED: z.string().default(process.env.REDIS_TLS_DISABLED ?? "false"),
    CACHE_REDIS_CLUSTER_MODE_ENABLED: z.string().default("0"),

    REALTIME_STREAMS_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    REALTIME_STREAMS_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    REALTIME_STREAMS_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    REALTIME_STREAMS_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    REALTIME_STREAMS_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    REALTIME_STREAMS_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    REALTIME_STREAMS_REDIS_TLS_DISABLED: z
      .string()
      .default(process.env.REDIS_TLS_DISABLED ?? "false"),
    REALTIME_STREAMS_REDIS_CLUSTER_MODE_ENABLED: z.string().default("0"),
    REALTIME_STREAMS_INACTIVITY_TIMEOUT_MS: z.coerce.number().int().default(60000), // 1 minute

    REALTIME_MAXIMUM_CREATED_AT_FILTER_AGE_IN_MS: z.coerce
      .number()
      .int()
      .default(24 * 60 * 60 * 1000), // 1 day in milliseconds

    PUBSUB_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    PUBSUB_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    PUBSUB_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    PUBSUB_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    PUBSUB_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    PUBSUB_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    PUBSUB_REDIS_TLS_DISABLED: z.string().default(process.env.REDIS_TLS_DISABLED ?? "false"),
    PUBSUB_REDIS_CLUSTER_MODE_ENABLED: z.string().default("0"),

    DEFAULT_ENV_EXECUTION_CONCURRENCY_LIMIT: z.coerce.number().int().default(100),
    DEFAULT_ENV_EXECUTION_CONCURRENCY_BURST_FACTOR: z.coerce.number().default(1.0),
    DEFAULT_ORG_EXECUTION_CONCURRENCY_LIMIT: z.coerce.number().int().default(300),
    DEFAULT_DEV_ENV_EXECUTION_ATTEMPTS: z.coerce.number().int().positive().default(1),

    //API Rate limiting
    /**
     * @example "60s"
     * @example "1m"
     * @example "1h"
     * @example "1d"
     * @example "1000ms"
     * @example "1000s"
     */
    API_RATE_LIMIT_REFILL_INTERVAL: z.string().default("10s"), // refill 250 tokens every 10 seconds
    API_RATE_LIMIT_MAX: z.coerce.number().int().default(750), // allow bursts of 750 requests
    API_RATE_LIMIT_REFILL_RATE: z.coerce.number().int().default(250), // refix 250 tokens every 10 seconds
    API_RATE_LIMIT_REQUEST_LOGS_ENABLED: z.string().default("0"),
    API_RATE_LIMIT_REJECTION_LOGS_ENABLED: z.string().default("1"),
    API_RATE_LIMIT_LIMITER_LOGS_ENABLED: z.string().default("0"),

    API_RATE_LIMIT_JWT_WINDOW: z.string().default("1m"),
    API_RATE_LIMIT_JWT_TOKENS: z.coerce.number().int().default(60),

    //v3
    PROVIDER_SECRET: z.string().default("provider-secret"),
    COORDINATOR_SECRET: z.string().default("coordinator-secret"),
    DEPOT_TOKEN: z.string().optional(),
    DEPOT_ORG_ID: z.string().optional(),
    DEPOT_REGION: z.string().default("us-east-1"),

    // Deployment registry (v3)
    DEPLOY_REGISTRY_HOST: z.string().min(1),
    DEPLOY_REGISTRY_USERNAME: z.string().optional(),
    DEPLOY_REGISTRY_PASSWORD: z.string().optional(),
    DEPLOY_REGISTRY_NAMESPACE: z.string().min(1).default("trigger"),
    DEPLOY_REGISTRY_ECR_TAGS: z.string().optional(), // csv, for example: "key1=value1,key2=value2"
    DEPLOY_REGISTRY_ECR_ASSUME_ROLE_ARN: z.string().optional(),
    DEPLOY_REGISTRY_ECR_ASSUME_ROLE_EXTERNAL_ID: z.string().optional(),

    // Deployment registry (v4) - falls back to v3 registry if not specified
    V4_DEPLOY_REGISTRY_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.DEPLOY_REGISTRY_HOST)
      .pipe(z.string().min(1)), // Ensure final type is required string
    V4_DEPLOY_REGISTRY_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.DEPLOY_REGISTRY_USERNAME),
    V4_DEPLOY_REGISTRY_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.DEPLOY_REGISTRY_PASSWORD),
    V4_DEPLOY_REGISTRY_NAMESPACE: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.DEPLOY_REGISTRY_NAMESPACE)
      .pipe(z.string().min(1).default("trigger")), // Ensure final type is required string
    V4_DEPLOY_REGISTRY_ECR_TAGS: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.DEPLOY_REGISTRY_ECR_TAGS),
    V4_DEPLOY_REGISTRY_ECR_ASSUME_ROLE_ARN: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.DEPLOY_REGISTRY_ECR_ASSUME_ROLE_ARN),
    V4_DEPLOY_REGISTRY_ECR_ASSUME_ROLE_EXTERNAL_ID: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.DEPLOY_REGISTRY_ECR_ASSUME_ROLE_EXTERNAL_ID),

    DEPLOY_IMAGE_PLATFORM: z.string().default("linux/amd64"),
    DEPLOY_TIMEOUT_MS: z.coerce
      .number()
      .int()
      .default(60 * 1000 * 8), // 8 minutes
    DEPLOY_QUEUE_TIMEOUT_MS: z.coerce
      .number()
      .int()
      .default(60 * 1000 * 15), // 15 minutes

    OBJECT_STORE_BASE_URL: z.string().optional(),
    OBJECT_STORE_ACCESS_KEY_ID: z.string().optional(),
    OBJECT_STORE_SECRET_ACCESS_KEY: z.string().optional(),
    OBJECT_STORE_REGION: z.string().optional(),
    OBJECT_STORE_SERVICE: z.string().default("s3"),

    ARTIFACTS_OBJECT_STORE_BUCKET: z.string().optional(),
    ARTIFACTS_OBJECT_STORE_BASE_URL: z.string().optional(),
    ARTIFACTS_OBJECT_STORE_ACCESS_KEY_ID: z.string().optional(),
    ARTIFACTS_OBJECT_STORE_SECRET_ACCESS_KEY: z.string().optional(),
    ARTIFACTS_OBJECT_STORE_REGION: z.string().optional(),
    EVENTS_BATCH_SIZE: z.coerce.number().int().default(100),
    EVENTS_BATCH_INTERVAL: z.coerce.number().int().default(1000),
    EVENTS_DEFAULT_LOG_RETENTION: z.coerce.number().int().default(7),
    EVENTS_MIN_CONCURRENCY: z.coerce.number().int().default(1),
    EVENTS_MAX_CONCURRENCY: z.coerce.number().int().default(10),
    EVENTS_MAX_BATCH_SIZE: z.coerce.number().int().default(500),
    EVENTS_MEMORY_PRESSURE_THRESHOLD: z.coerce.number().int().default(5000),
    EVENTS_LOAD_SHEDDING_THRESHOLD: z.coerce.number().int().default(100000),
    EVENTS_LOAD_SHEDDING_ENABLED: z.string().default("1"),
    SHARED_QUEUE_CONSUMER_POOL_SIZE: z.coerce.number().int().default(10),
    SHARED_QUEUE_CONSUMER_INTERVAL_MS: z.coerce.number().int().default(100),
    SHARED_QUEUE_CONSUMER_NEXT_TICK_INTERVAL_MS: z.coerce.number().int().default(100),
    SHARED_QUEUE_CONSUMER_EMIT_RESUME_DEPENDENCY_TIMEOUT_MS: z.coerce.number().int().default(1000),
    SHARED_QUEUE_CONSUMER_RESOLVE_PAYLOADS_BATCH_SIZE: z.coerce.number().int().default(25),

    MANAGED_WORKER_SECRET: z.string().default("managed-secret"),

    // Development OTEL environment variables
    DEV_OTEL_EXPORTER_OTLP_ENDPOINT: z.string().optional(),
    // If this is set to 1, then the below variables are used to configure the batch processor for spans and logs
    DEV_OTEL_BATCH_PROCESSING_ENABLED: z.string().default("0"),
    DEV_OTEL_SPAN_MAX_EXPORT_BATCH_SIZE: z.string().default("64"),
    DEV_OTEL_SPAN_SCHEDULED_DELAY_MILLIS: z.string().default("200"),
    DEV_OTEL_SPAN_EXPORT_TIMEOUT_MILLIS: z.string().default("30000"),
    DEV_OTEL_SPAN_MAX_QUEUE_SIZE: z.string().default("512"),
    DEV_OTEL_LOG_MAX_EXPORT_BATCH_SIZE: z.string().default("64"),
    DEV_OTEL_LOG_SCHEDULED_DELAY_MILLIS: z.string().default("200"),
    DEV_OTEL_LOG_EXPORT_TIMEOUT_MILLIS: z.string().default("30000"),
    DEV_OTEL_LOG_MAX_QUEUE_SIZE: z.string().default("512"),

    PROD_OTEL_BATCH_PROCESSING_ENABLED: z.string().default("0"),
    PROD_OTEL_SPAN_MAX_EXPORT_BATCH_SIZE: z.string().default("64"),
    PROD_OTEL_SPAN_SCHEDULED_DELAY_MILLIS: z.string().default("200"),
    PROD_OTEL_SPAN_EXPORT_TIMEOUT_MILLIS: z.string().default("30000"),
    PROD_OTEL_SPAN_MAX_QUEUE_SIZE: z.string().default("512"),
    PROD_OTEL_LOG_MAX_EXPORT_BATCH_SIZE: z.string().default("64"),
    PROD_OTEL_LOG_SCHEDULED_DELAY_MILLIS: z.string().default("200"),
    PROD_OTEL_LOG_EXPORT_TIMEOUT_MILLIS: z.string().default("30000"),
    PROD_OTEL_LOG_MAX_QUEUE_SIZE: z.string().default("512"),

    TRIGGER_OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT: z.string().default("1024"),
    TRIGGER_OTEL_LOG_ATTRIBUTE_COUNT_LIMIT: z.string().default("1024"),
    TRIGGER_OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT: z.string().default("131072"),
    TRIGGER_OTEL_LOG_ATTRIBUTE_VALUE_LENGTH_LIMIT: z.string().default("131072"),
    TRIGGER_OTEL_SPAN_EVENT_COUNT_LIMIT: z.string().default("10"),
    TRIGGER_OTEL_LINK_COUNT_LIMIT: z.string().default("2"),
    TRIGGER_OTEL_ATTRIBUTE_PER_LINK_COUNT_LIMIT: z.string().default("10"),
    TRIGGER_OTEL_ATTRIBUTE_PER_EVENT_COUNT_LIMIT: z.string().default("10"),

    CHECKPOINT_THRESHOLD_IN_MS: z.coerce.number().int().default(30000),

    // Internal OTEL environment variables
    INTERNAL_OTEL_TRACE_EXPORTER_URL: z.string().optional(),
    INTERNAL_OTEL_TRACE_EXPORTER_AUTH_HEADERS: z.string().optional(),
    INTERNAL_OTEL_TRACE_LOGGING_ENABLED: z.string().default("1"),
    // this means 1/20 traces or 5% of traces will be sampled (sampled = recorded)
    INTERNAL_OTEL_TRACE_SAMPLING_RATE: z.string().default("20"),
    INTERNAL_OTEL_TRACE_INSTRUMENT_PRISMA_ENABLED: z.string().default("0"),
    INTERNAL_OTEL_TRACE_DISABLED: z.string().default("0"),

    INTERNAL_OTEL_LOG_EXPORTER_URL: z.string().optional(),
    INTERNAL_OTEL_METRIC_EXPORTER_URL: z.string().optional(),
    INTERNAL_OTEL_METRIC_EXPORTER_AUTH_HEADERS: z.string().optional(),
    INTERNAL_OTEL_METRIC_EXPORTER_ENABLED: z.string().default("0"),
    INTERNAL_OTEL_METRIC_EXPORTER_INTERVAL_MS: z.coerce.number().int().default(30_000),
    INTERNAL_OTEL_HOST_METRICS_ENABLED: BoolEnv.default(true),
    INTERNAL_OTEL_NODEJS_METRICS_ENABLED: BoolEnv.default(true),
    INTERNAL_OTEL_ADDITIONAL_DETECTORS_ENABLED: BoolEnv.default(true),

    ORG_SLACK_INTEGRATION_CLIENT_ID: z.string().optional(),
    ORG_SLACK_INTEGRATION_CLIENT_SECRET: z.string().optional(),

    /** These enable the alerts feature in v3 */
    ALERT_EMAIL_TRANSPORT: z.enum(["resend", "smtp", "aws-ses"]).optional(),
    ALERT_FROM_EMAIL: z.string().optional(),
    ALERT_REPLY_TO_EMAIL: z.string().optional(),
    ALERT_RESEND_API_KEY: z.string().optional(),
    ALERT_SMTP_HOST: z.string().optional(),
    ALERT_SMTP_PORT: z.coerce.number().optional(),
    ALERT_SMTP_SECURE: BoolEnv.optional(),
    ALERT_SMTP_USER: z.string().optional(),
    ALERT_SMTP_PASSWORD: z.string().optional(),
    ALERT_RATE_LIMITER_EMISSION_INTERVAL: z.coerce.number().int().default(2_500),
    ALERT_RATE_LIMITER_BURST_TOLERANCE: z.coerce.number().int().default(10_000),
    ALERT_RATE_LIMITER_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    ALERT_RATE_LIMITER_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    ALERT_RATE_LIMITER_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    ALERT_RATE_LIMITER_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    ALERT_RATE_LIMITER_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    ALERT_RATE_LIMITER_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    ALERT_RATE_LIMITER_REDIS_TLS_DISABLED: z
      .string()
      .default(process.env.REDIS_TLS_DISABLED ?? "false"),
    ALERT_RATE_LIMITER_REDIS_CLUSTER_MODE_ENABLED: z.string().default("0"),

    LOOPS_API_KEY: z.string().optional(),
    MARQS_DISABLE_REBALANCING: BoolEnv.default(false),
    MARQS_VISIBILITY_TIMEOUT_MS: z.coerce
      .number()
      .int()
      .default(60 * 1000 * 15),
    MARQS_SHARED_QUEUE_LIMIT: z.coerce.number().int().default(1000),
    MARQS_MAXIMUM_QUEUE_PER_ENV_COUNT: z.coerce.number().int().default(50),
    MARQS_DEV_QUEUE_LIMIT: z.coerce.number().int().default(1000),
    MARQS_MAXIMUM_NACK_COUNT: z.coerce.number().int().default(64),
    MARQS_CONCURRENCY_LIMIT_BIAS: z.coerce.number().default(0.75),
    MARQS_AVAILABLE_CAPACITY_BIAS: z.coerce.number().default(0.3),
    MARQS_QUEUE_AGE_RANDOMIZATION_BIAS: z.coerce.number().default(0.25),
    MARQS_REUSE_SNAPSHOT_COUNT: z.coerce.number().int().default(0),
    MARQS_MAXIMUM_ENV_COUNT: z.coerce.number().int().optional(),
    MARQS_SHARED_WORKER_QUEUE_CONSUMER_INTERVAL_MS: z.coerce.number().int().default(250),
    MARQS_SHARED_WORKER_QUEUE_MAX_MESSAGE_COUNT: z.coerce.number().int().default(10),

    MARQS_SHARED_WORKER_QUEUE_EAGER_DEQUEUE_ENABLED: z.string().default("0"),
    MARQS_WORKER_ENABLED: z.string().default("0"),
    MARQS_WORKER_COUNT: z.coerce.number().int().default(2),
    MARQS_WORKER_CONCURRENCY_LIMIT: z.coerce.number().int().default(50),
    MARQS_WORKER_CONCURRENCY_TASKS_PER_WORKER: z.coerce.number().int().default(5),
    MARQS_WORKER_POLL_INTERVAL_MS: z.coerce.number().int().default(100),
    MARQS_WORKER_IMMEDIATE_POLL_INTERVAL_MS: z.coerce.number().int().default(100),
    MARQS_WORKER_SHUTDOWN_TIMEOUT_MS: z.coerce.number().int().default(60_000),
    MARQS_SHARED_WORKER_QUEUE_COOLOFF_COUNT_THRESHOLD: z.coerce.number().int().default(10),
    MARQS_SHARED_WORKER_QUEUE_COOLOFF_PERIOD_MS: z.coerce.number().int().default(5_000),

    PROD_TASK_HEARTBEAT_INTERVAL_MS: z.coerce.number().int().optional(),

    VERBOSE_GRAPHILE_LOGGING: z.string().default("false"),
    V2_MARQS_ENABLED: z.string().default("0"),
    V2_MARQS_CONSUMER_POOL_ENABLED: z.string().default("0"),
    V2_MARQS_CONSUMER_POOL_SIZE: z.coerce.number().int().default(10),
    V2_MARQS_CONSUMER_POLL_INTERVAL_MS: z.coerce.number().int().default(1000),
    V2_MARQS_QUEUE_SELECTION_COUNT: z.coerce.number().int().default(36),
    V2_MARQS_VISIBILITY_TIMEOUT_MS: z.coerce
      .number()
      .int()
      .default(60 * 1000 * 15),
    V2_MARQS_DEFAULT_ENV_CONCURRENCY: z.coerce.number().int().default(100),
    V2_MARQS_VERBOSE: z.string().default("0"),
    V3_MARQS_CONCURRENCY_MONITOR_ENABLED: z.string().default("0"),
    V2_MARQS_CONCURRENCY_MONITOR_ENABLED: z.string().default("0"),
    /* Usage settings */
    USAGE_EVENT_URL: z.string().optional(),
    PROD_USAGE_HEARTBEAT_INTERVAL_MS: z.coerce.number().int().optional(),

    CENTS_PER_RUN: z.coerce.number().default(0),
    CENTS_PER_QUERY_BYTE_SECOND: z.coerce.number().default(0),

    EVENT_LOOP_MONITOR_ENABLED: z.string().default("1"),
    RESOURCE_MONITOR_ENABLED: z.string().default("0"),
    MAXIMUM_LIVE_RELOADING_EVENTS: z.coerce.number().int().default(1000),
    MAXIMUM_TRACE_SUMMARY_VIEW_COUNT: z.coerce.number().int().default(25_000),
    MAXIMUM_TRACE_DETAILED_SUMMARY_VIEW_COUNT: z.coerce.number().int().default(10_000),
    TASK_PAYLOAD_OFFLOAD_THRESHOLD: z.coerce.number().int().default(524_288), // 512KB
    BATCH_PAYLOAD_OFFLOAD_THRESHOLD: z.coerce.number().int().optional(), // Defaults to TASK_PAYLOAD_OFFLOAD_THRESHOLD if not set
    TASK_PAYLOAD_MAXIMUM_SIZE: z.coerce.number().int().default(3_145_728), // 3MB
    BATCH_TASK_PAYLOAD_MAXIMUM_SIZE: z.coerce.number().int().default(1_000_000), // 1MB
    TASK_RUN_METADATA_MAXIMUM_SIZE: z.coerce.number().int().default(262_144), // 256KB

    MAXIMUM_DEV_QUEUE_SIZE: z.coerce.number().int().optional(),
    MAXIMUM_DEPLOYED_QUEUE_SIZE: z.coerce.number().int().optional(),
    MAX_BATCH_V2_TRIGGER_ITEMS: z.coerce.number().int().default(500),
    MAX_BATCH_AND_WAIT_V2_TRIGGER_ITEMS: z.coerce.number().int().default(500),

    // 2-phase batch API settings
    STREAMING_BATCH_MAX_ITEMS: z.coerce.number().int().default(1_000), // Max items in streaming batch
    STREAMING_BATCH_ITEM_MAXIMUM_SIZE: z.coerce.number().int().default(3_145_728),
    BATCH_RATE_LIMIT_REFILL_RATE: z.coerce.number().int().default(100),
    BATCH_RATE_LIMIT_MAX: z.coerce.number().int().default(1200),
    BATCH_RATE_LIMIT_REFILL_INTERVAL: z.string().default("10s"),
    BATCH_CONCURRENCY_LIMIT_DEFAULT: z.coerce.number().int().default(1),

    REALTIME_STREAM_VERSION: z.enum(["v1", "v2"]).default("v1"),
    REALTIME_STREAM_MAX_LENGTH: z.coerce.number().int().default(1000),
    REALTIME_STREAM_TTL: z.coerce
      .number()
      .int()
      .default(60 * 60 * 24), // 1 day in seconds
    BATCH_METADATA_OPERATIONS_FLUSH_INTERVAL_MS: z.coerce.number().int().default(1000),
    BATCH_METADATA_OPERATIONS_FLUSH_ENABLED: z.string().default("1"),
    BATCH_METADATA_OPERATIONS_FLUSH_LOGGING_ENABLED: z.string().default("1"),

    // Run Engine 2.0
    RUN_ENGINE_WORKER_COUNT: z.coerce.number().int().default(4),
    RUN_ENGINE_TASKS_PER_WORKER: z.coerce.number().int().default(10),
    RUN_ENGINE_WORKER_CONCURRENCY_LIMIT: z.coerce.number().int().default(10),
    RUN_ENGINE_WORKER_POLL_INTERVAL: z.coerce.number().int().default(100),
    RUN_ENGINE_WORKER_IMMEDIATE_POLL_INTERVAL: z.coerce.number().int().default(100),
    RUN_ENGINE_TIMEOUT_PENDING_EXECUTING: z.coerce.number().int().default(60_000),
    RUN_ENGINE_TIMEOUT_PENDING_CANCEL: z.coerce.number().int().default(60_000),
    RUN_ENGINE_TIMEOUT_EXECUTING: z.coerce.number().int().default(300_000), // 5 minutes
    RUN_ENGINE_TIMEOUT_EXECUTING_WITH_WAITPOINTS: z.coerce.number().int().default(300_000), // 5 minutes
    RUN_ENGINE_TIMEOUT_SUSPENDED: z.coerce
      .number()
      .int()
      .default(60_000 * 10),
    RUN_ENGINE_DEBUG_WORKER_NOTIFICATIONS: BoolEnv.default(false),
    RUN_ENGINE_PARENT_QUEUE_LIMIT: z.coerce.number().int().default(1000),
    RUN_ENGINE_CONCURRENCY_LIMIT_BIAS: z.coerce.number().default(0.75),
    RUN_ENGINE_AVAILABLE_CAPACITY_BIAS: z.coerce.number().default(0.3),
    RUN_ENGINE_QUEUE_AGE_RANDOMIZATION_BIAS: z.coerce.number().default(0.25),
    RUN_ENGINE_REUSE_SNAPSHOT_COUNT: z.coerce.number().int().default(0),
    RUN_ENGINE_MAXIMUM_ENV_COUNT: z.coerce.number().int().optional(),
    RUN_ENGINE_RUN_QUEUE_SHARD_COUNT: z.coerce.number().int().default(4),
    RUN_ENGINE_WORKER_SHUTDOWN_TIMEOUT_MS: z.coerce.number().int().default(60_000),
    RUN_ENGINE_RETRY_WARM_START_THRESHOLD_MS: z.coerce.number().int().default(30_000),
    RUN_ENGINE_PROCESS_WORKER_QUEUE_DEBOUNCE_MS: z.coerce.number().int().default(200),
    RUN_ENGINE_DEQUEUE_BLOCKING_TIMEOUT_SECONDS: z.coerce.number().int().default(10),
    RUN_ENGINE_MASTER_QUEUE_CONSUMERS_INTERVAL_MS: z.coerce.number().int().default(1000),
    RUN_ENGINE_MASTER_QUEUE_COOLOFF_PERIOD_MS: z.coerce.number().int().default(10_000),
    RUN_ENGINE_MASTER_QUEUE_COOLOFF_COUNT_THRESHOLD: z.coerce.number().int().default(10),
    RUN_ENGINE_MASTER_QUEUE_CONSUMER_DEQUEUE_COUNT: z.coerce.number().int().default(10),
    RUN_ENGINE_CONCURRENCY_SWEEPER_SCAN_SCHEDULE: z.string().optional(),
    RUN_ENGINE_CONCURRENCY_SWEEPER_PROCESS_MARKED_SCHEDULE: z.string().optional(),
    RUN_ENGINE_CONCURRENCY_SWEEPER_SCAN_JITTER_IN_MS: z.coerce.number().int().optional(),
    RUN_ENGINE_CONCURRENCY_SWEEPER_PROCESS_MARKED_JITTER_IN_MS: z.coerce.number().int().optional(),

    RUN_ENGINE_RUN_LOCK_DURATION: z.coerce.number().int().default(5000),
    RUN_ENGINE_RUN_LOCK_AUTOMATIC_EXTENSION_THRESHOLD: z.coerce.number().int().default(1000),
    RUN_ENGINE_RUN_LOCK_MAX_RETRIES: z.coerce.number().int().default(10),
    RUN_ENGINE_RUN_LOCK_BASE_DELAY: z.coerce.number().int().default(100),
    RUN_ENGINE_RUN_LOCK_MAX_DELAY: z.coerce.number().int().default(3000),
    RUN_ENGINE_RUN_LOCK_BACKOFF_MULTIPLIER: z.coerce.number().default(1.8),
    RUN_ENGINE_RUN_LOCK_JITTER_FACTOR: z.coerce.number().default(0.15),
    RUN_ENGINE_RUN_LOCK_MAX_TOTAL_WAIT_TIME: z.coerce.number().int().default(15000),

    RUN_ENGINE_SUSPENDED_HEARTBEAT_RETRIES_MAX_COUNT: z.coerce.number().int().default(12),
    RUN_ENGINE_SUSPENDED_HEARTBEAT_RETRIES_MAX_DELAY_MS: z.coerce
      .number()
      .int()
      .default(60_000 * 60 * 6),
    RUN_ENGINE_SUSPENDED_HEARTBEAT_RETRIES_INITIAL_DELAY_MS: z.coerce
      .number()
      .int()
      .default(60_000),
    RUN_ENGINE_SUSPENDED_HEARTBEAT_RETRIES_FACTOR: z.coerce.number().default(2),

    /** Maximum duration in milliseconds that a run can be debounced. Default: 1 hour (3,600,000ms) */
    RUN_ENGINE_MAXIMUM_DEBOUNCE_DURATION_MS: z.coerce
      .number()
      .int()
      .default(60_000 * 60), // 1 hour

    RUN_ENGINE_WORKER_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    RUN_ENGINE_WORKER_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    RUN_ENGINE_WORKER_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    RUN_ENGINE_WORKER_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    RUN_ENGINE_WORKER_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    RUN_ENGINE_WORKER_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    RUN_ENGINE_WORKER_REDIS_TLS_DISABLED: z
      .string()
      .default(process.env.REDIS_TLS_DISABLED ?? "false"),

    RUN_ENGINE_RUN_QUEUE_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    RUN_ENGINE_RUN_QUEUE_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    RUN_ENGINE_RUN_QUEUE_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    RUN_ENGINE_RUN_QUEUE_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    RUN_ENGINE_RUN_QUEUE_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    RUN_ENGINE_RUN_QUEUE_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    RUN_ENGINE_RUN_QUEUE_REDIS_TLS_DISABLED: z
      .string()
      .default(process.env.REDIS_TLS_DISABLED ?? "false"),

    RUN_ENGINE_RUN_LOCK_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    RUN_ENGINE_RUN_LOCK_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    RUN_ENGINE_RUN_LOCK_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    RUN_ENGINE_RUN_LOCK_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    RUN_ENGINE_RUN_LOCK_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    RUN_ENGINE_RUN_LOCK_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    RUN_ENGINE_RUN_LOCK_REDIS_TLS_DISABLED: z
      .string()
      .default(process.env.REDIS_TLS_DISABLED ?? "false"),

    RUN_ENGINE_DEV_PRESENCE_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    RUN_ENGINE_DEV_PRESENCE_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    RUN_ENGINE_DEV_PRESENCE_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    RUN_ENGINE_DEV_PRESENCE_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    RUN_ENGINE_DEV_PRESENCE_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    RUN_ENGINE_DEV_PRESENCE_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    RUN_ENGINE_DEV_PRESENCE_REDIS_TLS_DISABLED: z
      .string()
      .default(process.env.REDIS_TLS_DISABLED ?? "false"),

    //API Rate limiting
    /**
     * @example "60s"
     * @example "1m"
     * @example "1h"
     * @example "1d"
     * @example "1000ms"
     * @example "1000s"
     */
    RUN_ENGINE_RATE_LIMIT_REFILL_INTERVAL: z.string().default("10s"), // refill 250 tokens every 10 seconds
    RUN_ENGINE_RATE_LIMIT_MAX: z.coerce.number().int().default(1200), // allow bursts of 750 requests
    RUN_ENGINE_RATE_LIMIT_REFILL_RATE: z.coerce.number().int().default(400), // refix 250 tokens every 10 seconds
    RUN_ENGINE_RATE_LIMIT_REQUEST_LOGS_ENABLED: z.string().default("0"),
    RUN_ENGINE_RATE_LIMIT_REJECTION_LOGS_ENABLED: z.string().default("1"),
    RUN_ENGINE_RATE_LIMIT_LIMITER_LOGS_ENABLED: z.string().default("0"),

    RUN_ENGINE_RELEASE_CONCURRENCY_ENABLED: z.string().default("0"),
    RUN_ENGINE_RELEASE_CONCURRENCY_DISABLE_CONSUMERS: z.string().default("0"),
    RUN_ENGINE_RELEASE_CONCURRENCY_MAX_TOKENS_RATIO: z.coerce.number().default(1),
    RUN_ENGINE_RELEASE_CONCURRENCY_RELEASINGS_MAX_AGE: z.coerce
      .number()
      .int()
      .default(60_000 * 30),
    RUN_ENGINE_RELEASE_CONCURRENCY_RELEASINGS_POLL_INTERVAL: z.coerce
      .number()
      .int()
      .default(60_000),
    RUN_ENGINE_RELEASE_CONCURRENCY_MAX_RETRIES: z.coerce.number().int().default(3),
    RUN_ENGINE_RELEASE_CONCURRENCY_CONSUMERS_COUNT: z.coerce.number().int().default(1),
    RUN_ENGINE_RELEASE_CONCURRENCY_POLL_INTERVAL: z.coerce.number().int().default(500),
    RUN_ENGINE_RELEASE_CONCURRENCY_BATCH_SIZE: z.coerce.number().int().default(10),

    RUN_ENGINE_WORKER_ENABLED: z.string().default("1"),
    RUN_ENGINE_WORKER_LOG_LEVEL: z.enum(["log", "error", "warn", "info", "debug"]).default("info"),
    RUN_ENGINE_RUN_QUEUE_LOG_LEVEL: z
      .enum(["log", "error", "warn", "info", "debug"])
      .default("info"),
    RUN_ENGINE_TREAT_PRODUCTION_EXECUTION_STALLS_AS_OOM: z.string().default("0"),

    /** How long should the presence ttl last */
    DEV_PRESENCE_SSE_TIMEOUT: z.coerce.number().int().default(30_000),
    DEV_PRESENCE_TTL_MS: z.coerce.number().int().default(5_000),
    DEV_PRESENCE_POLL_MS: z.coerce.number().int().default(1_000),
    /** How many ms to wait until dequeuing again, if there was a run last time */
    DEV_DEQUEUE_INTERVAL_WITH_RUN: z.coerce.number().int().default(250),
    /** How many ms to wait until dequeuing again, if there was no run last time */
    DEV_DEQUEUE_INTERVAL_WITHOUT_RUN: z.coerce.number().int().default(1_000),
    /** The max number of runs per API call that we'll dequeue in DEV */
    DEV_DEQUEUE_MAX_RUNS_PER_PULL: z.coerce.number().int().default(10),

    /** The maximum concurrent local run processes executing at once in dev. This is a hard limit */
    DEV_MAX_CONCURRENT_RUNS: z.coerce.number().int().optional(),

    /** The CLI should connect to this for dev runs */
    DEV_ENGINE_URL: z.string().default(process.env.APP_ORIGIN ?? "http://localhost:3030"),

    LEGACY_RUN_ENGINE_WORKER_ENABLED: z.string().default(process.env.WORKER_ENABLED ?? "true"),
    LEGACY_RUN_ENGINE_WORKER_CONCURRENCY_WORKERS: z.coerce.number().int().default(2),
    LEGACY_RUN_ENGINE_WORKER_CONCURRENCY_TASKS_PER_WORKER: z.coerce.number().int().default(1),
    LEGACY_RUN_ENGINE_WORKER_POLL_INTERVAL: z.coerce.number().int().default(1000),
    LEGACY_RUN_ENGINE_WORKER_IMMEDIATE_POLL_INTERVAL: z.coerce.number().int().default(50),
    LEGACY_RUN_ENGINE_WORKER_CONCURRENCY_LIMIT: z.coerce.number().int().default(50),
    LEGACY_RUN_ENGINE_WORKER_SHUTDOWN_TIMEOUT_MS: z.coerce.number().int().default(60_000),
    LEGACY_RUN_ENGINE_WORKER_LOG_LEVEL: z
      .enum(["log", "error", "warn", "info", "debug"])
      .default("info"),

    LEGACY_RUN_ENGINE_WORKER_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    LEGACY_RUN_ENGINE_WORKER_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    LEGACY_RUN_ENGINE_WORKER_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    LEGACY_RUN_ENGINE_WORKER_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    LEGACY_RUN_ENGINE_WORKER_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    LEGACY_RUN_ENGINE_WORKER_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    LEGACY_RUN_ENGINE_WORKER_REDIS_TLS_DISABLED: z
      .string()
      .default(process.env.REDIS_TLS_DISABLED ?? "false"),
    LEGACY_RUN_ENGINE_WORKER_REDIS_CLUSTER_MODE_ENABLED: z.string().default("0"),

    LEGACY_RUN_ENGINE_WAITING_FOR_DEPLOY_BATCH_SIZE: z.coerce.number().int().default(100),
    LEGACY_RUN_ENGINE_WAITING_FOR_DEPLOY_BATCH_STAGGER_MS: z.coerce.number().int().default(1_000),

    COMMON_WORKER_ENABLED: z.string().default(process.env.WORKER_ENABLED ?? "true"),
    COMMON_WORKER_CONCURRENCY_WORKERS: z.coerce.number().int().default(2),
    COMMON_WORKER_CONCURRENCY_TASKS_PER_WORKER: z.coerce.number().int().default(10),
    COMMON_WORKER_POLL_INTERVAL: z.coerce.number().int().default(1000),
    COMMON_WORKER_IMMEDIATE_POLL_INTERVAL: z.coerce.number().int().default(50),
    COMMON_WORKER_CONCURRENCY_LIMIT: z.coerce.number().int().default(50),
    COMMON_WORKER_SHUTDOWN_TIMEOUT_MS: z.coerce.number().int().default(60_000),
    COMMON_WORKER_LOG_LEVEL: z.enum(["log", "error", "warn", "info", "debug"]).default("info"),

    COMMON_WORKER_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    COMMON_WORKER_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    COMMON_WORKER_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    COMMON_WORKER_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    COMMON_WORKER_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    COMMON_WORKER_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    COMMON_WORKER_REDIS_TLS_DISABLED: z.string().default(process.env.REDIS_TLS_DISABLED ?? "false"),
    COMMON_WORKER_REDIS_CLUSTER_MODE_ENABLED: z.string().default("0"),

    BATCH_TRIGGER_PROCESS_JOB_VISIBILITY_TIMEOUT_MS: z.coerce
      .number()
      .int()
      .default(60_000 * 5), // 5 minutes

    BATCH_TRIGGER_CACHED_RUNS_CHECK_ENABLED: BoolEnv.default(false),

    BATCH_TRIGGER_WORKER_ENABLED: z.string().default(process.env.WORKER_ENABLED ?? "true"),
    BATCH_TRIGGER_WORKER_CONCURRENCY_WORKERS: z.coerce.number().int().default(2),
    BATCH_TRIGGER_WORKER_CONCURRENCY_TASKS_PER_WORKER: z.coerce.number().int().default(10),
    BATCH_TRIGGER_WORKER_POLL_INTERVAL: z.coerce.number().int().default(1000),
    BATCH_TRIGGER_WORKER_IMMEDIATE_POLL_INTERVAL: z.coerce.number().int().default(50),
    BATCH_TRIGGER_WORKER_CONCURRENCY_LIMIT: z.coerce.number().int().default(20),
    BATCH_TRIGGER_WORKER_SHUTDOWN_TIMEOUT_MS: z.coerce.number().int().default(60_000),
    BATCH_TRIGGER_WORKER_LOG_LEVEL: z
      .enum(["log", "error", "warn", "info", "debug"])
      .default("info"),

    BATCH_TRIGGER_WORKER_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    BATCH_TRIGGER_WORKER_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    BATCH_TRIGGER_WORKER_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    BATCH_TRIGGER_WORKER_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    BATCH_TRIGGER_WORKER_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    BATCH_TRIGGER_WORKER_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    BATCH_TRIGGER_WORKER_REDIS_TLS_DISABLED: z
      .string()
      .default(process.env.REDIS_TLS_DISABLED ?? "false"),
    BATCH_TRIGGER_WORKER_REDIS_CLUSTER_MODE_ENABLED: z.string().default("0"),

    // BatchQueue DRR settings (Run Engine v2)
    BATCH_QUEUE_DRR_QUANTUM: z.coerce.number().int().default(25),
    BATCH_QUEUE_MAX_DEFICIT: z.coerce.number().int().default(100),
    BATCH_QUEUE_CONSUMER_COUNT: z.coerce.number().int().default(3),
    BATCH_QUEUE_CONSUMER_INTERVAL_MS: z.coerce.number().int().default(50),
    BATCH_QUEUE_WORKER_ENABLED: BoolEnv.default(true),
    // Number of master queue shards for horizontal scaling
    BATCH_QUEUE_SHARD_COUNT: z.coerce.number().int().default(1),
    // Maximum queues to fetch from master queue per iteration
    BATCH_QUEUE_MASTER_QUEUE_LIMIT: z.coerce.number().int().default(1000),
    // Enable worker queue for two-stage processing (claim messages, push to worker queue, process from worker queue)
    BATCH_QUEUE_WORKER_QUEUE_ENABLED: BoolEnv.default(true),
    // Worker queue blocking timeout in seconds (for two-stage processing, only used when BATCH_QUEUE_WORKER_QUEUE_ENABLED is true)
    BATCH_QUEUE_WORKER_QUEUE_TIMEOUT_SECONDS: z.coerce.number().int().default(10),
    // Global rate limit: max items processed per second across all consumers
    // If not set, no global rate limiting is applied
    BATCH_QUEUE_GLOBAL_RATE_LIMIT: z.coerce.number().int().positive().optional(),

    ADMIN_WORKER_ENABLED: z.string().default(process.env.WORKER_ENABLED ?? "true"),
    ADMIN_WORKER_CONCURRENCY_WORKERS: z.coerce.number().int().default(2),
    ADMIN_WORKER_CONCURRENCY_TASKS_PER_WORKER: z.coerce.number().int().default(10),
    ADMIN_WORKER_POLL_INTERVAL: z.coerce.number().int().default(1000),
    ADMIN_WORKER_IMMEDIATE_POLL_INTERVAL: z.coerce.number().int().default(50),
    ADMIN_WORKER_CONCURRENCY_LIMIT: z.coerce.number().int().default(20),
    ADMIN_WORKER_SHUTDOWN_TIMEOUT_MS: z.coerce.number().int().default(60_000),
    ADMIN_WORKER_LOG_LEVEL: z.enum(["log", "error", "warn", "info", "debug"]).default("info"),

    ADMIN_WORKER_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    ADMIN_WORKER_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    ADMIN_WORKER_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    ADMIN_WORKER_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    ADMIN_WORKER_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    ADMIN_WORKER_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    ADMIN_WORKER_REDIS_TLS_DISABLED: z.string().default(process.env.REDIS_TLS_DISABLED ?? "false"),
    ADMIN_WORKER_REDIS_CLUSTER_MODE_ENABLED: z.string().default("0"),

    ALERTS_WORKER_ENABLED: z.string().default(process.env.WORKER_ENABLED ?? "true"),
    ALERTS_WORKER_CONCURRENCY_WORKERS: z.coerce.number().int().default(2),
    ALERTS_WORKER_CONCURRENCY_TASKS_PER_WORKER: z.coerce.number().int().default(10),
    ALERTS_WORKER_POLL_INTERVAL: z.coerce.number().int().default(1000),
    ALERTS_WORKER_IMMEDIATE_POLL_INTERVAL: z.coerce.number().int().default(100),
    ALERTS_WORKER_CONCURRENCY_LIMIT: z.coerce.number().int().default(50),
    ALERTS_WORKER_SHUTDOWN_TIMEOUT_MS: z.coerce.number().int().default(60_000),
    ALERTS_WORKER_LOG_LEVEL: z.enum(["log", "error", "warn", "info", "debug"]).default("info"),

    ALERTS_WORKER_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    ALERTS_WORKER_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    ALERTS_WORKER_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    ALERTS_WORKER_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    ALERTS_WORKER_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    ALERTS_WORKER_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    ALERTS_WORKER_REDIS_TLS_DISABLED: z.string().default(process.env.REDIS_TLS_DISABLED ?? "false"),
    ALERTS_WORKER_REDIS_CLUSTER_MODE_ENABLED: z.string().default("0"),

    SCHEDULE_ENGINE_LOG_LEVEL: z.enum(["log", "error", "warn", "info", "debug"]).default("info"),
    SCHEDULE_WORKER_ENABLED: z.string().default(process.env.WORKER_ENABLED ?? "true"),
    SCHEDULE_WORKER_CONCURRENCY_WORKERS: z.coerce.number().int().default(2),
    SCHEDULE_WORKER_CONCURRENCY_TASKS_PER_WORKER: z.coerce.number().int().default(10),
    SCHEDULE_WORKER_POLL_INTERVAL: z.coerce.number().int().default(1000),
    SCHEDULE_WORKER_IMMEDIATE_POLL_INTERVAL: z.coerce.number().int().default(50),
    SCHEDULE_WORKER_CONCURRENCY_LIMIT: z.coerce.number().int().default(50),
    SCHEDULE_WORKER_SHUTDOWN_TIMEOUT_MS: z.coerce.number().int().default(30_000),
    SCHEDULE_WORKER_DISTRIBUTION_WINDOW_SECONDS: z.coerce.number().int().default(30),

    SCHEDULE_WORKER_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    SCHEDULE_WORKER_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    SCHEDULE_WORKER_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    SCHEDULE_WORKER_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    SCHEDULE_WORKER_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    SCHEDULE_WORKER_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    SCHEDULE_WORKER_REDIS_TLS_DISABLED: z
      .string()
      .default(process.env.REDIS_TLS_DISABLED ?? "false"),
    SCHEDULE_WORKER_REDIS_CLUSTER_MODE_ENABLED: z.string().default("0"),

    TASK_EVENT_PARTITIONING_ENABLED: z.string().default("0"),
    TASK_EVENT_PARTITIONED_WINDOW_IN_SECONDS: z.coerce.number().int().default(60), // 1 minute

    DEPLOYMENTS_AUTORELOAD_POLL_INTERVAL_MS: z.coerce.number().int().default(5_000),
    BULK_ACTION_AUTORELOAD_POLL_INTERVAL_MS: z.coerce.number().int().default(1_000),
    QUEUES_AUTORELOAD_POLL_INTERVAL_MS: z.coerce.number().int().default(5_000),

    SLACK_BOT_TOKEN: z.string().optional(),
    SLACK_SIGNUP_REASON_CHANNEL_ID: z.string().optional(),

    // kapa.ai
    KAPA_AI_WEBSITE_ID: z.string().optional(),

    // BetterStack
    BETTERSTACK_API_KEY: z.string().optional(),
    BETTERSTACK_STATUS_PAGE_ID: z.string().optional(),

    RUN_REPLICATION_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    RUN_REPLICATION_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    RUN_REPLICATION_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    RUN_REPLICATION_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    RUN_REPLICATION_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    RUN_REPLICATION_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    RUN_REPLICATION_REDIS_TLS_DISABLED: z
      .string()
      .default(process.env.REDIS_TLS_DISABLED ?? "false"),

    RUN_REPLICATION_CLICKHOUSE_URL: z.string().optional(),
    RUN_REPLICATION_ENABLED: z.string().default("0"),
    RUN_REPLICATION_SLOT_NAME: z.string().default("task_runs_to_clickhouse_v1"),
    RUN_REPLICATION_PUBLICATION_NAME: z.string().default("task_runs_to_clickhouse_v1_publication"),
    RUN_REPLICATION_MAX_FLUSH_CONCURRENCY: z.coerce.number().int().default(2),
    RUN_REPLICATION_FLUSH_INTERVAL_MS: z.coerce.number().int().default(1000),
    RUN_REPLICATION_FLUSH_BATCH_SIZE: z.coerce.number().int().default(100),
    RUN_REPLICATION_LEADER_LOCK_TIMEOUT_MS: z.coerce.number().int().default(30_000),
    RUN_REPLICATION_LEADER_LOCK_EXTEND_INTERVAL_MS: z.coerce.number().int().default(10_000),
    RUN_REPLICATION_ACK_INTERVAL_SECONDS: z.coerce.number().int().default(10),
    RUN_REPLICATION_LOG_LEVEL: z.enum(["log", "error", "warn", "info", "debug"]).default("info"),
    RUN_REPLICATION_CLICKHOUSE_LOG_LEVEL: z
      .enum(["log", "error", "warn", "info", "debug"])
      .default("info"),
    RUN_REPLICATION_LEADER_LOCK_ADDITIONAL_TIME_MS: z.coerce.number().int().default(10_000),
    RUN_REPLICATION_LEADER_LOCK_RETRY_INTERVAL_MS: z.coerce.number().int().default(500),
    RUN_REPLICATION_WAIT_FOR_ASYNC_INSERT: z.string().default("0"),
    RUN_REPLICATION_KEEP_ALIVE_ENABLED: z.string().default("0"),
    RUN_REPLICATION_KEEP_ALIVE_IDLE_SOCKET_TTL_MS: z.coerce.number().int().optional(),
    RUN_REPLICATION_MAX_OPEN_CONNECTIONS: z.coerce.number().int().default(10),
    // Retry configuration for insert operations
    RUN_REPLICATION_INSERT_MAX_RETRIES: z.coerce.number().int().default(3),
    RUN_REPLICATION_INSERT_BASE_DELAY_MS: z.coerce.number().int().default(100),
    RUN_REPLICATION_INSERT_MAX_DELAY_MS: z.coerce.number().int().default(2000),
    RUN_REPLICATION_INSERT_STRATEGY: z.enum(["insert", "insert_async"]).default("insert"),
    RUN_REPLICATION_DISABLE_PAYLOAD_INSERT: z.string().default("0"),

    // Clickhouse
    CLICKHOUSE_URL: z.string(),
    CLICKHOUSE_KEEP_ALIVE_ENABLED: z.string().default("1"),
    CLICKHOUSE_KEEP_ALIVE_IDLE_SOCKET_TTL_MS: z.coerce.number().int().optional(),
    CLICKHOUSE_MAX_OPEN_CONNECTIONS: z.coerce.number().int().default(10),
    CLICKHOUSE_LOG_LEVEL: z.enum(["log", "error", "warn", "info", "debug"]).default("info"),
    CLICKHOUSE_COMPRESSION_REQUEST: z.string().default("1"),

    // Logs List Query Settings (for paginated log views)
    CLICKHOUSE_LOGS_LIST_MAX_MEMORY_USAGE: z.coerce.number().int().default(256_000_000),
    CLICKHOUSE_LOGS_LIST_MAX_BYTES_BEFORE_EXTERNAL_SORT: z.coerce
      .number()
      .int()
      .default(256_000_000),
    CLICKHOUSE_LOGS_LIST_MAX_THREADS: z.coerce.number().int().default(2),
    CLICKHOUSE_LOGS_LIST_MAX_ROWS_TO_READ: z.coerce.number().int().default(10_000_000),
    CLICKHOUSE_LOGS_LIST_MAX_EXECUTION_TIME: z.coerce.number().int().default(120),

    // Logs Detail Query Settings (for single log views)
    CLICKHOUSE_LOGS_DETAIL_MAX_MEMORY_USAGE: z.coerce.number().int().default(64_000_000),
    CLICKHOUSE_LOGS_DETAIL_MAX_THREADS: z.coerce.number().int().default(2),
    CLICKHOUSE_LOGS_DETAIL_MAX_EXECUTION_TIME: z.coerce.number().int().default(60),

    // Query page ClickHouse limits (for TSQL queries)
    QUERY_CLICKHOUSE_MAX_EXECUTION_TIME: z.coerce.number().int().default(10),
    QUERY_CLICKHOUSE_MAX_MEMORY_USAGE: z.coerce.number().int().default(1_073_741_824), // 1GB in bytes
    QUERY_CLICKHOUSE_MAX_AST_ELEMENTS: z.coerce.number().int().default(4_000_000),
    QUERY_CLICKHOUSE_MAX_EXPANDED_AST_ELEMENTS: z.coerce.number().int().default(4_000_000),
    QUERY_CLICKHOUSE_MAX_BYTES_BEFORE_EXTERNAL_GROUP_BY: z.coerce.number().int().default(0),

    // Query page concurrency limits
    QUERY_DEFAULT_ORG_CONCURRENCY_LIMIT: z.coerce.number().int().default(3),
    QUERY_GLOBAL_CONCURRENCY_LIMIT: z.coerce.number().int().default(50),

    EVENTS_CLICKHOUSE_URL: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.CLICKHOUSE_URL),
    EVENTS_CLICKHOUSE_KEEP_ALIVE_ENABLED: z.string().default("1"),
    EVENTS_CLICKHOUSE_KEEP_ALIVE_IDLE_SOCKET_TTL_MS: z.coerce.number().int().optional(),
    EVENTS_CLICKHOUSE_MAX_OPEN_CONNECTIONS: z.coerce.number().int().default(10),
    EVENTS_CLICKHOUSE_LOG_LEVEL: z.enum(["log", "error", "warn", "info", "debug"]).default("info"),
    EVENTS_CLICKHOUSE_COMPRESSION_REQUEST: z.string().default("1"),
    EVENTS_CLICKHOUSE_BATCH_SIZE: z.coerce.number().int().default(1000),
    EVENTS_CLICKHOUSE_FLUSH_INTERVAL_MS: z.coerce.number().int().default(1000),
    EVENTS_CLICKHOUSE_INSERT_STRATEGY: z.enum(["insert", "insert_async"]).default("insert"),
    EVENTS_CLICKHOUSE_WAIT_FOR_ASYNC_INSERT: z.string().default("1"),
    EVENTS_CLICKHOUSE_ASYNC_INSERT_MAX_DATA_SIZE: z.coerce.number().int().default(10485760),
    EVENTS_CLICKHOUSE_ASYNC_INSERT_BUSY_TIMEOUT_MS: z.coerce.number().int().default(5000),
    EVENTS_CLICKHOUSE_START_TIME_MAX_AGE_MS: z.coerce
      .number()
      .int()
      .default(60_000 * 5), // 5 minutes
    EVENT_REPOSITORY_DEFAULT_STORE: z
      .enum(["postgres", "clickhouse", "clickhouse_v2"])
      .default("postgres"),
    EVENT_REPOSITORY_DEBUG_LOGS_DISABLED: BoolEnv.default(false),
    EVENTS_CLICKHOUSE_MAX_TRACE_SUMMARY_VIEW_COUNT: z.coerce.number().int().default(25_000),
    EVENTS_CLICKHOUSE_MAX_TRACE_DETAILED_SUMMARY_VIEW_COUNT: z.coerce.number().int().default(5_000),
    EVENTS_CLICKHOUSE_MAX_LIVE_RELOADING_SETTING: z.coerce.number().int().default(2000),

    // Bootstrap
    TRIGGER_BOOTSTRAP_ENABLED: z.string().default("0"),
    TRIGGER_BOOTSTRAP_WORKER_GROUP_NAME: z.string().optional(),
    TRIGGER_BOOTSTRAP_WORKER_TOKEN_PATH: z.string().optional(),

    // Machine presets
    MACHINE_PRESETS_OVERRIDE_PATH: z.string().optional(),

    // CLI package tag (e.g. "latest", "v4-beta", "4.0.0") - used for setup commands
    TRIGGER_CLI_TAG: z.string().default("latest"),

    HEALTHCHECK_DATABASE_DISABLED: z.string().default("0"),

    REQUEST_IDEMPOTENCY_REDIS_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_HOST),
    REQUEST_IDEMPOTENCY_REDIS_READER_HOST: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_READER_HOST),
    REQUEST_IDEMPOTENCY_REDIS_READER_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) =>
          v ?? (process.env.REDIS_READER_PORT ? parseInt(process.env.REDIS_READER_PORT) : undefined)
      ),
    REQUEST_IDEMPOTENCY_REDIS_PORT: z.coerce
      .number()
      .optional()
      .transform(
        (v) => v ?? (process.env.REDIS_PORT ? parseInt(process.env.REDIS_PORT) : undefined)
      ),
    REQUEST_IDEMPOTENCY_REDIS_USERNAME: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_USERNAME),
    REQUEST_IDEMPOTENCY_REDIS_PASSWORD: z
      .string()
      .optional()
      .transform((v) => v ?? process.env.REDIS_PASSWORD),
    REQUEST_IDEMPOTENCY_REDIS_TLS_DISABLED: z
      .string()
      .default(process.env.REDIS_TLS_DISABLED ?? "false"),

    REQUEST_IDEMPOTENCY_LOG_LEVEL: z
      .enum(["log", "error", "warn", "info", "debug"])
      .default("info"),

    REQUEST_IDEMPOTENCY_TTL_IN_MS: z.coerce
      .number()
      .int()
      .default(60_000 * 60 * 24),

    // Bulk action
    BULK_ACTION_BATCH_SIZE: z.coerce.number().int().default(100),
    BULK_ACTION_BATCH_DELAY_MS: z.coerce.number().int().default(200),
    BULK_ACTION_SUBBATCH_CONCURRENCY: z.coerce.number().int().default(5),

    // AI Run Filter
    AI_RUN_FILTER_MODEL: z.string().optional(),

    EVENT_LOOP_MONITOR_THRESHOLD_MS: z.coerce.number().int().default(100),
    EVENT_LOOP_MONITOR_UTILIZATION_INTERVAL_MS: z.coerce.number().int().default(1000),
    EVENT_LOOP_MONITOR_UTILIZATION_SAMPLE_RATE: z.coerce.number().default(0.05),
    EVENT_LOOP_MONITOR_NOTIFY_ENABLED: z.string().default("0"),

    VERY_SLOW_QUERY_THRESHOLD_MS: z.coerce.number().int().optional(),

    REALTIME_STREAMS_S2_BASIN: z.string().optional(),
    REALTIME_STREAMS_S2_ACCESS_TOKEN: z.string().optional(),
    REALTIME_STREAMS_S2_ACCESS_TOKEN_EXPIRATION_IN_MS: z.coerce
      .number()
      .int()
      .default(60_000 * 60 * 24), // 1 day
    REALTIME_STREAMS_S2_LOG_LEVEL: z
      .enum(["log", "error", "warn", "info", "debug"])
      .default("info"),
    REALTIME_STREAMS_S2_FLUSH_INTERVAL_MS: z.coerce.number().int().default(100),
    REALTIME_STREAMS_S2_MAX_RETRIES: z.coerce.number().int().default(10),
    REALTIME_STREAMS_S2_WAIT_SECONDS: z.coerce.number().int().default(60),
    REALTIME_STREAMS_DEFAULT_VERSION: z.enum(["v1", "v2"]).default("v1"),
    WAIT_UNTIL_TIMEOUT_MS: z.coerce.number().int().default(600_000),
  })
  .and(GithubAppEnvSchema)
  .and(S2EnvSchema);

export type Environment = z.infer<typeof EnvironmentSchema>;
export const env = EnvironmentSchema.parse(process.env);
