#!/usr/bin/env bash
#   하는 일: 제품 버전 표기가 7.0.0 대에서 3.0.0 대로 바뀌면서, 기존 서버가 새 패치를 "낮은 버전"
#     으로 읽는 것을 막는 1회용 맞추기 스크립트다. 옛 업데이터는 버전을 숫자로만 비교해서 7 > 3 이라
#     새 패치를 되돌리기로 오해한다. 그러면 옛 서버는 아예 막히고, 최신 서버는 설치는 되지만 경고창이
#     뜨고 이력에 '이전 버전' 딱지가 남는다. 표에 적힌 버전의 앞자리만 7 에서 3 으로 바꿔두면 없어진다.
#     내용을 되돌리지 않는다. 표에 적힌 버전 글자만 바꾼다. 데이터와 설정은 손대지 않는다.
#
#   돌려야 하는 서버 / 안 돌려도 되는 서버
#     - 2026-08-21 판(7.0.0.20260821) 이상을 이미 받았다  : 필요 없다. 그 판에 판정이 고쳐져 들어가
#       있어서, 3.0.0 패치를 그냥 올리면 경고 없이 설치된다.
#     - 2026-08-21 판을 건너뛰었다(8월 20일 판 이하)      : 3.0.0 패치를 올리기 전에 1회 돌린다.
#     - 새로 설치하는 서버                                : 필요 없다. 처음부터 3.0.0 으로 시작한다.
#
#   쓰는 법 (3.0.0 패치를 올리기 전에 서버에서 1회):
#       bash version_rebase_to_3.sh --dry-run     먼저 무엇이 바뀌는지만 본다
#       bash version_rebase_to_3.sh               실제로 바꾼다
#       bash version_rebase_to_3.sh trinity-prism-pg   DB 컨테이너를 직접 지정할 때
#
#   실행하면 되돌리기용 SQL 파일이 같은 폴더에 만들어진다. 문제가 생기면 그 파일로 원래대로 돌린다.
#
#   2026-08-27 yjmoon  데이터베이스 컨테이너를 찾을 때 이름 앞자리를 cosmos 로 박아두던 것을
#     걷어냄. 지금 설치는 이름이 trinity-prism-pg 라 못 찾고 멈췄다. 쓰는 법에 적힌 예시
#     이름도 같이 바꿨다.
#
#   2026-08-24 yjmoon  안 돌려도 되는 서버를 가르는 판 번호가 틀려 있던 것 고침. 8월 21일 판을
#     건너뛴 경우를 '8월 13일 판 이하' 로 적어 놔서, 8월 19일 판을 쓰는 곳은 자기가 해당되는지
#     알 수 없었다. 8월 21일 판에 판정 고침이 실려 나갔으므로 가르는 자리는 8월 20일 판이다.
#
set -euo pipefail

DRY_RUN=0
PG=""
for _a in "$@"; do
  case "$_a" in
    --dry-run|-n) DRY_RUN=1 ;;
    -h|--help)
      #   안내만 보여준다. 줄 번호로 자르면 안내가 길어질 때 뒤가 잘리고, 끝까지 찍으면
      #   맨 아래 수정이력(날짜로 시작하는 줄)까지 고객 화면에 나간다. 그래서 그 앞까지만 찍는다.
      #   날짜 자리는 {4} 같은 반복 표기를 안 쓰고 글자 수만큼 늘어놓는다. 고객사 서버의 옛 awk 는
      #   반복 표기를 글자 그대로 읽어서, 그 자리가 늘 거짓이 되면 수정이력까지 새어 나간다.
      awk 'NR>1 { if ($0 !~ /^#/) exit
                  if ($0 ~ /^#[ ][ ]*[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] /) exit
                  print }' "$0" | sed 's/^#[[:space:]]\{0,3\}//'
      exit 0 ;;
    -*) echo "[오류] 모르는 선택지: $_a" >&2; exit 1 ;;
    *)  PG="$_a" ;;
  esac
done

# 1. 컨테이너 엔진 결정 (docker 와 podman 둘 다 지원)
ENGINE="${PRISM_ENGINE:-}"
if [[ -z "$ENGINE" ]]; then
  for _e in docker podman; do
    command -v "$_e" >/dev/null 2>&1 || continue
    if "$_e" ps --format '{{.Names}}' 2>/dev/null | grep -q .; then ENGINE="$_e"; break; fi
  done
fi
if [[ -z "$ENGINE" ]]; then
  echo "[오류] docker 나 podman 을 찾지 못했습니다." >&2
  echo "       엔진을 직접 지정해 다시 실행하세요:  PRISM_ENGINE=podman bash $0" >&2
  exit 1
