#!/usr/bin/env bash
# =============================================================================
# 헬스체크 스크립트 (HTTP / TCP)
# Jenkins Stage 7: Health Check에서 호출
# 사용: health_check.sh --url <URL> [--timeout 60] [--retries 3] [--interval 10]
# =============================================================================
set -euo pipefail

CHECK_URL=""
CHECK_TYPE="http"   # http | tcp
TCP_HOST=""
TCP_PORT=""
TIMEOUT="${HEALTH_TIMEOUT:-60}"
RETRIES="${HEALTH_RETRIES:-3}"
INTERVAL="${HEALTH_INTERVAL:-10}"
EXPECT_STATUS="${EXPECT_STATUS:-200}"
LOG_DIR="${WORKSPACE:-/tmp}/build-logs"
HC_LOG="${LOG_DIR}/healthcheck-$(date +%Y%m%d-%H%M%S).log"

GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[1;33m'; NC='\033[0m'
log()  { echo -e "${GREEN}[HEALTH]${NC} $*" | tee -a "${HC_LOG}"; }
err()  { echo -e "${RED}[ERROR]${NC} $*" | tee -a "${HC_LOG}"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*" | tee -a "${HC_LOG}"; }

mkdir -p "${LOG_DIR}"

while [[ $# -gt 0 ]]; do
    case $1 in
        --url)      CHECK_URL="$2";    CHECK_TYPE="http"; shift 2 ;;
        --host)     TCP_HOST="$2";     CHECK_TYPE="tcp";  shift 2 ;;
        --port)     TCP_PORT="$2";     CHECK_TYPE="tcp";  shift 2 ;;
        --timeout)  TIMEOUT="$2";      shift 2 ;;
        --retries)  RETRIES="$2";      shift 2 ;;
        --interval) INTERVAL="$2";     shift 2 ;;
        --expect)   EXPECT_STATUS="$2";shift 2 ;;
        *) shift ;;
    esac
done

# ── HTTP 헬스체크 ────────────────────────────────────────────────────────────
check_http() {
    log "HTTP 헬스체크: ${CHECK_URL}"
    log "  예상 상태코드: ${EXPECT_STATUS}"
    log "  타임아웃: ${TIMEOUT}초 / 재시도: ${RETRIES}회"

    local attempt=0
    while [[ ${attempt} -lt ${RETRIES} ]]; do
        attempt=$((attempt + 1))
        log "  시도 ${attempt}/${RETRIES}..."

        local http_code
        local response_time_ms
        local start_ns
        start_ns=$(date +%s%N 2>/dev/null || echo 0)

        http_code=$(curl \
            --silent \
            --output /dev/null \
            --write-out "%{http_code}" \
            --max-time "${TIMEOUT}" \
            --connect-timeout 10 \
            --location \
            "${CHECK_URL}" 2>/dev/null || echo "000")

        local end_ns
        end_ns=$(date +%s%N 2>/dev/null || echo 0)
        if [[ "${start_ns}" != "0" ]]; then
            response_time_ms=$(( (end_ns - start_ns) / 1000000 ))
        else
            response_time_ms="N/A"
        fi

        log "  응답: HTTP ${http_code} (${response_time_ms}ms)"

        if [[ "${http_code}" == "${EXPECT_STATUS}" ]]; then
            log "✅ 헬스체크 통과: HTTP ${http_code}"
            return 0
        elif [[ "${http_code}" == "000" ]]; then
            warn "  연결 실패 (타임아웃 또는 접속 거부)"
        else
            warn "  예상과 다른 응답: ${http_code} (예상: ${EXPECT_STATUS})"
        fi

        if [[ ${attempt} -lt ${RETRIES} ]]; then
            log "  ${INTERVAL}초 후 재시도..."
            sleep "${INTERVAL}"
        fi
    done

    err "헬스체크 실패: ${RETRIES}회 모두 실패"
    return 1
}

# ── TCP 헬스체크 ────────────────────────────────────────────────────────────
check_tcp() {
    [[ -z "${TCP_HOST}" ]] && { err "--host 파라미터가 필요합니다"; exit 1; }
    [[ -z "${TCP_PORT}" ]] && { err "--port 파라미터가 필요합니다"; exit 1; }

    log "TCP 헬스체크: ${TCP_HOST}:${TCP_PORT}"

    local attempt=0
    while [[ ${attempt} -lt ${RETRIES} ]]; do
        attempt=$((attempt + 1))
        log "  시도 ${attempt}/${RETRIES}..."

        if timeout "${TIMEOUT}" bash -c \
            "echo >/dev/tcp/${TCP_HOST}/${TCP_PORT}" 2>/dev/null; then
            log "✅ TCP 연결 성공: ${TCP_HOST}:${TCP_PORT}"
            return 0
        fi

        warn "  TCP 연결 실패: ${TCP_HOST}:${TCP_PORT}"
        if [[ ${attempt} -lt ${RETRIES} ]]; then
            log "  ${INTERVAL}초 후 재시도..."
            sleep "${INTERVAL}"
        fi
    done

    err "TCP 헬스체크 실패: ${RETRIES}회 모두 실패"
    return 1
}

# ── 복합 헬스체크 ─────────────────────────────────────────────────────────────
check_composite() {
    # HTTP + 추가 TCP 포트 확인
    check_http || return 1

    if [[ -n "${TCP_HOST}" ]] && [[ -n "${TCP_PORT}" ]]; then
        check_tcp || return 1
    fi

    return 0
}

# ── 메인 ─────────────────────────────────────────────────────────────────────
main() {
    log "=== 헬스체크 시작: $(date) ==="

    case "${CHECK_TYPE}" in
        http)
            [[ -z "${CHECK_URL}" ]] && { err "--url 파라미터가 필요합니다"; exit 1; }
            check_http
            ;;
        tcp)
            check_tcp
            ;;
        composite)
            check_composite
            ;;
        *)
            err "알 수 없는 헬스체크 유형: ${CHECK_TYPE}"
            exit 1
            ;;
    esac

    log "=== 헬스체크 통과 ==="
}

main "$@"
