#!/usr/bin/env bash
# AutoSeg Viewer + Agfa Enterprise Imaging (ambiente demo.agfa.net)
#
#   bash agfa.sh teste    SECRET   testa login e DICOMweb do Agfa, como o viewer faz
#   bash agfa.sh instalar SECRET   instala/atualiza o viewer ligado ao Agfa
#   bash agfa.sh sondar   SECRET   diagnóstico de 401/403: papéis do token e variações da busca
#
# O SECRET é o client secret do Keycloak do Agfa (32 caracteres), NÃO o token
# (eyJ...). Nada aqui grava o secret em disco; o instalador o guarda num Secret
# do Kubernetes. A saída mostra só códigos HTTP, contagens e UIDs, sem nomes.
set -u

ACAO=${1:-}
SEC=$(printf '%s' "${2:-}" | tr -d '[:space:]')
[ $# -ge 2 ] && shift 2 || shift $#

CID=${AGFA_CLIENT_ID:-xeroticket}
H=${AGFA_HOST:-ahei01.demo.agfa.net}
IP=${AGFA_IP:-192.168.93.5}
VM=${VIEWER_IP:-192.168.93.202}
VER=${VIEWER_VERSION:-1.4.6}
TURL=${AGFA_TOKEN_URL:-https://$H:1243/auth/realms/EI/protocol/openid-connect/token}
BASE=${AGFA_DICOMWEB:-https://$H/dicom-web}
CAF=${AGFA_CA:-/root/ca-agfa.pem}
PKG=https://pkg.rtmedical.ai/api/packages/apps/generic/viewer

die() { echo "ERRO: $*" >&2; exit 1; }
uso() { sed -n '4,6p' "$0" | sed 's/^# *//'; exit 1; }

case $ACAO in teste|instalar|sondar) ;; *) uso ;; esac
[ -n "$SEC" ] || die "falta o secret. Ex.: bash agfa.sh $ACAO 9mne...Comh"
case $SEC in eyJ*|*eyJhbGci*) die "isso é (ou contém) o TOKEN, não o secret. Use só o client secret de 32 caracteres." ;; esac
[ ${#SEC} -eq 32 ] || echo "aviso: o secret tem ${#SEC} caracteres (o do Keycloak costuma ter 32)."

# Certificados do Agfa (porta 443 e 1243), usados como "CA" do PACS.
garantir_ca() {
  if grep -q 'BEGIN CERT' "$CAF" 2>/dev/null; then return 0; fi
  echo "criando $CAF com os certificados do $H ..."
  : > "$CAF"
  for p in 443 1243; do
    echo | openssl s_client -connect "$IP:$p" -servername "$H" 2>/dev/null | openssl x509 >> "$CAF" 2>/dev/null
  done
  grep -q 'BEGIN CERT' "$CAF" || die "não consegui ler o certificado do $H ($IP)"
}

TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
TLS=(--cacert "$CAF")
# O nome do Agfa não tem DNS: resolve $H -> $IP em cada porta usada pelas URLs.
porta() { local u=${1#*://}; u=${u%%/*}
  case $u in *:*) echo "${u##*:}" ;; *) case $1 in https:*) echo 443 ;; *) echo 80 ;; esac ;; esac; }
RES=(); for p in $(printf '%s\n' "$(porta "$TURL")" "$(porta "$BASE")" | sort -u); do RES+=(--resolve "$H:$p:$IP"); done
c() { curl -sS -m 30 "${RES[@]}" "${TLS[@]}" "$@"; }
tok() { c -X POST "$TURL" --data-urlencode grant_type=client_credentials \
          --data-urlencode "client_id=$CID" --data-urlencode "client_secret=$SEC"; }

PY=$(command -v python3 || command -v /usr/libexec/platform-python || true)
# pick TAG MODALIDADES -> "<quantidade> <valor da TAG no 1º item, preferindo as modalidades>"
pick() {
  [ -n "$PY" ] || { echo "? -"; return; }
  "$PY" -c '
import json,sys
tag,pref=sys.argv[1],sys.argv[2].split(",")
try: d=json.load(open(sys.argv[3]))
except Exception: print("0 -"); sys.exit()
if not isinstance(d,list): print("0 -"); sys.exit()
def v(x,t):
    try: return x[t]["Value"][0]
    except Exception: return ""
best=[x for x in d if v(x,"00080060") in pref] or d
print(len(d), (v(best[0],tag) or "-") if best else "-")
' "$1" "$2" "$TMP/r.json"
}
# q ROTULO URL -> GET com token; mostra HTTP e, se não for 200, o começo da resposta
q() {
  local code
  code=$(c -H "Authorization: Bearer $TOK" -H 'Accept: application/dicom+json' \
           -o "$TMP/r.json" -w '%{http_code}' "$2")
  echo "$1: HTTP $code, $(wc -c < "$TMP/r.json" 2>/dev/null || echo 0) bytes"
  if [ "$code" != 200 ]; then head -c 300 "$TMP/r.json" 2>/dev/null; echo; return 1; fi
}

obter_token() {
  echo "== 1. token ($CID)"
  local j rc; j=$(tok 2>&1); rc=$?
  case $rc in 35|51|53|54|58|59|60|64|66|77|80|82|83|90|91)
    echo "o certificado do Agfa NÃO confere com $CAF (curl $rc): $(printf '%s' "$j" | head -c 200)"
    echo "repetindo sem verificar o certificado, só para ver se o resto funciona..."
    TLS=(-k); j=$(tok 2>&1) ;;
  esac
  TOK=$(printf '%s' "$j" | sed -n 's/.*"access_token" *: *"\([^"]*\)".*/\1/p')
  if [ -z "$TOK" ]; then echo "token: FALHOU"; printf '%s\n' "$j" | head -c 300; echo; exit 1; fi
  echo "token: ok (${#TOK} caracteres), TLS: ${TLS[*]}"
}

