#!/bin/bash

source $1
export BACKUP_DIR=/tmp
export LOG_FILE=/var/log/whatap_update.log
export PATCH_RESULT_FILE="$INSTALL_DIR/patch_history.log"

#pkg="$1" 
if [[ -z "${pkg:-}" ]]; then
	echo "usage: $0 <pkg-file>"
	exit 2
fi

os_id="" ; os_like=""
if [[ -r /etc/os-release ]]; then
	os_id=$(awk -F= '$1=="ID"{gsub(/"/,"");print tolower($2)}' /etc/os-release)
	os_like=$(awk -F= '$1=="ID_LIKE"{gsub(/"/,"");print tolower($2)}' /etc/os-release)
fi

is_like() {
	[[ "$os_id" == *"$1"* ]] || [[ "$os_like" == *"$1"* ]]
}

# Logging function
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

# Error handling
error_exit() {
    log "ERROR: $1"
    exit 1
}

error() {
    log "ERROR: $1"
}

# Patch result logging functions
write_patch_result() {
    local status="$1"
    local patch_version="$2"
    local start_time="$3"
    local error_message="$4"
    local end_time=$(date '+%Y-%m-%d %H:%M:%S')

    # Format: status|patch_version|start_time|end_time|error_message
    echo "$status|$patch_version|$start_time|$end_time|$error_message" >> "$PATCH_RESULT_FILE"
    log "Patch result written to $PATCH_RESULT_FILE"
}

get_patch_version() {
    local pkg_file="$1"
    local version=""

    # Extract version from package
    if [[ "$pkg_type" == "tar" ]]; then
        # Read conf/VERSION from tarball without full extraction
        version=$(tar -xzf "$pkg_file" -O "whatap-infra/conf/VERSION" 2>/dev/null | head -1 | tr -d '[:space:]')
        [[ -z "$version" ]] && version=$(basename "$pkg_file" | sed -E 's/.*-([0-9]+\.[0-9]+\.[0-9]+)-.*/\1/')
        [[ -z "$version" ]] && version="unknown"
    elif [[ "$pkg_type" == "deb" ]] && need dpkg-deb; then
        version=$(dpkg-deb --field "$pkg_file" Version 2>/dev/null || echo "unknown")
    elif [[ "$pkg_type" == "rpm" ]] && need rpm; then
        version=$(rpm -qp --qf '%{VERSION}.%{RELEASE}\n' "$pkg_file" 2>/dev/null || echo "unknown")
    else
        # Fallback: extract from filename
	version=$(basename "$pkg_file" | sed -E 's/.*-([0-9]+\.[0-9]+)-([0-9]+).*/\1.\2/; t; s/.*_([0-9]+\.[0-9]+\.[0-9]+)_.*/\1/')
        [[ -z "$version" ]] && version=$(basename "$pkg_file")
    fi

    echo "$version"
}


stop_service() {
    log "service stop..."
    service whatap-infra stop
    if [[ $? -ne 0 ]]; then 
        log "service stop error"
    fi
    log "service stop ok"
}

start_service() {
    log "service start..."
    rm -rf $INSTALL_DIR/conf/whatap_infrad.pid
    service whatap-infra start
    if [[ $? -ne 0 ]]; then 
        log "service start error"
    fi
    log "service start ok"
}

backup_whatap() {
    log "creating backup of existing installation..."
    if [[ -d "$INSTALL_DIR" ]]; then
        mkdir -p "$BACKUP_DIR"
        cp -r "$INSTALL_DIR" "$BACKUP_DIR/" || error_exit "failed to create backup"
        log "backup created at $BACKUP_DIR"
    else
        log "no existing installation found to backup"
    fi
    log "backup ok"
}


rollback_whatap() {
    log "rollback start..."
    stop_service
    rm -rf "$INSTALL_DIR" 
    cp -r "$BACKUP_DIR"/infra "$INSTALL_DIR" || error_exit "failed to rollback"
    start_service
    echo " rollback ok"
}

need() { command -v "$1" >/dev/null 2>&1; }

# Extract RPM --prefix from INSTALL_DIR
# e.g., /usr/whatap/infra -> /usr/whatap, /opt/whatap/infra/ -> /opt/whatap, /opt/infra -> /opt
get_rpm_prefix() {
	local install_dir="${INSTALL_DIR%/}"
	local prefix="${install_dir%/infra}"
	if [[ -z "$prefix" ]]; then
		prefix="/usr/whatap"
	fi
	echo "$prefix"
}

install_deb_file() {
	echo "install $pkg..."
	if need dpkg; then
		sudo dpkg -i "$pkg" 
	else
		error "dpkg command not found"
		return 1
	fi

	if [[ $? -ne 0 ]]; then
		error "$pkg install fail"
		return 1
	else
		log "$pkg install ok"
		return 0
	fi
}

install_rpm_file() {
	local rpm_prefix
	rpm_prefix=$(get_rpm_prefix)
	log "install $pkg with --prefix=$rpm_prefix ..."
	if need rpm; then
		sudo rpm -Uvh --replacepkgs --oldpackage --prefix="$rpm_prefix" "$pkg"
	elif need dnf; then
		sudo dnf -y install "$pkg"
	elif need yum; then
		sudo yum -y localinstall "$pkg" || sudo rpm -Uvh --replacepkgs --oldpackage "$pkg"
	elif need zypper; then
		sudo zypper --non-interactive install "$pkg"
	else
		error "rpm command not found"
		return 1
	fi

	if [[ $? -ne 0 ]]; then
		error "$pkg install fail"
		return 1
	else
		log "$pkg install ok"
		return 0
	fi
	return $?
}

