#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────────────────────
# erp_module E2E 통합 테스트 — 실제 HTTP(로그인→CSRF→API) + DB 저장 검증
#
#   실제 사이트 흐름을 그대로 탄다:
#     1) 임시 master 계정 생성 (테스트 후 삭제)
#     2) HTTP 로그인 (CSRF 폼토큰)
#     3) setting API 로 자리타입(부모) 생성 → DB 저장 확인           [WRITE]
#     4) setting API 로 자리별 전용타입(자식) localize → DB 독립 확인 [WRITE]
#     5) 자리별 타입 목록 GET → 상속/전용 병합 확인                    [READ]
#     6) 계약 API(get_current_maintenance_base) → 2계층 관리비 해석    [READ]
#     7) 생성한 데이터 + 임시 계정 전부 정리
#
#   ⚠ 테스트가 만든 모든 행과 계정은 종료 시 자동 삭제(cleanup trap)된다.
#   사용:  bash bin/e2e_setting_to_contract.sh
# ─────────────────────────────────────────────────────────────────────────────
set -uo pipefail

ROOT="/home/erp_module/www"; DB="erp_module"; HOST="erp_module.acux.store"; BASE="http://127.0.0.1"
JAR="$(mktemp)"; TMP="$(mktemp -d)"
QA_USER="qa_e2e_$$"; QA_PW="QaE2e!$$secret"
QA_ACC_ID=""; PARENT_TYPE_ID=""; CHILD_TYPE_ID=""; SPOT_ID=""; CAT_ID=""

PASS=0; FAIL=0
ok()  { printf '  \033[32m✓ PASS\033[0m  %s\n' "$1"; PASS=$((PASS+1)); }
bad() { printf '  \033[31m✗ FAIL\033[0m  %s\n' "$1"; FAIL=$((FAIL+1)); }
stage(){ printf '\n\033[1m━━ %s\033[0m\n' "$1"; }
mq(){ mysql -N -u root "$DB" -e "$1" 2>/dev/null; }
curlh(){ curl -s -H "Host: $HOST" -c "$JAR" -b "$JAR" "$@"; }

cleanup() {
  stage "정리 (테스트 데이터/계정 삭제)"
  [ -n "$CHILD_TYPE_ID" ]  && mq "DELETE FROM burial_spot_custom_types WHERE id=$CHILD_TYPE_ID" && echo "  - 자식 자리타입 #$CHILD_TYPE_ID 삭제"
  [ -n "$PARENT_TYPE_ID" ] && mq "DELETE FROM burial_category_spot_types WHERE id=$PARENT_TYPE_ID" && echo "  - 부모 자리타입 #$PARENT_TYPE_ID 삭제"
  [ -n "$QA_ACC_ID" ]      && mq "DELETE FROM accounts WHERE id=$QA_ACC_ID" && echo "  - 임시 계정 #$QA_ACC_ID 삭제"
  rm -rf "$JAR" "$TMP"
}
trap cleanup EXIT

# ── 0) 임시 master 계정 생성 ────────────────────────────────────────────────
stage "STEP 0 · 임시 master 계정 생성"
HASH=$(php -r 'echo password_hash($argv[1], PASSWORD_DEFAULT);' "$QA_PW")
CAT_ID=$(mq "SELECT id FROM burial_categories WHERE is_active=1 ORDER BY id LIMIT 1")
SPOT_ID=$(mq "SELECT id FROM burial_spots WHERE deleted_at IS NULL ORDER BY id LIMIT 1")
if [ -z "$CAT_ID" ] || [ -z "$SPOT_ID" ]; then bad "테스트 전제 데이터 없음 (활성 카테고리/자리)"; exit 1; fi
mq "INSERT INTO accounts (user_id, user_password, name, roles_id, is_active, created_at) VALUES ('$QA_USER', '$HASH', 'QA E2E', 1, 1, NOW())"
QA_ACC_ID=$(mq "SELECT id FROM accounts WHERE user_id='$QA_USER' LIMIT 1")
[ -n "$QA_ACC_ID" ] && ok "임시 master 계정 생성 (#$QA_ACC_ID, $QA_USER) · 카테고리=$CAT_ID 자리=$SPOT_ID" || { bad "계정 생성 실패"; exit 1; }

