#!/usr/bin/env bash
# star365 배포 점검 — CI 용 CLI (https://audit.star365.site)
#
#   1) 최초 1회(사람):  star365-audit.sh request <도메인> <이메일>
#        → 출력된 «동의 파일 내용»을 https://<도메인>/.well-known/star365-audit-consent.txt 에 올린다
#          (standing=on 줄이 반복 점검 허가다. 지우면 철회된다)
#        → 출력된 NONCE·RECEIPT_KEY 를 CI 비밀(STAR365_NONCE·STAR365_RECEIPT_KEY)로 저장한다
#   2) 배포마다(CI):   star365-audit.sh rescan
#        → 점검을 요청하고 영수증이 나올 때까지 기다린 뒤 판정한다
#
# 종료코드: 0 통과 · 1 실패(FAIL_ON 기준) · 2 판정 불가(시간 초과·동의 없음·오류) — «못 본 것»을 통과로 접지 않는다
# 환경변수: STAR365_API(기본 https://audit.star365.site) · FAIL_ON=crit|warn|none(기본 crit) · TIMEOUT_MIN(기본 25)
# 요구: bash · curl · python3
set -uo pipefail
API="${STAR365_API:-https://audit.star365.site}"
FAIL_ON="${FAIL_ON:-crit}"
TIMEOUT_MIN="${TIMEOUT_MIN:-25}"
die() { echo "star365-audit: $*" >&2; exit 2; }
json() { python3 -c "import json,sys;d=json.load(sys.stdin);print(eval(sys.argv[1]))" "$1"; }

cmd="${1:-}"; shift || true
case "$cmd" in
request)
  dom="${1:?도메인}"; email="${2:?이메일}"
  body=$(python3 -c "import json,sys;print(json.dumps({'domain':sys.argv[1],'requester':sys.argv[2],'contact':sys.argv[2]}))" "$dom" "$email")
  r=$(curl -fsS -X POST "$API/api/request" -H 'content-type: application/json' -d "$body") || die "신청 실패"
  [ "$(echo "$r" | json "d.get('ok')")" = "True" ] || die "신청 거부: $(echo "$r" | json "d.get('error')")"
  echo "── 동의 파일 내용 (아래 전부를 그대로 올리세요) ──"
  echo "$r" | json "d['request']['instructions']['well_known']['content']"
  echo "standing=on"
  echo "── 위치: $(echo "$r" | json "d['request']['instructions']['well_known']['url']")"
  echo
  echo "STAR365_NONCE=$(echo "$r" | json "d['request']['nonce']")"
  echo "STAR365_RECEIPT_KEY=$(echo "$r" | json "d['request']['receipt_key']")   # 🔒 비밀 — CI secret 으로만 저장"
  echo "(파일을 올린 뒤 첫 점검은 자동으로 돈다. 이후 배포마다: star365-audit.sh rescan)"
  ;;
rescan)
  : "${STAR365_NONCE:?STAR365_NONCE}"; : "${STAR365_RECEIPT_KEY:?STAR365_RECEIPT_KEY}"
  r=$(curl -sS -X POST "$API/api/rescan" -H 'content-type: application/json' \
        -H "Authorization: Bearer $STAR365_RECEIPT_KEY" -d "{\"nonce\":\"$STAR365_NONCE\"}") || die "재점검 요청 실패"
  ok=$(echo "$r" | json "d.get('ok')")
  [ "$ok" = "True" ] || die "재점검 거부: $(echo "$r" | json "d.get('error')") — $(echo "$r" | json "d.get('reason') or ''")"
  n=$(echo "$r" | json "d['nonce']")
  # 쿨다운(같은 도메인 소유자 재점검 1시간)이 기다릴 수 있는 시간보다 길면 헛되이 기다리지 않는다
  stage=$(echo "$r" | json "(d.get('queue') or {}).get('stage')")
  if [ "$stage" = "cooldown" ]; then
    rem=$(echo "$r" | json "((d.get('queue') or {}).get('cooldown') or {}).get('remaining_min', 0)")
    [ "$rem" -gt "$TIMEOUT_MIN" ] && die "쿨다운 중 — ${rem}분 뒤에 점검된다(대기 한도 ${TIMEOUT_MIN}분). 같은 도메인은 1시간에 한 번"
  fi
  echo "star365-audit: 점검 대기 — nonce $n (워커 10분 주기, 최대 ${TIMEOUT_MIN}분)"
  end=$(( $(date +%s) + TIMEOUT_MIN*60 ))
  while :; do
    out=$(curl -sS -H "Authorization: Bearer $STAR365_RECEIPT_KEY" "$API/api/receipt?nonce=$n")
    if [ "$(echo "$out" | json "d.get('ok')")" = "True" ]; then break; fi
    [ "$(date +%s)" -ge "$end" ] && die "시간 초과 — 영수증이 아직 없다(판정 불가, 통과로 접지 않는다)"
    sleep 30
  done
  echo "$out" | FAIL_ON="$FAIL_ON" python3 - <<'PY'
import json, os, sys
d = json.load(sys.stdin); fo = os.environ["FAIL_ON"]
det = (d.get("detail") or {}).get("checks") or {}
rows, bad, undet = [], [], []
for k, st in (d.get("verdicts") or {}).items():
    sev = (det.get(k) or {}).get("severity") or ("crit" if st == "FAIL" else "")
    rows.append(f"  {st:<13} {sev:<5} {k}  — {(det.get(k) or {}).get('reason','')[:90]}")
    if st == "FAIL" and (fo == "warn" or (fo == "crit" and sev == "crit")): bad.append(k)
    if st == "UNDETERMINED": undet.append(k)
print(f"star365-audit: {d.get('domain')} · 영수증 #{str(d.get('receipt_hash'))[:16]} · {d.get('summary')}")
print("\n".join(sorted(rows)))
if bad: print(f"🔴 실패(FAIL_ON={fo}): {', '.join(bad)}"); sys.exit(1)
if undet: print(f"⚠️ 확인 불가 {len(undet)}건: {', '.join(undet)} — 통과로 접지 않았지만 FAIL_ON 기준 실패는 아니다")
print("✅ 통과"); sys.exit(0)
PY
  ;;
*) sed -n '2,15p' "$0"; exit 2 ;;
esac
