# Multi-Tier Approval — amount-based routing with escalation
# Demonstrates: emit/waitFor with condition filter, if/elseIf tier routing,
# timeout escalation, and multi-stage approval chains.

flowmarkup:
  title: Purchase Approval Workflow
  version: 1
  description: >
    Routes purchase requests through approval tiers based on amount:
    manager (<$1k), director ($1k–$10k), CFO (>$10k).
    Escalates on timeout. Collects full approval chain.
  requires:
    CONTEXT: [department_id]
    SERVICES: [approvals]

  input:
    request_id: STRING
    amount: NUMBER
    description: TEXT
    requester: STRING
  output:
    status: STRING
    approval_chain: ARRAY

  throws:
  - ApprovalTimeoutError

  events:
    approval_request:
      _notes_: Sent to approver when their decision is needed
      data:
        request_id: STRING
        amount: NUMBER
        description: STRING
        tier: STRING
        escalated: BOOLEAN
    approval_response:
      _notes_: Received from approver with their decision
      data:
        request_id: STRING
        decision: STRING
        approver: STRING

  examples:
    small_purchase:
      _notes_: Small purchase approved by manager only
      input:
        request_id: PR-001
        amount: 500
        description: Office supplies
        requester: alice
      output:
        status: approved
        approval_chain:
        - {tier: manager, approver: bob, decision: approved}
    large_purchase_denied:
      _notes_: Large purchase denied by director
      input:
        request_id: PR-002
        amount: 5000
        description: Server hardware
        requester: carol
      output:
        status: denied
        approval_chain:
        - {tier: manager, approver: bob, decision: approved}
        - {tier: director, approver: dave, decision: denied}

  vars:
    approval_chain: []
    current_tier: ""
    tiers_required: []
    decision: ""
    approver: ""

  do:
    # Determine which tiers are required based on amount
  - if:
      condition: =amount >= 10000
      then:
      - set:
          tiers_required: "=[\"manager\", \"director\", \"cfo\"]"
      elseIf:
      - condition: =amount >= 1000
        then:
        - set:
            tiers_required: "=[\"manager\", \"director\"]"
      else:
      - set:
          tiers_required: "=[\"manager\"]"

    # Walk through each required tier
  - forEach:
      items: =tiers_required
      as: tier
      maxItems: 100
      do:
      - set:
          current_tier: =tier

        # Request approval from the current tier
      - emit:
          event: approval_request
          scope: CONTEXT
          data:
            request_id: =request_id
            amount: =amount
            description: =description
            tier: =tier
            escalated: false

        # Wait for the response, filtering by request_id and tier
      - try:
          do:
          - waitFor:
              event: approval_response
              scope: CONTEXT
              timeout: 24h
              condition: =EVENT.DATA.request_id == request_id
              capture: [decision, approver]

          catch:
            TimeoutError:
            # If this is the last tier, throw — no one left to escalate to
            - if:
                condition: =tier == tiers_required[size(tiers_required) - 1]
                then:
                - throw:
                    error: ApprovalTimeoutError
                    message: "='Approval timed out at ' + tier + ' tier for request ' + request_id"
            - log: "Timeout at {{tier}} tier — escalating to next tier"
            - set:
                decision: escalated
                approver: "timeout"

      - set:
          approval_chain: "=approval_chain + [{tier: tier, approver: approver, decision: decision}]"

        # If denied at any tier, stop immediately
      - if:
          condition: =decision == "denied"
          then:
            return: {status: denied, approval_chain: =approval_chain}

        # If escalated (timeout), the next tier will handle it via the forEach loop

  - return: {status: approved, approval_chain: =approval_chain}
