#!/usr/bin/env bash
# SPA 기반 도서관 웹사이트 분석 도구
# 새 도서관 모듈 추가 시 API 엔드포인트·파라미터 탐색에 사용

set -euo pipefail

cmd=${1:-help}
shift 2>/dev/null || true

_usage() {
  cat <<'EOF'
사용법: bash scripts/analyze-library.sh <명령> [인수...]

명령:
  endpoints   BUNDLE_URL                    JS 번들에서 /api/* 경로 목록 추출
  context     BUNDLE_URL PATTERN            패턴 주변 컨텍스트(±200자) 출력 (최대 5개)
  symbol      BUNDLE_URL SYMBOL             심볼/함수 정의 위치 출력 (앞 200자, 뒤 500자)
  libraries   API_URL                       도서관 목록 JSON API 파싱
  pattern     BUNDLE_URL REGEX              정규식 매칭 결과 추출 (최대 30개)
  test-param  API_URL BASE_JSON PARAM VAL.. POST 파라미터 유효값 순차 탐색
  pyxis       BASE_URL                      pyxis 플랫폼 분관 목록 조회 (ikc-pyxis-wrap 계열)
  ssl-check   HOSTNAME                      SSL 인증서 체인 확인 (중간 CA 누락 감지)

예시:
  bash scripts/analyze-library.sh endpoints "https://alpasq.bcl.go.kr/app.abc123.js"

  bash scripts/analyze-library.sh context "https://example.go.kr/app.js" "/api/search"

  bash scripts/analyze-library.sh symbol "https://example.go.kr/app.js" "convertToDetailPath:function"

  bash scripts/analyze-library.sh libraries "https://example.go.kr/api/common/libraryInfo"

  bash scripts/analyze-library.sh pattern "https://example.go.kr/app.js" '"(TITLE|AUTHOR|ALL|LOANABLE)"'

  bash scripts/analyze-library.sh test-param "https://example.go.kr/api/search" \
    '{"searchKeyword":"별","manageCode":"AA","pubFormCode":"ALL","page":"1","display":"3","order":"DESC"}' \
    article TITLE AUTHOR LOANABLE ALL SCORE

  bash scripts/analyze-library.sh pyxis "https://lib.siheung.go.kr"

  bash scripts/analyze-library.sh ssl-check "lib.siheung.go.kr"

EOF
}

case "$cmd" in

  endpoints)
    url="${1:?오류: BUNDLE_URL 필요}"
    curl -s "$url" | grep -oE '"/api/[^"]{3,80}"' | sort -u
    ;;

  context)
    url="${1:?오류: BUNDLE_URL 필요}"
    pattern="${2:?오류: PATTERN 필요}"
    tmpfile=$(mktemp)
    trap "rm -f '$tmpfile'" EXIT
    curl -s "$url" > "$tmpfile"
    python3 - "$tmpfile" "$pattern" <<'PYEOF'
import sys, re
path, pattern = sys.argv[1], sys.argv[2]
with open(path) as f:
    content = f.read()
escaped = re.escape(pattern)
matches = re.findall(fr'.{{0,200}}{escaped}.{{0,400}}', content)
if not matches:
    print(f'"{pattern}" 주변 컨텍스트를 찾을 수 없습니다.')
    sys.exit(0)
for i, m in enumerate(matches[:5]):
    print(f'--- match {i+1}/{min(len(matches),5)} ---')
    print(m)
    print()
PYEOF
    ;;

  symbol)
    url="${1:?오류: BUNDLE_URL 필요}"
    symbol="${2:?오류: SYMBOL 필요}"
    tmpfile=$(mktemp)
    trap "rm -f '$tmpfile'" EXIT
    curl -s "$url" > "$tmpfile"
    python3 - "$tmpfile" "$symbol" <<'PYEOF'
import sys
path, symbol = sys.argv[1], sys.argv[2]
with open(path) as f:
    content = f.read()
idx = content.find(symbol)
if idx == -1:
    print(f'"{symbol}" 를 찾을 수 없습니다.')
    sys.exit(0)
print(content[max(0, idx - 200):idx + 500])
PYEOF
    ;;

  libraries)
    url="${1:?오류: API_URL 필요}"
    tmpfile=$(mktemp)
    trap "rm -f '$tmpfile'" EXIT
    curl -s "$url" > "$tmpfile"
    python3 - "$tmpfile" <<'PYEOF'
import json, sys

path = sys.argv[1]
with open(path) as f:
    try:
        data = json.load(f)
    except json.JSONDecodeError as e:
        print(f'JSON 파싱 오류: {e}', file=sys.stderr)
        sys.exit(1)

def find_list(obj, depth=0):
    if depth > 5:
        return None
    if isinstance(obj, list) and len(obj) > 0 and isinstance(obj[0], dict):
        return obj
    if isinstance(obj, dict):
        for k in ('libList', 'libraryList', 'list', 'data', 'contents', 'result', 'items'):
            if k in obj:
                found = find_list(obj[k], depth + 1)
                if found:
                    return found
    return None

libs = find_list(data)
if not libs:
    print('[원본 JSON (처음 2000자)]')
    print(json.dumps(data, ensure_ascii=False, indent=2)[:2000])
    sys.exit(0)

print(f'총 {len(libs)}개 항목')
print()
for lib in libs:
    code = lib.get('manageCode') or lib.get('libCode') or lib.get('code') or '?'
    name = lib.get('libName') or lib.get('name') or lib.get('libraryName') or '?'
    group = lib.get('groupName') or lib.get('group') or ''
    if code == 'ALL':
        continue
    suffix = f' (그룹: {group})' if group else ''
    print(f'{code}: {name}{suffix}')
PYEOF
    ;;

  pattern)
    url="${1:?오류: BUNDLE_URL 필요}"
    regex="${2:?오류: REGEX 필요}"
    tmpfile=$(mktemp)
    trap "rm -f '$tmpfile'" EXIT
    curl -s "$url" > "$tmpfile"
    python3 - "$tmpfile" "$regex" <<'PYEOF'
import sys, re
path, regex = sys.argv[1], sys.argv[2]
with open(path) as f:
    content = f.read()
try:
    matches = re.findall(regex, content)
except re.error as e:
    print(f'정규식 오류: {e}', file=sys.stderr)
    sys.exit(1)
unique = list(dict.fromkeys(matches))
if not unique:
    print('매칭 결과 없음')
    sys.exit(0)
print(f'총 {len(unique)}개 (상위 30개):')
for m in unique[:30]:
    print(m)
PYEOF
    ;;

  test-param)
    url="${1:?오류: API_URL 필요}"
    base_json="${2:?오류: BASE_JSON 필요}"
    param="${3:?오류: PARAM 필요}"
    shift 3
    if [ $# -eq 0 ]; then
      echo "오류: 테스트할 값 목록이 필요합니다" >&2
      exit 1
    fi
    echo "[$param 유효값 탐색] → $url"
    echo
    for val in "$@"; do
      body=$(python3 -c "
import json, sys
d = json.loads(sys.argv[1])
d[sys.argv[2]] = sys.argv[3]
print(json.dumps(d, ensure_ascii=False))
" "$base_json" "$param" "$val")
      printf "%s=%-12s " "$param" "$val:"
      curl -s -X POST "$url" \
        -H "Content-Type: application/json" \
        -d "$body" | python3 -c "
import json, sys
try:
    d = json.load(sys.stdin)
    r = d
    for k in ('result', 'data', 'contents', 'response'):
        if isinstance(r, dict) and k in r:
            r = r[k]
    if isinstance(r, dict):
        out = r.get('debug') or r.get('message') or r.get('code') or r.get('totalCount')
        print(str(out if out is not None else r)[:80])
    elif isinstance(r, list):
        print(f'{len(r)}건')
    else:
        print(str(d)[:80])
except Exception as e:
    print(f'파싱 오류: {e}')
"
    done
    ;;

  pyxis)
    base="${1:?오류: BASE_URL 필요}"
    base="${base%/}"
    echo "[$base pyxis 분관 목록]"
    tmpfile=$(mktemp)
    trap "rm -f '$tmpfile'" EXIT
    curl -sk "$base/pyxis-api/1/branches" > "$tmpfile"
    python3 - "$tmpfile" <<'PYEOF'
import json, sys
path = sys.argv[1]
with open(path) as f:
    content = f.read().strip()
if not content:
    print('오류: 응답이 비어 있습니다. URL을 확인하거나 pyxis 플랫폼이 아닐 수 있습니다.')
    sys.exit(1)
try:
    data = json.loads(content)
except json.JSONDecodeError as e:
    print(f'JSON 파싱 오류: {e}')
    sys.exit(1)
if not data.get('success'):
    print(f'API 오류: {data.get("message","?")}\npyxis 플랫폼이 아닐 수 있습니다.')
    sys.exit(1)
branches = data.get('data', {}).get('list', [])
print(f'총 {len(branches)}개 분관')
print()
for b in branches:
    bid = b.get('id')
    bname = b.get('name', '?')
    group = b.get('branchGroup', {}).get('name', '')
    suffix = f' (그룹: {group})' if group and group != bname else ''
    print(f'  {bid}: {bname}{suffix}')
PYEOF
    ;;

  ssl-check)
    host="${1:?오류: HOSTNAME 필요}"
    echo "[SSL 인증서 체인 확인: $host]"
    openssl s_client -connect "$host:443" -servername "$host" 2>&1 | head -15
    ;;

  help|--help|-h)
    _usage
    ;;

  *)
    echo "알 수 없는 명령: $cmd" >&2
    _usage >&2
    exit 1
    ;;
esac
