#!/usr/bin/env bash
#   2026-07-03 yjmoon  설치 후 HTTPS 켜기 — 이미 http 로 설치된 서버에 SSL 만 얹는 전용 스크립트. (prod 전용)
#                      install.sh 전체 재실행(이미지 load·시크릿 재생성) 없이, setup_ssl.sh 로 인증서·override
#                      를 생성하고 gateway 컨테이너만 재생성한다. 데이터·다른 컨테이너 무영향.
#
#   쓰는 때:
#     · 신규 설치부터 HTTPS = install.sh --ssl (이 스크립트 아님)
#     · 이미 http 로 돌고 있는데 나중에 HTTPS 로 전환 = 이 스크립트
#
#   사용법 (서버 호스트에서 실행):
#     sudo ./enable_ssl.sh --domain=prism.acme.co --cert-path=/root/cert   # 정식 cert
#     sudo ./enable_ssl.sh --domain=prism.acme.co                          # self-signed(브라우저 경고)
#     sudo ./enable_ssl.sh                                                 # server_name _, self-signed
#
#   전제: install.sh(prod) 로 설치 완료(= $INSTALL_ROOT/.env + gateway 컨테이너 기동 중).
set -euo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

RED='\033[31m'; GREEN='\033[32m'; CYAN='\033[36m'; YELLOW='\033[33m'; NC='\033[0m'
step() { printf "${CYAN}▶ %s${NC}\n" "$*"; }
ok()   { printf "${GREEN}  ✓${NC} %s\n" "$*"; }
warn() { printf "${YELLOW}  ⚠${NC} %s\n" "$*"; }
die()  { printf "${RED}  ✗${NC} %s\n" "$*" >&2; exit 1; }

# ── 인자 파싱 (install.sh 의 SSL 옵션과 동일 이름) ──────────────────────────
PRISM_ENV="prod"
SSL_DOMAIN=""
SSL_CERT_PATH=""
SSL_PORT=443
INSTALL_ROOT_ARG=""
for arg in "$@"; do
  case "$arg" in
    --env=*)           PRISM_ENV="${arg#*=}" ;;
    --domain=*)        SSL_DOMAIN="${arg#*=}" ;;
    --cert-path=*)     SSL_CERT_PATH="${arg#*=}" ;;
    --ssl-port=*)      SSL_PORT="${arg#*=}" ;;
    --install-root=*)  INSTALL_ROOT_ARG="${arg#*=}" ;;
    --help|-h)
      cat <<EOF
설치 후 HTTPS 켜기 (이미 http 로 설치된 prod 서버 대상)

옵션:
  --domain=<fqdn>     server_name (선택, 예: prism.acme.co)
  --cert-path=<dir>   인증서 디렉토리 (선택, 정식 cert). 인식 이름:
                      cert = server.crt/fullchain.pem/cert.pem, key = server.key/privkey.pem/key.pem
  --ssl-port=<port>   HTTPS 포트 (기본 443)
  --install-root=<d>  설치 루트 직접 지정 (기본: /opt/prism-cosmos)

  cert-path 없으면 self-signed(브라우저 경고). 정식 운영은 --cert-path 권장.
  실행하면 gateway 만 재생성됩니다. 이때 기존 http 도 수 초 순단됩니다(트래픽 낮은 시간 권장).
  데이터/다른 컨테이너는 그대로. dev 는 미지원(멀티인스턴스/override 조합).
EOF
      exit 0 ;;
    *) die "알 수 없는 인자: $arg (--help 참조)" ;;
  esac
done

# ── env 매트릭스 — 이 스크립트는 prod(정식 운영) 전용 ──────────────────────
#   dev 는 per-user override(포트·container_name)가 사용자마다 달라 gateway 안전 재생성 불가
#   (설치 패키지에도 dev compose 미동봉). install.sh 도 dev 를 --ssl 정식 대상으로 보지 않음.
[ "$PRISM_ENV" = "prod" ] || die "이 스크립트는 prod 전용입니다 (--env=$PRISM_ENV 미지원). dev 는 -f dev.yml 조합으로 직접 구성하세요."
PROJECT="prism-cosmos-prod"
INSTALL_ROOT="${INSTALL_ROOT_ARG:-/opt/prism-cosmos}"
ROOT="$INSTALL_ROOT"

# ── 전제 검증 — 설치 완료 상태여야 (신규 설치는 install.sh --ssl 이 담당) ──
[ -f "$ROOT/.env" ] || die ".env 없음: $ROOT/.env. 먼저 install.sh 로 설치하세요 (--install-root 로 경로 지정 가능)"
[ -x "$HERE/setup_ssl.sh" ] || die "setup_ssl.sh 없음/실행불가: $HERE/setup_ssl.sh. 설치 패키지 동봉 확인"

