# Configuration Composition Helpers
#
# Provides utilities for merging configurations from multiple layers:
# 1. Schema (type contracts)
# 2. Service Defaults (base values)
# 3. Mode Overlay (mode-specific tuning)
# 4. User Customization (overrides)

{
  # Recursively merge two record configurations
  # Mode config values override defaults (shallow merge at each level)
  #
  # Example:
  #   let base = { server = { port = 9000, workers = 4 } }
  #   let mode = { server = { workers = 16 } }
  #   merge_with_override base mode
  #   # Result: { server = { port = 9000, workers = 16 } }
  merge_with_override = fun base override =>
    if std.type.is_record base && std.type.is_record override then
      let base_fields = std.record.fields base in
      let override_fields = std.record.fields override in

      base_fields
      |> std.array.fold
        (fun acc key =>
          let base_value = base |> std.record.get key in

          if std.record.has_field override key then
            let override_value = override |> std.record.get key in

            if std.type.is_record base_value && std.type.is_record override_value then
              acc
              |> std.record.insert key (
                merge_with_override base_value override_value
              )
            else
              # Override value takes precedence
              acc |> std.record.insert key override_value
          else
            # Keep base value
            acc
        )
        (override_fields
         |> std.array.fold
           (fun acc key =>
             if !std.record.has_field base key then
               acc |> std.record.insert key (override |> std.record.get key)
             else
               acc
           )
           base
        )
    else
      # If either is not a record, override takes precedence
      if std.type.is_null override then base else override,

  # Compose configuration from multiple layers with proper merging
  #
  # Layer 1: defaults (base values)
  # Layer 2: mode_config (mode-specific overrides)
  # Layer 3: user_overrides (user customization)
  #
  # Example:
  #   compose_config
  #     orchestrator_defaults
  #     solo_mode_config
  #     user_customization
  compose_config = fun defaults mode_config user_overrides =>
    let base_merged = merge_with_override defaults mode_config in
    merge_with_override base_merged user_overrides,

  # Transform configuration for runtime (identity for now, extensible)
  # This is a hook for service-specific transformations
  transform_for_runtime = fun config service_name =>
    config,

  # Flatten nested record into dot-notation for TOML export
  # Example:
  #   flatten_config { server = { port = 9000 } }
  #   # Result: { "server.port" = 9000 }
  flatten_config = fun config =>
    let rec flatten_with_prefix = fun prefix config =>
      if std.type.is_record config then
        std.record.fields config
        |> std.array.fold
          (fun acc key =>
            let value = config |> std.record.get key in
            let full_key = if std.string.is_empty prefix then
              key
            else
              prefix ++ "." ++ key
            in

            if std.type.is_record value then
              acc
              |> std.record.merge (flatten_with_prefix full_key value)
            else
              acc |> std.record.insert full_key value
          )
          {}
      else
        config
    in
    flatten_with_prefix "" config,

  # Deep merge with recursive descent
  # Used for complex nested configs
  deep_merge = fun a b =>
    if std.type.is_record a && std.type.is_record b then
      let a_fields = std.record.fields a in

      a_fields
      |> std.array.fold
        (fun acc key =>
          let a_val = a |> std.record.get key in
          let has_b_key = std.record.has_field b key in

          if has_b_key then
            let b_val = b |> std.record.get key in

            if std.type.is_record a_val && std.type.is_record b_val then
              acc |> std.record.insert key (deep_merge a_val b_val)
            else
              acc |> std.record.insert key b_val
          else
            acc |> std.record.insert key a_val
        )
        {}
      |> (fun merged =>
        std.record.fields b
        |> std.array.fold
          (fun acc key =>
            if !std.record.has_field a key then
              acc |> std.record.insert key (b |> std.record.get key)
            else
              acc
          )
          merged
      )
    else
      b,
}
