#!/usr/bin/env bash
set -euo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib/env.sh
source "$HERE/lib/env.sh"

ENV_ALIAS="${NDO_ENV:-}"

# -e/--env may appear anywhere; strip it before dispatch.
ARGS=()
while [ $# -gt 0 ]; do
  case "$1" in
    -e|--env) ENV_ALIAS="$2"; shift 2 ;;
    *) ARGS+=("$1"); shift ;;
  esac
done
set -- "${ARGS[@]:-}"

NDO_REALM="${NDO_REALM:-default}"
NDO_CLIENT="${NDO_CLIENT:-frontend}"
NDO_USER="${NDO_USER:?Set NDO_USER through an approved configuration source before using authenticated API commands}"
NDO_PASS="${NDO_PASS:?Set NDO_PASS through an approved secret source before using authenticated API commands}"

usage() {
  cat <<'USAGE'
ndo-api.sh — drive the NDO BOM API for live repro, on any registered env.

Every command needs a target env: -e <alias> (or NDO_ENV=<alias>).
Auth is automatic: a keycloak password-grant token is minted per env and
refreshed on expiry (~15 min). Token cache: ~/.cache/ndo-repro/token-<env>.

Env:
  env ls                                   list registered envs
  env discover                             rescan kube contexts, rebuild the registry
  env show                                 resolved context / namespace / gateway for -e

API:
  login                                    mint a fresh token now
  token <jwt>                              save an externally-supplied bearer token
  whoami                                   check auth (200 = ok)
  opdef <key>                              GET operation-definition for an op key
  initiate <key> [bodyfile]                POST initiate, prints operation-request-id
  perform <rid> <innerJsonOrFile>          POST /{rid}/perform with a wrapped {method,url,body}
  prepare <rid> <key> <bodyfile>           POST /{rid}/prepare?key=<key> with body file
  get <rid> <cimPath> [innerBodyJson]      perform a GET against /consolidated-inventory-manager<cimPath>
  report <rid>                             replacement report (resolved/unresolved)
  target <rid>                             replacement target tree
  avail  <rid> <impactMkey> <refMkey> [type]   available-target-values (type default l2_link)

Cluster:
  logs <service> [since] [grep]            tail+denoise logs (default since=10m)
  image <service>                          deployed image of <service>-v1
  pods <service>                           pod phase/restarts for <service>-v1

Examples:
  ndo-api.sh env ls
  ndo-api.sh -e shared-244 whoami
  ndo-api.sh -e oss-01/dev-2 report 21dec51b-f9cb-41fe-af94-512c0921036b
  ndo-api.sh -e oss-01/dev-2 logs consolidated-inventory-manager 15m '\[UNM-231239\]'
USAGE
}

case "${1:-}" in
  ""|-h|--help|help) usage; exit 0 ;;
  env)
    case "${2:-ls}" in
      ls|list) env_list; exit 0 ;;
      discover) env_discover; exit 0 ;;
      show) env_resolve "$ENV_ALIAS"; printf 'alias   : %s\ncontext : %s\nns      : %s\ngateway : %s\n' \
              "$ENV_ALIAS" "$NDO_CTX" "$NDO_NS" "$NDO_GW"; exit 0 ;;
      *) echo "env: ls | discover | show" >&2; exit 2 ;;
    esac ;;
esac

env_resolve "$ENV_ALIAS"
GW="${NDO_GW_OVERRIDE:-$NDO_GW}"
BOM="$GW/business-operation-manager/v1"
mkdir -p "$NDO_CACHE"
TOKFILE="${NDO_TOKEN_FILE:-$NDO_CACHE/token-$(tr '/' '_' <<<"$ENV_ALIAS").txt}"

mint() {
  local out
  out=$(curl -sk -X POST "$GW/auth/realms/$NDO_REALM/protocol/openid-connect/token" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    --data-urlencode "grant_type=password" --data-urlencode "client_id=$NDO_CLIENT" \
    --data-urlencode "username=$NDO_USER" --data-urlencode "password=$NDO_PASS")
  printf '%s' "$out" | python3 -c "import sys,json;d=json.load(sys.stdin);open('$TOKFILE','w').write(d['access_token']) if 'access_token' in d else sys.exit('mint failed: '+json.dumps(d)[:200])" || return 1
  chmod 600 "$TOKFILE"
}

token_valid() {
  [ -s "$TOKFILE" ] || return 1
  python3 - "$TOKFILE" <<'PY' 2>/dev/null
import sys,base64,json,time
t=open(sys.argv[1]).read().strip()
p=t.split('.')[1]; p+='='*(-len(p)%4)
exp=json.loads(base64.urlsafe_b64decode(p)).get('exp',0)
sys.exit(0 if exp-time.time()>30 else 1)
PY
}