install_tar_file() {
	local tmp_dir
	tmp_dir=$(mktemp -d) || { error "failed to create temp directory"; return 1; }
	trap 'rm -rf "$tmp_dir"' RETURN

	log "extracting $pkg to $tmp_dir ..."
	if ! tar -xzf "$pkg" -C "$tmp_dir"; then
		error "failed to extract tarball: $pkg"
		return 1
	fi

	# Find install.sh inside extracted directory
	local install_script=""
	if [[ -f "$tmp_dir/whatap-infra/install.sh" ]]; then
		install_script="$tmp_dir/whatap-infra/install.sh"
	else
		# Search for install.sh in extracted contents
		install_script=$(find "$tmp_dir" -maxdepth 2 -name "install.sh" -type f | head -1)
	fi

	if [[ -z "$install_script" || ! -f "$install_script" ]]; then
		error "install.sh not found in tarball"
		return 1
	fi

	chmod +x "$install_script"
	log "running $install_script --prefix $INSTALL_DIR ..."
	if ! bash "$install_script" --prefix "$INSTALL_DIR"; then
		error "install.sh execution failed"
		return 1
	fi

	log "$pkg tarball install ok"
	return 0
}

pkg_type=""
pkg_arch=""
detect_pkg_type() {
	if [[ -f "$pkg" ]]; then
		# Check tarball first by extension
		case "$pkg" in
			*.tar.gz|*.tgz)
				pkg_type="tar"
				pkg_arch=$(uname -m)
				return
				;;
		esac
		if need dpkg-deb && dpkg-deb --info "$pkg" >/dev/null 2>&1; then
			pkg_type="deb"
			pkg_arch=$(dpkg-deb --field "$pkg" Architecture || true)
			return
		fi
		if need rpm && rpm -qp --qf '%{NAME}\n' "$pkg" >/dev/null 2>&1; then
			pkg_type="rpm"
			pkg_arch=$(rpm -qp --qf '%{ARCH}\n' "$pkg" || true)
			return
		fi
		case "$(file -b "$pkg" | tr '[:upper:]' '[:lower:]')" in
			*'debian binary package'*) pkg_type="deb" ;;
			*'rpm'*) pkg_type="rpm" ;;
			*'gzip compressed'*|*'tar archive'*) pkg_type="tar" ; pkg_arch=$(uname -m) ;;
		esac
	fi
}


install_package() {
	echo "install package..."
	# Tarball is OS-independent, handle first
	if [[ "$pkg_type" == "tar" ]]; then
		install_tar_file
	elif is_like "debian" || is_like "ubuntu" || need apt-get; then
		[[ "$pkg_type" == "deb" ]] || { echo "deb-based OS but file is not .deb"; exit 1; }
		install_deb_file
	elif is_like "suse" || need zypper; then
		[[ "$pkg_type" == "rpm" ]] || { echo "suse-based OS but file is not .rpm"; exit 1; }
		install_rpm_file
	elif is_like "rhel" || is_like "centos" || is_like "fedora" || is_like "alma" || is_like "rocky" || is_like "amzn" || need dnf || need yum; then
		[[ "$pkg_type" == "rpm" ]] || { echo "rpm-based OS but file is not .rpm"; exit 1; }
		install_rpm_file
	else
		error "unsupported distro for local file install"
		return 1
	fi

	if [[ $? -ne 0 ]]; then
		error "install package error"
		return 1
	else
		log "install package ok"
		return 0
	fi
}

test_agent() {
	log "testing agent..."

	if [[ -x "$INSTALL_DIR/whatap_infrad" ]]; then
		"$INSTALL_DIR/whatap_infrad" version
		if [[ $? -ne 0 ]]; then
			error "Agent Version Check Failed"
			return 1
		fi
        export WHATAP_HOME="$INSTALL_DIR/conf"
		"$INSTALL_DIR/whatap_infrad" boot-test
		if [[ $? -ne 0 ]]; then
			error "Agent Test Check Failed"
			return 1
		fi
		return 0
	else
		error "agent test fail"
		return 1
	fi
}

check_root() {
    log "checking root privileges..."
    if [[ $EUID -ne 0 ]]; then
        error_exit "This script must be run as root"
    fi
    log "check root ok"
}


check_root


detect_pkg_type
PATCH_START_TIME=$(date '+%Y-%m-%d %H:%M:%S')
PATCH_VERSION=$(get_patch_version "$pkg")
log "Starting patch process for version: $PATCH_VERSION at $PATCH_START_TIME"

backup_whatap
stop_service

###
install_package
if [[ $? -ne 0 ]]; then
	# 패키지 설치 실패 - 롤백
	log "Package installation failed - rollback"
	rollback_whatap
	write_patch_result "rollback" "$PATCH_VERSION" "$PATCH_START_TIME" "Package installation failed"
else
	log "install complete"
	test_agent
	if [[ $? -ne 0 ]]; then
		# 에이전트 테스트 실패 - 롤백
		log "Agent test failed - rollback"
		rollback_whatap
		write_patch_result "rollback" "$PATCH_VERSION" "$PATCH_START_TIME" "Agent test failed"
	else
        # 성공
        start_service
        log "Patch completed successfully"
		write_patch_result "success" "$PATCH_VERSION" "$PATCH_START_TIME" ""
	fi
fi