# ── 컨테이너 이름 조립 (install.sh 와 동일: .env 의 PRISM_SUFFIX / PRISM_NAME_BASE 재사용) ──
#   2026-07-03 yjmoon  grep 0매칭(옛 설치=키 없음)도 set -e/pipefail 에 안 죽도록 || true 로 흡수.
_env_get() { { grep "^$1=" "$ROOT/.env" 2>/dev/null || true; } | head -1 | cut -d= -f2- | tr -d '"'; }
#   2026-07-08 yjmoon  PRISM_SUFFIX 폴백 install.sh 정합 — 옛 설치는 .env 에 PRISM_SUFFIX 키 자체가 없어
#     _env_get 이 빈값을 줬고, 컨테이너는 cosmos-gateway-prod(suffix=prod)인데 suffix 누락 → cosmos-gateway
#     오조회 → '미발견' die 하던 버그(LS오토모티브 2026-07-08). install.sh(137-143)와 동일하게
#     '키 있으면 그 값 / .env 는 있는데 키 없으면 옛 prod 설치 = prod' 로 폴백. 신규는 .env 에 빈값이
#     명시돼(PRISM_SUFFIX=) grep 매칭 → 빈값 유지(회귀 0). export 로 compose container_name 조립에도 반영.
if grep -q '^PRISM_SUFFIX=' "$ROOT/.env" 2>/dev/null; then
  PRISM_SUFFIX="$(_env_get PRISM_SUFFIX)"
else
  PRISM_SUFFIX="prod"
fi
PRISM_NAME_BASE="$(_env_get PRISM_NAME_BASE)"
[ -n "$PRISM_NAME_BASE" ] || PRISM_NAME_BASE="cosmos"   # 옛 설치(.env 에 키 없음) = cosmos 보존
export PRISM_SUFFIX PRISM_NAME_BASE   # compose up -d gateway 가 동일 container_name 을 재조립하도록
_HTTP_PORT="$(_env_get GATEWAY_PORT)"; [ -n "$_HTTP_PORT" ] || _HTTP_PORT=8200
SUFFIX="${PRISM_SUFFIX:+-$PRISM_SUFFIX}"
GW_CONTAINER="${PRISM_NAME_BASE}-gateway${SUFFIX}"

#   2026-07-08 yjmoon  안전망 — 조립 이름이 실제로 없으면 prod 프로젝트에서 gateway 컨테이너를 직접 탐지해
#     이름·suffix 를 보정(이름 규칙이 더 어긋난 설치까지 커버). 보정한 suffix 를 export 해 step 2 compose
#     재생성도 같은 이름으로 정합(엉뚱한 새 이름 컨테이너 생성 방지).
if ! docker inspect "$GW_CONTAINER" >/dev/null 2>&1; then
  _detected="$(docker ps -a --filter "label=com.docker.compose.project=$PROJECT" --format '{{.Names}}' 2>/dev/null | grep -E '(^|-)gateway(-|$)' | head -1 || true)"
  if [ -n "$_detected" ] && [ "$_detected" != "$GW_CONTAINER" ]; then
    warn "조립 이름 '$GW_CONTAINER' 미발견 → 실행 중인 '$_detected' 로 보정 (.env 의 PRISM_SUFFIX 누락 추정)."
    GW_CONTAINER="$_detected"
    _sfx="${_detected#${PRISM_NAME_BASE}-gateway}"; _sfx="${_sfx#-}"   # cosmos-gateway-prod → prod
    PRISM_SUFFIX="$_sfx"; export PRISM_SUFFIX; SUFFIX="${_sfx:+-$_sfx}"
  fi
fi

# gateway 가 실제로 떠 있어야 사후 전환 의미가 있음 (nginx -t 이미지 태그도 여기서 취득).
docker inspect "$GW_CONTAINER" >/dev/null 2>&1 \
  || die "gateway 컨테이너 '$GW_CONTAINER' 미발견. 설치가 완료됐고 기동 중인지 확인 (docker ps)"
GATEWAY_IMAGE="$(docker inspect -f '{{.Config.Image}}' "$GW_CONTAINER" 2>/dev/null || true)"
[ -n "$GATEWAY_IMAGE" ] || die "gateway 이미지 태그 취득 실패 ($GW_CONTAINER)"

# ── compose 본체 탐지 (prod SSOT = docker-compose.yml, 6-28 통일 이전 설치 = docker-compose.prod.yml) ──
#   2026-07-06 yjmoon  파일명 하드코딩 → 실존 감지. compose 통일(6-28) 이전 최초설치 서버는 패치 이력에
#     따라 docker-compose.yml(compose 패치 받음) 또는 docker-compose.prod.yml(안 받음)이 남음 → 둘 다 커버.
#     신규 설치는 항상 yml 이라 폴백 미발동(회귀 0).
COMPOSE_FILE="$ROOT/ops/docker/docker-compose.yml"
[ -f "$COMPOSE_FILE" ] || COMPOSE_FILE="$ROOT/ops/docker/docker-compose.prod.yml"
[ -f "$COMPOSE_FILE" ] || die "compose 파일 없음: $ROOT/ops/docker/docker-compose.yml (또는 docker-compose.prod.yml)"
OVERRIDE_FILE="$ROOT/ops/docker/docker-compose.override.yml"

