# Shared contracts for the event pipeline system
#
# Mirrors rustelo_server::nats::pipeline — PipelineConfig, Pipeline,
# PipelineTrigger, PipelineStep, MessageTarget.
#
# Sub-type contracts are in:
#   pipelines/nats/contracts.ncl   — NatsPipeline  (pipeline_type = "nats")
#   pipelines/ci_cd/contracts.ncl  — CiCdPipeline  (pipeline_type = "ci_cd")
#
# Validate standalone:
#   source .env && nickel export --format json site/config/pipelines.ncl
#   # or with explicit import path:
#   nickel export --format json --import-path site/nickel site/config/pipelines.ncl

# ── Allowed value sets ─────────────────────────────────────────────────────────

let PipelineTypes = ["nats", "ci_cd"]                                     in
let StepTypes     = ["cache_invalidate", "broadcast", "script",
                     "persist_message"]                                    in
let TargetTypes   = ["user_id", "payload_field"]                          in
let ToastKinds    = ["info", "success", "warning", "error"]               in

# ── Reusable primitive contracts ───────────────────────────────────────────────

let OneOf = fun allowed =>
  std.contract.from_predicate (fun v => std.array.elem v allowed)
in

let NonEmpty = std.contract.from_predicate (fun s =>
  std.is_string s && std.string.length s > 0)
in

# ── Contracts ──────────────────────────────────────────────────────────────────

{

  # MessageTarget — selects the target user for a persist_message step.
  MessageTarget = {
    type | OneOf TargetTypes
      | doc "Selector variant:
             user_id       — literal UUID configured in the pipeline
             payload_field — extract UUID from a JSON field in the payload",

    value | String | NonEmpty
      | doc "user_id: literal UUID of the target user"
      | optional,

    field | String | NonEmpty
      | doc "payload_field: JSON field name that contains the user UUID"
      | optional,

    ..
  },

  # PipelineStep — one action in the execution chain.
  # Variant-specific fields are optional; the executor validates
  # required fields at runtime matching the Rust enum.
  PipelineStep = {
    type | OneOf StepTypes
      | doc "Step variant:
             cache_invalidate — flush the in-process content cache
             broadcast        — send a WebSocket toast to all clients
             script           — execute a Nu or shell script
             persist_message  — store a message in a user's inbox (requires auth feature)",

    # ── broadcast ────────────────────────────────────────────────────────────
    kind | String | OneOf ToastKinds
      | doc "broadcast: toast severity — info | success | warning | error"
      | optional,

    message | String | NonEmpty
      | doc "broadcast: toast body shown to connected WebSocket clients"
      | optional,

    # ── script ───────────────────────────────────────────────────────────────
    path | String | NonEmpty
      | doc "script: path to script file (.nu → nu, .sh → sh, other → direct exec).
             Relative paths resolve against SITE_CONTENT_PATH.
             Script receives PIPELINE_EVENT and PIPELINE_PAYLOAD env vars
             (plus NATS_SUBJECT / NATS_PAYLOAD aliases for NATS pipelines)."
      | optional,

    # ── persist_message ───────────────────────────────────────────────────────
    target | MessageTarget
      | doc "persist_message: user selector"
      | optional,

    sender_email | String | NonEmpty
      | doc "persist_message: sender label shown in the user's inbox"
      | optional,

    subject_template | String | NonEmpty
      | doc "persist_message: message subject; supports {{field}} substitution"
      | optional,

    body_template | String
      | doc "persist_message: body template; defaults to raw payload when omitted"
      | optional,
  },

  # Pipeline — generic shape shared by all pipeline types.
  # Use the type-specific contracts (nats/contracts.ncl, ci_cd/contracts.ncl)
  # for stricter validation of individual files.
  Pipeline = {
    pipeline_type | OneOf PipelineTypes
      | doc "Trigger mechanism:
             nats  — NATS JetStream subject subscription
             ci_cd — CI/CD event hook (webhook-driven)",

    name | String | NonEmpty
      | doc "Human-readable identifier used in structured log output",

    steps | Array PipelineStep
      | doc "Ordered actions executed sequentially on each trigger.
             Step failures are logged and do not abort subsequent steps."
      | default = [],

    ..
  },

  # PipelinesConfig — root record, deserialized directly into PipelineConfig.
  PipelinesConfig = {
    pipelines | Array Pipeline
      | doc "Aggregated list of all event pipelines across all trigger types."
      | default = [],
  },
}
