#!/bin/bash
MV="/bin/mv -f"
RM="/bin/rm -rf"
CP="/bin/cp -rfp"
MKDIR="/bin/mkdir -p"
LN="/bin/ln -nsf"
TEE="/usr/bin/tee -a"
RSYNC="/bin/rsync -avh"
TAR="/bin/tar"

# 数据路径安全检查：TRIM_PKGVAR 为空或指向非应用数据路径时拒绝继续
if [ -z "${TRIM_PKGVAR:-}" ]; then
    echo "ERROR: TRIM_PKGVAR 未设置，无法确定数据存储路径" >&2
    exit 1
fi
case "${TRIM_PKGVAR}" in
    /vol*) ;;                              # 普通应用：数据卷（fnOS 数据盘挂载点）
    /usr/local/apps/@appdata/*) ;;          # root 安装应用：fnOS 系统盘上的应用数据路径
    *) echo "ERROR: TRIM_PKGVAR=${TRIM_PKGVAR} 不是有效的应用数据路径，拒绝继续" >&2; exit 1 ;;
esac
# 确保数据目录存在
/bin/mkdir -p "${TRIM_PKGVAR}" 2>/dev/null || true

INST_ETC="/var/apps/${TRIM_APPNAME}/etc"
INST_VARIABLES="${INST_ETC}/installer-variables"
INST_LOG="/var/log/apps/${TRIM_APPNAME}.log"

FWPORTS_FILE="/var/apps/${TRIM_APPNAME}/etc/${TRIM_APPNAME}.sc"
SHARE_PATH="/var/apps/${TRIM_APPNAME}/shares/${TRIM_APPNAME}"

LOG_FILE="${TRIM_PKGVAR}/${TRIM_APPNAME}.log"
PID_FILE="${TRIM_PKGVAR}/${TRIM_APPNAME}.pid"

SVC_WAIT_TIMEOUT=15

SVC_CWD="${TRIM_PKGVAR}"
SVC_BACKGROUND=y
SVC_WRITE_PID=y
SVC_QUIET=y
DOCKER_NAME=""

DNAME="${TRIM_APPNAME}"

SVC_NO_REDIRECT=""

OUT=/dev/null
if [ -n "${SVC_NO_REDIRECT}" ]; then
  OUT="/dev/null"
else
  OUT="${LOG_FILE}"
fi

# V1.1.8+: 向用户展示错误信息的 Dialog 对话框
# 写入 TRIM_TEMP_LOGFILE 后 exit 1，系统前端会展示该错误
error_exit()
{
    local msg="$1"
    if [ -n "${TRIM_TEMP_LOGFILE:-}" ]; then
        echo "$msg" > "${TRIM_TEMP_LOGFILE}"
    fi
    echo "ERROR: $msg" >&2
    exit 1
}

validate_preinst()
{
echo "validate_preinst"
}
service_preinst()
{
echo "service_preinst"
}
service_postinst()
{
echo "service_postinst"
}
service_preuninst()
{
echo "service_preuninst"
}
service_postuninst()
{
echo "service_postuninst"
}
validate_preupgrade()
{
echo "validate_preupgrade"
}
service_preupgrade()
{
echo "service_preupgrade"
}
service_save()
{
echo "service_save"
}
service_restore()
{
echo "service_restore"
}
service_postupgrade()
{
echo "service_postupgrade"
}
service_preconfig()
{
echo "service_preconfig"
}
service_postconfig()
{
echo "service_postconfig"
}

check_docker()
{
	FILE_PATH="${TRIM_APPDEST}/app/docker-compose.yaml"
	if [ -f "$FILE_PATH" ]; then
		DOCKER_NAME=$(cat $FILE_PATH | grep "container_name" | awk -F ':' '{print $2}' | xargs)
		echo "DOCKER_NAME is set to: $DOCKER_NAME"
	fi
}

check_docker

install_log ()
{
    local _msg_="$@"
    if [ -z "${_msg_}" ]; then
        while IFS=$'\n' read -r line; do
            install_log "${line}"
        done
    else
        echo -e "$(date +'%Y/%m/%d %H:%M:%S')\t${_msg_}" 1>&2
    fi
}

call_func ()
{
    FUNC=$1
    LOG=$2
    if type "${FUNC}" 2>/dev/null | grep -q 'function' 2>/dev/null; then
		if [ -n "${LOG}" ]; then
			install_log "Begin ${FUNC}"
			eval ${FUNC} 2>&1 | ${LOG}
			install_log "End ${FUNC}"
		else
			echo "Begin ${FUNC}" >> ${LOG_FILE}
			eval ${FUNC}         >> ${LOG_FILE}
			echo "End ${FUNC}"   >> ${LOG_FILE}
		fi
    fi
}

get_key_value()
{
        CONFIG_FILE=$1
        KEY=$2
        value=$(cat $CONFIG_FILE | grep -F "${KEY}" | awk -F "=" '{print $2}' | tr -d ' ' | tr -d '"')
        echo $value
}

log_step ()
{
    install_log "===> Step $1. STATUS=${TRIM_APP_STATUS} USER=$USER GROUP=$GROUP SHARE_PATH=${SHARE_PATH}"
}

initialize_variables ()
{
    if [ -n "${USER}" -a -z "${USER_DESC}" ]; then
        USER_DESC="User running ${TRIM_APPNAME}"
    fi
    if [ -n "${GROUP}" -a -z "${GROUP_DESC}" ]; then
        GROUP_DESC="${TRIM_APPNAME} Package Group"
    fi
    if [ -n "${SHARE_PATH}" ]; then
        if [ -n "${wizard_volume}" ]; then
            SHARE_PATH="${wizard_volume}/${SHARE_PATH}"
        fi
        SHARE_VOLUME=$(echo "${SHARE_PATH}" | awk -F/ '{print "/"$2}')
        SHARE_NAME=$(echo "${SHARE_PATH}" | awk -F/ '{print $3}')
    fi
}

load_variables_from_file ()
{
   if [ -n "$1" -a -r "$1" ]; then
      while read -r _line; do
        if [ "$(echo ${_line} | grep -v ^[/s]*#)" != "" ]; then
           _key="$(echo ${_line} | cut --fields=1 --delimiter==)"
           _value="$(echo ${_line} | cut --fields=2- --delimiter==)"
           export "${_key}=${_value}"
        fi
      done < "$1"
   fi
}

save_wizard_variables ()
{
    if [ -e "${INST_VARIABLES}" ]; then
        $RM "${INST_VARIABLES}"
    fi
    if [ -n "${GROUP}" ]; then
        echo "GROUP=${GROUP}" >> ${INST_VARIABLES}
    fi
    if [ -n "${SHARE_PATH}" ]; then
        echo "SHARE_PATH=${SHARE_PATH}" >> ${INST_VARIABLES}
    fi
}

sync_var_folder () {
    if [ -d ${TRIM_APPDEST}/var -a "$(ls -A ${TRIM_APPDEST}/var 2>/dev/null)" ]; then
        echo "Install files from var folder"
        echo "$RSYNC --ignore-existing --remove-source-files ${TRIM_APPDEST}/var/ ${TRIM_PKGVAR}"
        $RSYNC --ignore-existing --remove-source-files ${TRIM_APPDEST}/var/ ${TRIM_PKGVAR}
        find ${TRIM_APPDEST}/var -type f -exec sh -c 'x="{}"; mv "$x" "${x}.new"' \;
        echo "$RSYNC --remove-source-files ${TRIM_APPDEST}/var/ ${TRIM_PKGVAR}"
        $RSYNC --remove-source-files ${TRIM_APPDEST}/var/ ${TRIM_PKGVAR}
        $RM ${TRIM_APPDEST}/var
    fi
}

install_init ()
{
    log_step "install_init"
    call_func "validate_preinst" install_log
    call_func "service_preinst" install_log
    exit 0
}

install_callback ()
{
    log_step "install_callback"
    call_func "save_wizard_variables" install_log
    sync_var_folder
    call_func "service_postinst" install_log
    if [ -n "${LOG_FILE}" ]; then
        echo "Installation log: ${INST_LOG}" >> ${LOG_FILE}
    fi
    exit 0
}

uninstall_init ()
{
    log_step "uninstall_init"
    stop_daemon
    call_func "service_preuninst" install_log
    exit 0
}

uninstall_callback ()
{
    log_step "uninstall_callback"
    call_func "service_postuninst" install_log
    if [ "$wizard_delete_data" = "true" ]; then
        echo "Removing files..." | install_log
        if [ "$(ls -A ${TRIM_PKGHOME})" != "" ]; then
            find ${TRIM_PKGHOME} -mindepth 1 -delete -print | install_log
        fi
        if [ "$(ls -A ${TRIM_PKGVAR})" != "" ]; then
            find ${TRIM_PKGVAR} -mindepth 1 -delete -print | install_log
        fi
        if [ "$(ls -A /var/apps/${TRIM_APPNAME}/etc)" != "" ]; then
            find /var/apps/${TRIM_APPNAME}/etc -mindepth 1 -delete -print | install_log
        fi
    fi
    exit 0
}

upgrade_init ()
{
    log_step "upgrade_init"
    call_func "validate_preupgrade"  install_log
    stop_daemon
    call_func "service_preupgrade" install_log
    call_func "service_save" install_log
    exit 0
}

fix_data_ownership ()
{
    if [ -n "${TRIM_USERNAME}" ] && [ -n "${TRIM_GROUPNAME}" ]; then
        local owner="${TRIM_USERNAME}:${TRIM_GROUPNAME}"
        for dir in "${TRIM_PKGVAR}" "${TRIM_PKGETC}" "${TRIM_PKGHOME}"; do
            if [ -d "$dir" ]; then
                chown -R "$owner" "$dir" 2>/dev/null || true
            fi
        done
    fi
}

upgrade_callback ()
{
    log_step "upgrade_callback"
    call_func "fix_data_ownership" install_log
    call_func "service_restore" install_log
    call_func "service_postupgrade" install_log
    exit 0
}

config_init ()
{
    log_step "config_init"
    call_func "service_preconfig" install_log
    exit 0
}

config_callback ()
{
    log_step "config_callback"
    call_func "service_postconfig" install_log
    exit 0
}

start_daemon ()
{
	if [ -n "$DOCKER_NAME" ]; then
        echo "DOCKER_NAME is set to '$DOCKER_NAME', exiting function."
        return
    fi
    i=0
    if [ -z "${SVC_QUIET}" ]; then
        if [ -z "${SVC_KEEP_LOG}" ]; then
            date > ${LOG_FILE}
        else
            date >> ${LOG_FILE}
        fi
    fi
    call_func "service_prestart"
    printf "%s" "$SERVICE_COMMAND" | while read -r service || [ -n "$service" ]
    do
        i=$((i + 1))
        if [ -z "${SVC_QUIET}" ]; then
            echo "Starting ${DNAME} command ${service}" >> ${LOG_FILE}
        fi
        if [ -n "${service}" ]; then 
            if [ -n "${SVC_CWD}" ]; then
                cd ${SVC_CWD}
            fi
            if [ -z "${SVC_BACKGROUND}" ]; then
                ${service} >> ${OUT} 2>&1
            else
                ${service} >> ${OUT} 2>&1 &
            fi    
            if [ -n "${SVC_WRITE_PID}" -a -n "${SVC_BACKGROUND}" -a -n "${PID_FILE}" ]; then
                 [ $i -eq 1 ] && printf "%s" "$!" > ${PID_FILE} || printf "\n%s" "$!" >> ${PID_FILE}
            else
                wait_for_status 0 ${SVC_WAIT_TIMEOUT:=20}
            fi
        fi
    done
}

stop_daemon ()
{
	if [ -n "$DOCKER_NAME" ]; then
        echo "DOCKER_NAME is set to '$DOCKER_NAME', exiting function."
        return
    fi
    if [ -n "${PID_FILE}" -a -r "${PID_FILE}" ]; then
        for pid in $(cat "${PID_FILE}")
        do
            if [ -z "$pid" ]; then
              continue
            fi
            if [ -z "${SVC_QUIET}" ]; then
                date >> ${LOG_FILE}
                echo "Stopping ${DNAME} service : $(ps -p${pid} -o comm=) (${pid})" >> ${LOG_FILE}
            fi
            kill -TERM ${pid} >> ${LOG_FILE} 2>&1
            wait_for_status 1 ${SVC_WAIT_TIMEOUT:=20} ${pid} || kill -KILL ${pid} >> ${LOG_FILE} 2>&1
        done
        if [ -f "${PID_FILE}" ]; then
            rm -f "${PID_FILE}" > /dev/null
        fi
    fi
    call_func "service_poststop"
}

daemon_status ()
{
	if [ -n "$DOCKER_NAME" ]; then
        docker inspect $DOCKER_NAME | grep -q "\"Status\": \"running\"," || exit 1
        return
    fi	
    status=0
    [ -z "${1}" ] && pid_list=$(cat ${PID_FILE} 2>/dev/null) || pid_list=${1}
    if [ -n "${pid_list}" ]; then
        for pid in ${pid_list}
        do
           kill -0 ${pid} > /dev/null 2>&1
           status=$((status + $?))
        done
        if [ $status -ne 0 ]; then
           rm -f "${PID_FILE}" > /dev/null
           return 1
        else
           return 0
        fi
    else
        return 1
    fi
}

wait_for_status ()
{
    counter=${2}
    counter=${counter:=20}
    while [ ${counter} -gt 0 ]; do
        daemon_status ${3}
        [ $? -eq $1 ] && return
        counter=$((counter - 1))
        sleep 1
    done
    return 1
}