teste() {
  garantir_ca
  obter_token
  echo "== 2. busca de estudos (QIDO)"
  q estudos "$BASE/studies?limit=10" || exit 1
  local n st se sop
  read -r n st <<< "$(pick 0020000D x)"; echo "estudos: $n, primeiro: $st"
  [ "$st" != "-" ] || { echo "nenhum estudo retornado"; exit 1; }
  echo "== 3. séries"
  q series "$BASE/studies/$st/series" || exit 1
  read -r n se <<< "$(pick 0020000E CT,MR)"; echo "séries: $n, escolhida: $se"
  echo "== 4. metadados (WADO-RS)"
  q metadados "$BASE/studies/$st/series/$se/metadata"
  echo "== 5. imagem (WADO-RS)"
  q instancias "$BASE/studies/$st/series/$se/instances" || exit 1
  read -r n sop <<< "$(pick 00080018 x)"; echo "imagens na série: $n"
  c -H "Authorization: Bearer $TOK" -H 'Accept: multipart/related; type="application/dicom"' \
    -o "$TMP/i.bin" -w 'imagem: HTTP %{http_code}, %{size_download} bytes\n' \
    "$BASE/studies/$st/series/$se/instances/$sop"
  echo "== link do estudo no viewer"
  echo "https://$VM/viewer/launch?url=$BASE/studies/$st"
}

# Sem dados de paciente: só códigos HTTP, tamanhos e o conteúdo do token.
sondar() {
  garantir_ca
  RES+=(--resolve "$H:8443:$IP")
  obter_token
  echo "== 2. o que o token diz (para o administrador do Agfa)"
  [ -n "$PY" ] && "$PY" -c '
import base64,json,sys,datetime
p=sys.argv[1].split(".")[1]; d=json.loads(base64.urlsafe_b64decode(p+"="*(-len(p)%4)))
for k in ("iss","azp","aud","preferred_username","scope"): print(f"  {k}: {d.get(k)}")
print("  papéis do realm:", ", ".join(d.get("realm_access",{}).get("roles",[])) or "-")
for c,v in (d.get("resource_access") or {}).items(): print(f"  papéis do client {c}:", ", ".join(v.get("roles",[])))
print("  validade:", (d.get("exp",0)-d.get("iat",0))//60, "min")
' "$TOK"
  echo "== 3. variações da busca (código HTTP, tamanho)"
  local u a code
  s() { code=$(c "${@:3}" -o "$TMP/s.out" -w '%{http_code} %{size_download}B %{content_type}' "$2"); printf '  %-44s %s\n' "$1" "$code"; }
  A="Authorization: Bearer $TOK"
  s "sem token (esperado 302)"            "$BASE/studies?limit=1"
  s "token, sem filtro"                   "$BASE/studies?limit=1" -H "$A" -H 'Accept: application/dicom+json'
  s "token, filtro de data"               "$BASE/studies?limit=1&StudyDate=19000101-20991231" -H "$A" -H 'Accept: application/dicom+json'
  s "token, filtro de modalidade CT"      "$BASE/studies?limit=1&ModalitiesInStudy=CT" -H "$A" -H 'Accept: application/dicom+json'
  s "token, PatientID=*"                  "$BASE/studies?limit=1&PatientID=*" -H "$A" -H 'Accept: application/dicom+json'
  s "token, Accept application/json"      "$BASE/studies?limit=1" -H "$A" -H 'Accept: application/json'
  s "token, Accept */*"                   "$BASE/studies?limit=1" -H "$A" -H 'Accept: */*'
  s "token, nível paciente /patients"     "$BASE/patients?limit=1" -H "$A" -H 'Accept: application/dicom+json'
  s "token, porta 8443"                   "https://$H:8443/dicom-web/studies?limit=1" -H "$A" -H 'Accept: application/dicom+json'
  s "token, raiz /dicom-web/"             "$BASE/" -H "$A"
  echo "== 4. resposta do Agfa ao pedido sem filtro"
  c -H "$A" -H 'Accept: application/dicom+json' -D "$TMP/h.txt" -o "$TMP/s.out" "$BASE/studies?limit=1" >/dev/null 2>&1
  grep -i -E '^(HTTP|www-authenticate|server|x-)' "$TMP/h.txt" | sed 's/^/  /'
  if ! grep -q '^HTTP[^ ]* 200' "$TMP/h.txt"; then head -c 300 "$TMP/s.out" | sed 's/^/  /'; echo; fi
}

instalar() {
  garantir_ca
  cd "$TMP" || die "sem diretório temporário"
  curl -fsSLo install-viewer.sh "$PKG/$VER/install-viewer.sh" || die "não baixei o instalador $VER"
  curl -fsSLo SHA256SUMS "$PKG/$VER/SHA256SUMS" || die "não baixei o SHA256SUMS"
  sha256sum -c SHA256SUMS || die "SHA-256 do instalador não confere"
  bash install-viewer.sh --yes --ip "$VM" \
    --pacs-host "$H=$IP" \
    --pacs-url "$BASE" \
    --pacs-token-url "$TURL" \
    --pacs-client-id "$CID" \
    --pacs-client-secret "$SEC" \
    --pacs-ca "$CAF" "$@"
}

"$ACAO" "$@"