echo "  대상: project=$PROJECT / gateway=$GW_CONTAINER / http 포트=$_HTTP_PORT / https 포트=$SSL_PORT"
echo "  인증서: ${SSL_CERT_PATH:-(self-signed 생성)}   도메인: ${SSL_DOMAIN:-_ (모든 호스트)}"
[ -z "$SSL_CERT_PATH" ] && warn "self-signed 를 새로 생성합니다. 재실행 시 브라우저에 저장된 신뢰 예외가 초기화될 수 있습니다."

# ── 1. SSL 산출물 생성 (setup_ssl.sh = cert·ssl.conf·override.yml + nginx -t 검증) ──
step "1/2  SSL 구성 생성 (인증서, https 설정, override). setup_ssl.sh"
INSTALL_ROOT="$ROOT" SSL_PORT="$SSL_PORT" DOMAIN="$SSL_DOMAIN" CERT_PATH="$SSL_CERT_PATH" \
  PRISM_ENV="$PRISM_ENV" PROJECT="$PROJECT" GATEWAY_IMAGE="$GATEWAY_IMAGE" \
  bash "$HERE/setup_ssl.sh" || die "SSL 구성 실패 (setup_ssl.sh). 위 오류 확인. gateway 는 손대지 않았습니다."
[ -f "$OVERRIDE_FILE" ] || die "override.yml 미생성. setup_ssl.sh 점검"

# ── 2. gateway 만 재생성 (base + override 병합) — 다른 컨테이너 무영향 ──────
warn "gateway 재생성 중 기존 http(포트 $_HTTP_PORT)도 수 초 순단됩니다. 활성 세션이 있으면 잠깐 끊깁니다."
step "2/2  gateway 재생성 (443 포트 + 인증서 마운트 반영)"
#   --env-file 로 .env 주입, -f base -f override 병합. gateway 만 지정 → 다른 서비스는 그대로.
docker compose --env-file "$ROOT/.env" -f "$COMPOSE_FILE" -f "$OVERRIDE_FILE" -p "$PROJECT" up -d gateway \
  || die "gateway 재생성 실패. 'docker logs $GW_CONTAINER' 확인. override.yml 은 생성됨(재실행 가능)."
ok "gateway 재생성 완료"

# ── https health 검증 (443 200) + 실패 시 복구 안내 ───────────────────────
_RECOVER="rm '$OVERRIDE_FILE' && docker compose --env-file '$ROOT/.env' -f '$COMPOSE_FILE' -p '$PROJECT' up -d gateway"
echo -n "  https 응답 대기 (port $SSL_PORT)..."
_ok=0
for i in $(seq 1 30); do
  code=$(curl -sk -o /dev/null -w "%{http_code}" "https://127.0.0.1:${SSL_PORT}/health" 2>/dev/null || echo "000")
  if [ "$code" = "200" ]; then echo " OK (${i}s)"; _ok=1; break; fi
  sleep 1
done
if [ "$_ok" -ne 1 ]; then
  echo " TIMEOUT"
  #   2026-07-03 yjmoon  실패 시 override 가 디스크에 남아 이후 재기동에도 자동 병합됨(install_core elif).
  #     롤백은 사용자 판단이 낫지만(cert 만 문제인지, gateway 자체가 죽었는지 다름), 되돌리는 원커맨드와
  #     기존 http 생사를 명시해 판단을 돕는다.
  printf "${RED}  ✗${NC} https 200 대기 timeout (${SSL_PORT}). 'docker logs %s' 확인 (cert/포트/방화벽)\n" "$GW_CONTAINER" >&2
  _http=$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:${_HTTP_PORT}/health" 2>/dev/null || echo "000")
  if [ "$_http" = "200" ]; then
    echo "  ℹ 기존 http(포트 ${_HTTP_PORT})는 정상. 서비스 접속은 계속 가능합니다." >&2
  else
    echo "  ⚠ 기존 http(포트 ${_HTTP_PORT})도 응답 없음. gateway 가 안 떴을 수 있습니다(로그 확인)." >&2
  fi
  echo "  ↩ http 전용으로 되돌리려면:  $_RECOVER" >&2
  exit 1
fi

echo
echo "================================================================="
echo "  ✅ HTTPS 활성화 완료"
echo "================================================================="
echo "  HTTPS:  https://${SSL_DOMAIN:-<서버IP>}:${SSL_PORT}/   (기존 http 포트 ${_HTTP_PORT} 도 유지)"
[ -z "$SSL_CERT_PATH" ] && echo "  (self-signed. 브라우저 보안 경고. 정식 cert = --cert-path 로 재실행)"
echo "  되돌리기(http 전용):  $_RECOVER"
echo
