# Batch Processing — forEach with per-item error accumulation
# Demonstrates: forEach with try/catch inside loop, error collection,
# post-loop assertion, and partial failure reporting.

flowmarkup:
  title: Batch Order Processor
  version: 1
  description: >
    Processes a list of orders, accumulating successes and failures.
    Fails if more than 50% of orders error out.
  requires:
    SERVICES: [orders, notifications]

  input:
    order_list:
      $kind: ARRAY
      _notes_: List of order maps with order_id, customer_id, amount
  output:
    processed_count: NUMBER
    failed_count: NUMBER
    failures: ARRAY

  throws:
  - $kind: BatchThresholdError
    data:
      failed_count: NUMBER
      total_count: NUMBER

  examples:
    all_succeed:
      _notes_: All orders process successfully
      input:
        order_list:
        - {order_id: O-1, customer_id: C-1, amount: 50}
        - {order_id: O-2, customer_id: C-2, amount: 75}
      output:
        processed_count: 2
        failed_count: 0
        failures: []
    partial_failure:
      _notes_: One order fails but under threshold
      input:
        order_list:
        - {order_id: O-1, customer_id: C-1, amount: 50}
        - {order_id: O-2, customer_id: C-2, amount: -1}
        - {order_id: O-3, customer_id: C-3, amount: 100}
      output:
        processed_count: 2
        failed_count: 1
        failures:
        - {order_id: O-2, error_type: ValidationError, message: Invalid amount}

  vars:
    processed: []
    failed: []

  do:
  - forEach:
      items: =order_list
      as: order
      maxItems: 10000
      do:
      - try:
          do:
          - call:
              service: orders
              operation: process
              timeout: 30s
              params:
                order_id: =order.order_id
                customer_id: =order.customer_id
                amount: =order.amount
              result:
                receipt: =RESULT
              retry:
                maxAttempts: 2
                delay: 1s
                onErrors: [TimeoutError]

          - set:
              processed: =processed + [order.order_id]

          catch:
            default:
            - set:
                failed: "=failed + [{order_id: order.order_id, error_type: ERROR.TYPE, message: ERROR.MESSAGE}]"
            - log: "Order {{order.order_id}} failed: {{ERROR.MESSAGE}}"

    # Fail the batch if more than 50% of orders errored
  - if:
      condition: =size(failed) > size(order_list) / 2
      then:
      - throw:
          _label_: Batch failure threshold exceeded
          error: BatchThresholdError
          message: "='Batch failure threshold exceeded: ' + size(failed) + ' of ' + size(order_list) + ' orders failed'"
          data:
            failed_count: =size(failed)
            total_count: =size(order_list)

  - if:
      condition: =size(failed) > 0
      then:
      - call:
          _label_: Notify ops about partial failures
          service: notifications
          operation: send
          timeout: 30s
          params:
            channel: ops
            message: "='Batch completed with ' + size(failed) + ' failures out of ' + size(order_list)"

  - return:
      processed_count: =size(processed)
      failed_count: =size(failed)
      failures: =failed