# ── 1) HTTP 로그인 ──────────────────────────────────────────────────────────
stage "STEP 1 · HTTP 로그인 (CSRF 폼토큰)"
curlh "$BASE/login" > "$TMP/login.html"
FORM_CSRF=$(grep -o 'name="_csrf_token" value="[^"]*"' "$TMP/login.html" | head -1 | sed 's/.*value="\([^"]*\)".*/\1/')
[ -n "$FORM_CSRF" ] && ok "로그인 폼 CSRF 토큰 획득" || bad "로그인 폼 CSRF 토큰 없음"
LOGIN_CODE=$(curlh -o "$TMP/after_login.html" -w '%{http_code}' \
  --data-urlencode "mb_id=$QA_USER" --data-urlencode "mb_password=$QA_PW" \
  --data-urlencode "_csrf_token=$FORM_CSRF" "$BASE/admin/index.php")
# 로그인 성공 시 302 리다이렉트
if [ "$LOGIN_CODE" = "302" ] || [ "$LOGIN_CODE" = "200" ]; then
  # 세션이 실제로 인증됐는지: 보호 페이지가 로그인으로 안 튕기는지 확인
  WHO=$(curlh -o /dev/null -w '%{http_code}' "$BASE/admin/main.php")
  [ "$WHO" = "200" ] && ok "로그인 성공 (보호 페이지 200)" || bad "로그인 후 세션 미인증 (main.php=$WHO)"
else
  bad "로그인 응답 코드 $LOGIN_CODE"
fi

# ── 인증 페이지에서 AJAX용 CSRF(meta) 획득 ──
curlh "$BASE/setup-map-basic" > "$TMP/basic.html"
META_CSRF=$(grep -o '<meta name="csrf-token" content="[^"]*"' "$TMP/basic.html" | head -1 | sed 's/.*content="\([^"]*\)".*/\1/')
[ -n "$META_CSRF" ] && ok "AJAX용 CSRF(meta) 토큰 획득" || bad "meta csrf-token 없음 (인증 안 됐거나 페이지 오류)"

apipost(){ curlh -H "Content-Type: application/json" -H "X-CSRF-TOKEN: $META_CSRF" -X POST --data "$2" "$BASE$1"; }

# ── 2) [WRITE] 부모 자리타입 생성 (관리비+정상가) ───────────────────────────
stage "STEP 2 · [WRITE] 부모 자리타입 생성 → DB 저장 확인"
RESP=$(apipost "/setting/api/burial_category_spot_types.php" \
  "{\"category_id\":$CAT_ID,\"name\":\"_E2E부모$$\",\"cols\":1,\"capacity\":1,\"is_communal\":0,\"maintenance_fee\":5000,\"list_price\":10000000,\"bg_color\":\"#dbeafe\",\"border_color\":\"#93c5fd\",\"sort_order\":99}")
echo "$RESP" | grep -q '"success":true' && ok "부모 생성 API 성공" || bad "부모 생성 실패: $(echo "$RESP" | head -c 200)"
PARENT_TYPE_ID=$(mq "SELECT id FROM burial_category_spot_types WHERE name='_E2E부모$$' AND deleted_at IS NULL LIMIT 1")
ROW=$(mq "SELECT CONCAT(maintenance_fee,'/',list_price) FROM burial_category_spot_types WHERE id=$PARENT_TYPE_ID")
[ "$ROW" = "5000/10000000" ] && ok "DB 저장 검증: 부모 관리비/정상가 = $ROW" || bad "DB 값 불일치: $ROW (기대 5000/10000000)"

