#!/usr/bin/env bash
# vault-run-action.sh — Execute an action inside the ephemeral vault-runner container
#
# This script is the entrypoint for the vault-runner container. It runs with
# vault secrets injected as environment variables (GITHUB_TOKEN, CLAWHUB_TOKEN,
# deploy keys, etc.) and dispatches to the appropriate action handler.
#
# The vault-runner container is ephemeral: it starts, runs the action, and is
# destroyed. Secrets exist only in container memory, never on disk.
#
# Usage: vault-run-action.sh <action-id>

set -euo pipefail

VAULT_SCRIPT_DIR="${DISINTO_VAULT_DIR:-/home/agent/disinto/vault}"
OPS_VAULT_DIR="${DISINTO_OPS_VAULT_DIR:-${VAULT_SCRIPT_DIR}}"
LOGFILE="${VAULT_SCRIPT_DIR}/vault.log"
ACTION_ID="${1:?Usage: vault-run-action.sh <action-id>}"

log() {
  printf '[%s] vault-runner: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >> "$LOGFILE" 2>/dev/null || \
    printf '[%s] vault-runner: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >&2
}

# Find action file in approved/
ACTION_FILE="${OPS_VAULT_DIR}/approved/${ACTION_ID}.json"
if [ ! -f "$ACTION_FILE" ]; then
  log "ERROR: action file not found: ${ACTION_FILE}"
  echo "ERROR: action file not found: ${ACTION_FILE}" >&2
  exit 1
fi

ACTION_TYPE=$(jq -r '.type // ""' < "$ACTION_FILE")
ACTION_SOURCE=$(jq -r '.source // ""' < "$ACTION_FILE")
PAYLOAD=$(jq -c '.payload // {}' < "$ACTION_FILE")

if [ -z "$ACTION_TYPE" ]; then
  log "ERROR: ${ACTION_ID} has no type field"
  exit 1
fi

log "${ACTION_ID}: executing type=${ACTION_TYPE} source=${ACTION_SOURCE}"

FIRE_EXIT=0

case "$ACTION_TYPE" in
  webhook-call)
    # HTTP call to endpoint with optional method/headers/body
    ENDPOINT=$(echo "$PAYLOAD" | jq -r '.endpoint // ""')
    METHOD=$(echo "$PAYLOAD" | jq -r '.method // "POST"')
    REQ_BODY=$(echo "$PAYLOAD" | jq -r '.body // ""')

    if [ -z "$ENDPOINT" ]; then
      log "ERROR: ${ACTION_ID} webhook-call missing endpoint"
      exit 1
    fi

    CURL_ARGS=(-sf -X "$METHOD" -o /dev/null -w "%{http_code}")
    while IFS= read -r header; do
      [ -n "$header" ] && CURL_ARGS+=(-H "$header")
    done < <(echo "$PAYLOAD" | jq -r '.headers // {} | to_entries[] | "\(.key): \(.value)"' 2>/dev/null || true)
    if [ -n "$REQ_BODY" ] && [ "$REQ_BODY" != "null" ]; then
      CURL_ARGS+=(-d "$REQ_BODY")
    fi

    HTTP_CODE=$(curl "${CURL_ARGS[@]}" "$ENDPOINT" 2>/dev/null) || HTTP_CODE="000"
    if [[ "$HTTP_CODE" =~ ^2 ]]; then
      log "${ACTION_ID}: webhook-call -> HTTP ${HTTP_CODE} OK"
    else
      log "ERROR: ${ACTION_ID} webhook-call -> HTTP ${HTTP_CODE}"
      FIRE_EXIT=1
    fi
    ;;

  promote)
    # Promote a Woodpecker pipeline to a deployment environment (staging/production).
    # Payload: {"repo_id": N, "pipeline": N, "environment": "staging"|"production"}
    PROMOTE_REPO_ID=$(echo "$PAYLOAD" | jq -r '.repo_id // ""')
    PROMOTE_PIPELINE=$(echo "$PAYLOAD" | jq -r '.pipeline // ""')
    PROMOTE_ENV=$(echo "$PAYLOAD" | jq -r '.environment // ""')

    if [ -z "$PROMOTE_REPO_ID" ] || [ -z "$PROMOTE_PIPELINE" ] || [ -z "$PROMOTE_ENV" ]; then
      log "ERROR: ${ACTION_ID} promote missing repo_id, pipeline, or environment"
      FIRE_EXIT=1
    else
      # Validate environment is staging or production
      case "$PROMOTE_ENV" in
        staging|production) ;;
        *)
          log "ERROR: ${ACTION_ID} promote invalid environment '${PROMOTE_ENV}' (must be staging or production)"
          FIRE_EXIT=1
          ;;
      esac

      if [ "$FIRE_EXIT" -eq 0 ]; then
        WP_SERVER="${WOODPECKER_SERVER:-http://woodpecker:8000}"
        WP_TOKEN="${WOODPECKER_TOKEN:-}"

        if [ -z "$WP_TOKEN" ]; then
          log "ERROR: ${ACTION_ID} promote requires WOODPECKER_TOKEN"
          FIRE_EXIT=1
        else
          PROMOTE_RESP=$(curl -sf -X POST \
            -H "Authorization: Bearer ${WP_TOKEN}" \
            -H "Content-Type: application/x-www-form-urlencoded" \
            -d "event=deployment&deploy_to=${PROMOTE_ENV}" \
            "${WP_SERVER}/api/repos/${PROMOTE_REPO_ID}/pipelines/${PROMOTE_PIPELINE}" 2>/dev/null) || PROMOTE_RESP=""

          NEW_PIPELINE=$(printf '%s' "$PROMOTE_RESP" | jq -r '.number // empty' 2>/dev/null)
          if [ -n "$NEW_PIPELINE" ]; then
            log "${ACTION_ID}: promoted pipeline ${PROMOTE_PIPELINE} to ${PROMOTE_ENV} -> new pipeline #${NEW_PIPELINE}"
          else
            log "ERROR: ${ACTION_ID} promote API failed (repo_id=${PROMOTE_REPO_ID} pipeline=${PROMOTE_PIPELINE} env=${PROMOTE_ENV})"
            FIRE_EXIT=1
          fi
        fi
      fi
    fi
    ;;

  blog-post|social-post|email-blast|pricing-change|dns-change|stripe-charge)
    HANDLER="${VAULT_SCRIPT_DIR}/handlers/${ACTION_TYPE}.sh"
    if [ -x "$HANDLER" ]; then
      bash "$HANDLER" "$ACTION_ID" "$PAYLOAD" 2>&1 || FIRE_EXIT=$?
    else
      log "ERROR: ${ACTION_ID} no handler for type '${ACTION_TYPE}' (${HANDLER} not found)"
      FIRE_EXIT=1
    fi
    ;;

  *)
    log "ERROR: ${ACTION_ID} unknown action type '${ACTION_TYPE}'"
    FIRE_EXIT=1
    ;;
esac

exit "$FIRE_EXIT"