ensure_token() { token_valid || mint; }
tok() { cat "$TOKFILE"; }
auth() { ensure_token >&2 || { echo "auth failed on $ENV_ALIAS" >&2; exit 1; }; echo "Authorization: Bearer $(tok)"; }
K() { kubectl --context="$NDO_CTX" -n "$NDO_NS" "$@"; }

# Services use either app=<svc>-v1 or name=<svc>-v1 depending on the chart.
selector_for() {
  local svc="$1" l
  for l in "app=$svc-v1" "name=$svc-v1" "app=$svc" "name=$svc"; do
    [ -n "$(K get pod -l "$l" -o name 2>/dev/null)" ] && { echo "$l"; return 0; }
  done
  echo "no pods for $svc (tried app=/name= selectors) in $NDO_NS" >&2
  return 1
}

case "${1:-}" in
  token)   printf '%s' "$2" > "$TOKFILE"; chmod 600 "$TOKFILE"; echo "saved to $TOKFILE"; ;;
  login)   mint && echo "minted ($NDO_USER, realm=$NDO_REALM, env=$ENV_ALIAS) → $TOKFILE" ;;
  whoami)  curl -sk -o /dev/null -w "HTTP %{http_code}\n" -H "$(auth)" "$BOM/operation-definition?key=nc_op_ci_as-is_hw-component.replacement" ;;
  opdef)   curl -sk -H "$(auth)" "$BOM/operation-definition?key=$2" ;;
  initiate)
    body="${3:-{} }"; [ -f "${3:-}" ] && body="@$3"
    curl -sk -X POST -H "$(auth)" -H 'Content-Type: application/json' "$BOM/operation-request/initiate?key=$2" -d "$body" ;;
  perform)
    inner="$3"; [ -f "$3" ] && inner="@$3"
    curl -sk -X POST -H "$(auth)" -H 'Content-Type: application/json' "$BOM/operation-request/$2/perform" -d "$inner" ;;
  prepare)
    curl -sk -X POST -H "$(auth)" -H 'Content-Type: application/json' "$BOM/operation-request/$2/prepare?key=$3" -d "@$4" ;;
  get)
    rid="$2"; path="$3"; innerbody="${4:-}"
    if [ -n "$innerbody" ]; then req="{\"method\":\"GET\",\"url\":\"/consolidated-inventory-manager$path\",\"body\":$innerbody}";
    else req="{\"method\":\"GET\",\"url\":\"/consolidated-inventory-manager$path\"}"; fi
    curl -sk -X POST -H "$(auth)" -H 'Content-Type: application/json' "$BOM/operation-request/$rid/perform" -d "$req" ;;
  report)
    curl -sk -X POST -H "$(auth)" -H 'Content-Type: application/json' "$BOM/operation-request/$2/perform" \
      -d '{"method":"GET","url":"/consolidated-inventory-manager/v3/replacement/report"}' \
      | python3 -c "import sys,json;i=json.load(sys.stdin).get('action-report',{}).get('results',{}).get('impact',[]);print(json.dumps(i,indent=1))" ;;
  target)
    curl -sk -X POST -H "$(auth)" -H 'Content-Type: application/json' "$BOM/operation-request/$2/perform" \
      -d '{"method":"GET","url":"/consolidated-inventory-manager/v3/replacement/target"}' ;;
  avail)
    typ="${5:-l2_link}"
    curl -sk -X POST -H "$(auth)" -H 'Content-Type: application/json' "$BOM/operation-request/$2/perform" \
      -d "{\"method\":\"GET\",\"url\":\"/consolidated-inventory-manager/v3/replacement/mapping/available-target-values\",\"body\":{\"impact-type\":\"$typ\",\"impacted-entity-mkey\":\"$3\",\"ref-endpoint-mkey\":\"$4\"}}" \
      | python3 -c "import sys,json;r=json.load(sys.stdin).get('action-report',{}).get('results',{});print('total',r.get('total'),'values',len(r.get('available-values',[])))" ;;
  logs)
    svc="$2"; since="${3:-10m}"; pat="${4:-}"
    SEL=$(selector_for "$svc") || exit 1
    P=$(K get pod -l "$SEL" -o jsonpath='{.items[0].metadata.name}')
    K logs "$P" --since="$since" 2>/dev/null \
      | sed -E 's/\[(tenant_id|thread|originating_bi_id|traceId|spanId|request_id)=[^]]*\] ?//g' \
      | { [ -n "$pat" ] && grep -aE "$pat" || cat; } ;;
  image)
    K get deploy "$2-v1" -o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}' ;;
  pods)
    SEL=$(selector_for "$2") || exit 1
    K get pod -l "$SEL" -o custom-columns='POD:.metadata.name,PHASE:.status.phase,READY:.status.containerStatuses[0].ready,RESTARTS:.status.containerStatuses[0].restartCount,IMAGE:.status.containerStatuses[0].image' ;;
  *) echo "unknown cmd: $1"; usage; exit 1 ;;
esac
