src/lightspeed/integration/jobs.gleam

//// Background-job integration patterns for ecosystem compatibility (M26).

import gleam/int

/// Queue backend profile.
pub type QueueBackend {
  GleamWorkerPool(pool_size: Int)
  ObanBridge(module: String)
  MixedQueue(primary: String, fallback: String)
}

/// Retry/timeout policy for one job class.
pub type RetryPolicy {
  RetryPolicy(max_attempts: Int, base_backoff_ms: Int, timeout_ms: Int)
}

/// One job integration pattern.
pub type Pattern {
  Pattern(
    name: String,
    backend: QueueBackend,
    retry_policy: RetryPolicy,
    tenant_partitioned: Bool,
    dead_letter_enabled: Bool,
  )
}

/// Critical-path integration pattern.
pub fn critical_path_pattern() -> Pattern {
  Pattern(
    name: "critical_path_jobs",
    backend: ObanBridge(module: "MyApp.Workers"),
    retry_policy: RetryPolicy(
      max_attempts: 10,
      base_backoff_ms: 250,
      timeout_ms: 15_000,
    ),
    tenant_partitioned: True,
    dead_letter_enabled: True,
  )
}

/// Mixed-runtime integration pattern.
pub fn mixed_runtime_pattern() -> Pattern {
  Pattern(
    name: "mixed_runtime_jobs",
    backend: MixedQueue(primary: "Oban", fallback: "GleamWorkers"),
    retry_policy: RetryPolicy(
      max_attempts: 6,
      base_backoff_ms: 500,
      timeout_ms: 20_000,
    ),
    tenant_partitioned: True,
    dead_letter_enabled: True,
  )
}

/// Local development integration pattern.
pub fn local_dev_pattern() -> Pattern {
  Pattern(
    name: "local_dev_jobs",
    backend: GleamWorkerPool(pool_size: 4),
    retry_policy: RetryPolicy(
      max_attempts: 3,
      base_backoff_ms: 100,
      timeout_ms: 5000,
    ),
    tenant_partitioned: True,
    dead_letter_enabled: True,
  )
}

/// Validate job integration constraints.
pub fn valid(pattern: Pattern) -> Bool {
  backend_valid(pattern.backend)
  && retry_policy_valid(pattern.retry_policy)
  && pattern.tenant_partitioned
  && pattern.dead_letter_enabled
}

/// Stable backend label.
pub fn backend_label(backend: QueueBackend) -> String {
  case backend {
    GleamWorkerPool(pool_size) ->
      "gleam_worker_pool:" <> int.to_string(pool_size)
    ObanBridge(module) -> "oban_bridge:" <> module
    MixedQueue(primary, fallback) ->
      "mixed_queue:" <> primary <> ":" <> fallback
  }
}

/// Stable pattern signature.
pub fn signature(pattern: Pattern) -> String {
  "jobs:"
  <> pattern.name
  <> "|backend="
  <> backend_label(pattern.backend)
  <> "|max_attempts="
  <> int.to_string(pattern.retry_policy.max_attempts)
  <> "|base_backoff_ms="
  <> int.to_string(pattern.retry_policy.base_backoff_ms)
  <> "|timeout_ms="
  <> int.to_string(pattern.retry_policy.timeout_ms)
  <> "|tenant_partitioned="
  <> bool_label(pattern.tenant_partitioned)
  <> "|dead_letter_enabled="
  <> bool_label(pattern.dead_letter_enabled)
}

/// Pattern backend.
pub fn backend(pattern: Pattern) -> QueueBackend {
  pattern.backend
}

/// Pattern name.
pub fn name(pattern: Pattern) -> String {
  pattern.name
}

fn backend_valid(backend: QueueBackend) -> Bool {
  case backend {
    GleamWorkerPool(pool_size) -> pool_size > 0
    ObanBridge(module) -> module != ""
    MixedQueue(primary, fallback) -> primary != "" && fallback != ""
  }
}

fn retry_policy_valid(policy: RetryPolicy) -> Bool {
  policy.max_attempts > 0 && policy.base_backoff_ms > 0 && policy.timeout_ms > 0
}

fn bool_label(value: Bool) -> String {
  case value {
    True -> "true"
    False -> "false"
  }
}