# ── 3) [WRITE] 자리별 전용타입 localize → 독립성 ────────────────────────────
stage "STEP 3 · [WRITE] 자리 전용타입(자식) 생성 → DB 독립 확인"
RESP=$(apipost "/setting/api/burial_spot_custom_types.php" \
  "{\"spot_id\":$SPOT_ID,\"source_type_id\":$PARENT_TYPE_ID,\"name\":\"_E2E자식$$\",\"cols\":1,\"capacity\":1,\"is_communal\":0,\"maintenance_fee\":7777,\"list_price\":9999999,\"bg_color\":\"#dbeafe\",\"border_color\":\"#93c5fd\",\"sort_order\":99,\"replace_source\":false}")
echo "$RESP" | grep -q '"success":true' && ok "자식 생성 API 성공" || bad "자식 생성 실패: $(echo "$RESP" | head -c 200)"
CHILD_TYPE_ID=$(mq "SELECT id FROM burial_spot_custom_types WHERE name='_E2E자식$$' AND deleted_at IS NULL LIMIT 1")
CROW=$(mq "SELECT CONCAT(maintenance_fee,'/',list_price) FROM burial_spot_custom_types WHERE id=$CHILD_TYPE_ID")
PROW=$(mq "SELECT CONCAT(maintenance_fee,'/',list_price) FROM burial_category_spot_types WHERE id=$PARENT_TYPE_ID")
[ "$CROW" = "7777/9999999" ] && ok "DB 저장 검증: 자식 관리비/정상가 = $CROW (전용값)" || bad "자식 DB 값 불일치: $CROW"
[ "$PROW" = "5000/10000000" ] && ok "독립성 검증: 자식 저장 후에도 부모 = $PROW 그대로" || bad "독립성 위반: 부모가 $PROW 로 바뀜"

# ── 4) [READ] 자리별 타입 목록 병합(상속/전용) ──────────────────────────────
stage "STEP 4 · [READ] 자리 타입 목록 — 상속/전용 병합 확인"
LIST=$(curlh "$BASE/setting/api/burial_spot_custom_types.php?spot_id=$SPOT_ID")
echo "$LIST" | php -r '
  $j=json_decode(file_get_contents("php://stdin"),true);
  $rows=$j["data"]??[];
  $childId=(int)($argv[1]??0);
  $found=null; foreach($rows as $r){ if((int)($r["id"]??0)===$childId && ($r["type_scope"]??"")==="spot"){ $found=$r; break; } }
  if($found && (int)($found["is_localized"]??0)===1 && (int)($found["list_price"]??0)===9999999){ echo "OK\n"; }
  else { echo "FAIL:".json_encode($found,JSON_UNESCAPED_UNICODE)."\n"; }
' "$CHILD_TYPE_ID" | { read r; case "$r" in OK) ok "병합 목록에 전용타입 노출 (is_localized=1, 정상가 9,999,999)";; *) bad "병합 목록 확인 실패: ${r#FAIL:}";; esac; }

# ── 5) [READ] 계약 API — 2계층 관리비 해석 ──────────────────────────────────
stage "STEP 5 · [READ] 계약 API(get_current_maintenance_base) 응답"
CID=$(mq "SELECT id FROM burial_contracts WHERE state IN (1,4) ORDER BY id LIMIT 1")
if [ -n "$CID" ]; then
  CRESP=$(curlh "$BASE/admin/api/contract/save.php?action=get_current_maintenance_base&contract_id=$CID&cell_id=1&spot_id=1")
  echo "$CRESP" | grep -q '"success":true' && ok "계약 관리비 기준 조회 API 성공 (contract #$CID)" || bad "계약 API 응답 이상: $(echo "$CRESP" | head -c 200)"
else
  ok "활성 계약 없음 — 계약 API 호출 생략(스킵)"
fi

# ── 요약 ─────────────────────────────────────────────────────────────────────
printf '\n\033[1m━━ E2E 결과\033[0m\n  통과 %d · 실패 %d\n' "$PASS" "$FAIL"
[ "$FAIL" -eq 0 ] && printf '  \033[32m전체 통과\033[0m\n' || printf '  \033[31m실패 확인 필요\033[0m\n'
# cleanup 은 trap 으로 자동 실행
[ "$FAIL" -eq 0 ]