fi

# 2. DB 컨테이너 결정 (인자 우선, 없으면 자동 탐지)
if [[ -z "$PG" ]]; then
  #   2026-08-27 yjmoon: 이름 앞자리를 박지 않는다. 지금 설치는 trinity-prism-pg, 예전 설치는 cosmos-pg 라 둘 다 잡아야 한다.
  mapfile -t CANDIDATES < <("$ENGINE" ps --format '{{.Names}}' 2>/dev/null | grep -E -- '-pg([-_][A-Za-z0-9]+)?$' || true)
  if [[ "${#CANDIDATES[@]}" -eq 0 ]]; then
    echo "[오류] DB 컨테이너(이름이 -pg 로 끝나는 것)를 찾지 못했습니다." >&2
    echo "       실행 중인 DB 컨테이너 이름을 뒤에 붙여 다시 실행하세요:" >&2
    echo "         bash $0 <DB컨테이너명>" >&2
    "$ENGINE" ps --format '  - {{.Names}}   ({{.Image}})' >&2
    exit 1
  elif [[ "${#CANDIDATES[@]}" -gt 1 ]]; then
    echo "[오류] DB 컨테이너가 여러 개입니다. 하나를 뒤에 붙여 지정하세요:" >&2
    printf '  - %s\n' "${CANDIDATES[@]}" >&2
    exit 1
  fi
  PG="${CANDIDATES[0]}"
fi

echo "=== PRISM 버전 표기 맞추기 (엔진=$ENGINE, DB=$PG)$([ "$DRY_RUN" = 1 ] && echo "  [미리보기]") ==="

#   DB 계정은 컨테이너 자체 env 에서 꺼낸다. 고객사마다 계정이 달라도 그대로 통한다.
psql_run() { "$ENGINE" exec -i "$PG" sh -c 'psql -v ON_ERROR_STOP=1 -U "${POSTGRES_USER:-cosmos}" -d "${POSTGRES_DB:-cosmos}" '"$1"; }
psql_q()   { psql_run "-tAF'|'"; }

# 3. 표가 있는지부터 확인
_has=$(psql_q <<'SQL'
SELECT to_regclass('public.prism_release_state') IS NOT NULL;
SQL
)
if [[ "$_has" != "t" ]]; then
  echo "[오류] prism_release_state 표가 없습니다. DB 컨테이너가 맞는지 확인해 주세요." >&2
  exit 1
fi

# 4. 지금 상태
echo
echo "[1/4] 지금 버전 표기:"
psql_run "" <<'SQL'
SELECT tier AS "구분", version AS "버전" FROM prism_release_state ORDER BY tier;
SQL

BEFORE_ROWS=$(psql_q <<'SQL'
SELECT count(*) FROM prism_release_state;
SQL
)

#   되돌리기 파일 - 지금 값을 그대로 되살리는 SQL. 무슨 일이 생기면 이 파일 한 개로 원상복구한다.
STAMP="$(date +%Y%m%d_%H%M%S)"
UNDO="$(cd "$(dirname "$0")" && pwd)/version_rebase_undo_${STAMP}.sql"
{
  echo "--   $(date '+%Y-%m-%d %H:%M:%S') 버전 표기 맞추기 직전 값. 되돌리려면 이 파일을 그대로 실행."
  echo "--   실행:  $ENGINE exec -i $PG sh -c 'psql -U \"\${POSTGRES_USER:-cosmos}\" -d \"\${POSTGRES_DB:-cosmos}\"' < $(basename "$UNDO")"
  echo "BEGIN;"
  psql_q <<'SQL'
SELECT format('UPDATE prism_release_state SET version = %L WHERE tier = %L;', version, tier)
  FROM prism_release_state ORDER BY tier;
SQL
  echo "COMMIT;"
} > "$UNDO"
echo "      되돌리기 파일: $UNDO"

# 5. 예상 밖 버전이 있으면 멈춘다
#   2026-08-19 yjmoon  건드리지 않아도 되는 값을 예상 밖으로 몰아 멈추던 것 수정. 실제 서버의
#     deps, model, install 은 아직 한 번도 패치를 안 받아 1.0.0 인데, 그 값이 중단 조건에 걸려
#     스크립트가 통째로 멈췄다(실측). 3 으로 시작하는 값도 마찬가지다. 이 스크립트를 이미 돌려
#     3.0.1 이나 3.1.0 까지 받은 서버에서 다시 돌리면 멀쩡한데 멈췄다.
#
#   그대로 둬도 되는 것 : 0.x, 1.x, 2.x (새 3.0.0 패치가 더 큼) / 3 으로 시작(이미 새 표기)
#   바꿔야 하는 것     : 7.0.0 으로 시작 / 점 없는 날짜형(어떤 정식 버전보다 커서 전부 막힘)
#   그 밖              : 손대지 않고 멈춘다. 마음대로 건드리면 그 서버가 패치를 영영 못 받을 수 있다.
UNKNOWN=$(psql_q <<'SQL'
SELECT string_agg(tier || '=' || version, ', ' ORDER BY tier)
  FROM prism_release_state
 WHERE version !~ '^7\.0\.0'
   AND version !~ '^[0-9]{8,}$'
   AND version !~ '^3\.'
   AND version !~ '^[0-2]\.';
SQL
)
if [[ -n "$UNKNOWN" ]]; then
  echo >&2
  echo "[중단] 예상하지 못한 버전 표기가 있습니다: $UNKNOWN" >&2
  echo "       임의로 바꾸면 이 서버가 이후 패치를 못 받을 수 있어 손대지 않고 멈춥니다." >&2
  echo "       위 값을 그대로 개발팀에 알려 주세요." >&2
  exit 2
fi

# 6. 바꿀 대상 미리 보기
echo
echo "[2/4] 바뀔 내용:"
psql_run "" <<'SQL'
SELECT tier AS "구분", version AS "지금",
       CASE WHEN version ~ '^7\.0\.0'      THEN regexp_replace(version, '^7\.0\.0', '3.0.0')
            WHEN version ~ '^[0-9]{8,}$'   THEN '0.0.0'
            ELSE version END               AS "바뀐 뒤",
       CASE WHEN version ~ '^3\.'          THEN '이미 맞음'
            WHEN version ~ '^[0-2]\.'      THEN '그대로 둠'
            ELSE '바꿈' END                AS "처리"
  FROM prism_release_state ORDER BY tier;
SQL

if [[ "$DRY_RUN" = 1 ]]; then
  echo
  echo "미리보기라 실제로는 아무것도 바꾸지 않았습니다."
  echo "실제로 적용하려면 --dry-run 없이 다시 실행하세요:  bash $0"
  rm -f "$UNDO"
  exit 0
fi

# 7. 적용 (한 덩어리로 처리해서 중간에 실패하면 전부 되돌아간다)
echo
echo "[3/4] 적용 중..."
psql_run "" <<'SQL'
BEGIN;
--   7.0.0 으로 시작하는 것은 앞자리만 3.0.0 으로. 뒤의 날짜와 빌드번호는 그대로 둔다.
--   설치된 내용이 언제 것인지가 그대로 남아야 다음 패치와 앞뒤가 맞는다.
UPDATE prism_release_state SET version = regexp_replace(version, '^7\.0\.0', '3.0.0')
 WHERE version ~ '^7\.0\.0';
--   아주 옛 설치의 점 없는 날짜형(12자리, 14자리 둘 다)은 숫자로 읽으면 어떤 정식 버전보다도
--   커서 전부 막힌다. 기준선 0.0.0 으로 한 번 내려두면 이후 정식 패치가 정상으로 올라간다.
UPDATE prism_release_state SET version = '0.0.0'
 WHERE version ~ '^[0-9]{8,}$';
COMMIT;
SQL

# 8. 결과 확인 (행 수가 그대로인지도 같이 본다)
echo
echo "[4/4] 바뀐 뒤 버전 표기:"
psql_run "" <<'SQL'
SELECT tier AS "구분", version AS "버전" FROM prism_release_state ORDER BY tier;
SQL

AFTER_ROWS=$(psql_q <<'SQL'
SELECT count(*) FROM prism_release_state;
SQL
)
LEFT7=$(psql_q <<'SQL'
SELECT count(*) FROM prism_release_state WHERE version ~ '^7\.';
SQL
)

if [[ "$BEFORE_ROWS" != "$AFTER_ROWS" ]]; then
  echo "[오류] 줄 수가 달라졌습니다 (전 $BEFORE_ROWS, 후 $AFTER_ROWS). 되돌리기 파일로 복구하세요: $UNDO" >&2
  exit 3
fi
if [[ "$LEFT7" != "0" ]]; then
  echo "[오류] 아직 7 로 시작하는 버전이 $LEFT7 건 남았습니다. 되돌리기 파일로 복구하세요: $UNDO" >&2
  exit 3
fi

echo
echo "완료. 줄 수 $BEFORE_ROWS 건 그대로, 7 로 시작하는 버전 0 건."
echo "이제 시스템 업데이트 화면에서 새 패치(3.0.0 으로 시작)를 평소처럼 올리시면 됩니다."
echo "경고창 없이 정상 업데이트로 진행됩니다."
