#!/usr/bin/env bash
# 由 scripts/compose-install.sh 生成，请勿手工编辑。
set -euo pipefail
NGC_COMPOSED=1
trap cleanup EXIT
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM

# shellcheck shell=bash
# 在线/离线安装与卸载的共享实现。
# 本文件不直接执行，由 scripts/compose-install.sh 注入到生成的脚本中。

PROJECT_NAME="nginx-config-control"
MAIN_COMMAND="ngc"
PLATFORM="unix"
PUBLISHED_PLATFORMS="unix"
DEFAULT_BASE_URL="https://files.tymler.work"
BASE_URL_ENV="NGINX_CONFIG_CONTROL_BASE_URL"
INSECURE_ENV="NGINX_CONFIG_CONTROL_INSECURE"

PREFIX=""
SHELL_CHOICE=""
BASE_URL_ARG=""
REINSTALL=0
FORCE=0
INSECURE=0
TMP_DIR=""

BLOCK_START="# >>> nginx-config-control >>>"
BLOCK_END="# <<< nginx-config-control <<<"

log() {
  printf '%s\n' "$*" >&2
}

die() {
  printf '%s: %s\n' "$PROJECT_NAME" "$1" >&2
  exit "${2:-1}"
}

cleanup() {
  if [ -n "${TMP_DIR:-}" ] && { [ -e "$TMP_DIR" ] || [ -L "$TMP_DIR" ]; }; then
    rm -rf -- "$TMP_DIR"
  fi
}

env_value() {
  eval "printf '%s' \"\${$1:-}\""
}

sanitize_value() {
  value=$1
  value=$(printf '%s\n' "$value" | sed -E 's/[[:space:]]+#.*$//')
  value=$(printf '%s\n' "$value" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')
  case "$value" in
    \"*\") value=${value#\"}; value=${value%\"} ;;
    \'*\') value=${value#\'}; value=${value%\'} ;;
  esac
  printf '%s' "$value"
}

parse_args() {
  while [ $# -gt 0 ]; do
    case "$1" in
      --prefix)
        [ $# -ge 2 ] || { usage; die "--prefix 需要参数" 2; }
        PREFIX=$2
        shift 2
        ;;
      --prefix=*) PREFIX=${1#*=}; shift ;;
      --shell)
        [ $# -ge 2 ] || { usage; die "--shell 需要参数" 2; }
        SHELL_CHOICE=$2
        shift 2
        ;;
      --shell=*) SHELL_CHOICE=${1#*=}; shift ;;
      --base-url)
        [ $# -ge 2 ] || { usage; die "--base-url 需要参数" 2; }
        BASE_URL_ARG=$2
        shift 2
        ;;
      --base-url=*) BASE_URL_ARG=${1#*=}; shift ;;
      --reinstall) REINSTALL=1; shift ;;
      --force) FORCE=1; shift ;;
      --insecure) INSECURE=1; shift ;;
      -h|--help) usage; exit 0 ;;
      --) shift; break ;;
      -*) usage; die "未知选项: $1" 2 ;;
      *) usage; die "未知参数: $1" 2 ;;
    esac
  done
  if [ $# -gt 0 ]; then
    usage
    die "未知参数: $1" 2
  fi
  case "$SHELL_CHOICE" in
    ''|bash|zsh) ;;
    *) usage; die "--shell 只能是 bash 或 zsh" 2 ;;
  esac
  if [ -n "$PREFIX" ]; then
    PREFIX=${PREFIX%/}
    [ -n "$PREFIX" ] || { usage; die "--prefix 不能为空" 2; }
  fi
  if [ "$(env_value "$INSECURE_ENV")" = "1" ]; then
    INSECURE=1
  fi
}

install_conf_path() {
  printf '%s' "${XDG_CONFIG_HOME:-${HOME:-$PWD}/.config}/$PROJECT_NAME/install.conf"
}

peek_base_url() {
  peek_value=""
  if [ -n "$BASE_URL_ARG" ]; then
    peek_value=$BASE_URL_ARG
  else
    peek_value=$(env_value "$BASE_URL_ENV")
    if [ -z "$peek_value" ]; then
      peek_conf=$(install_conf_path)
      if [ -f "$peek_conf" ] && [ -r "$peek_conf" ]; then
        peek_value=$(sed -nE 's/^[[:space:]]*base_url[[:space:]]*=[[:space:]]*(.*)$/\1/p' "$peek_conf" | tail -n 1)
        peek_value=$(sanitize_value "$peek_value")
      fi
    fi
    if [ -z "$peek_value" ]; then
      peek_value=$DEFAULT_BASE_URL
    fi
  fi
  printf '%s' "${peek_value%/}"
}

resolve_base_url() {
  base_url_value=$(peek_base_url)
  if [ -z "$base_url_value" ]; then
    die "未配置基地址：请使用 --base-url URL、设置 $BASE_URL_ENV，或在 $(install_conf_path) 写入 base_url=..." 2
  fi
  printf '%s' "$base_url_value"
}

detect_platform() {
  case "$(uname -s 2>/dev/null)" in
    Darwin) printf 'macos' ;;
    *) printf 'unix' ;;
  esac
}

# 校验本机平台与脚本所属平台一致；不一致时给出本机应使用的入口地址。
require_platform() {
  req_expected=$1
  req_entry=$2
  req_base=${3:-}
  req_detected=$(detect_platform)
  if [ "$req_detected" != "$req_expected" ]; then
    case " $PUBLISHED_PLATFORMS " in
      *" $req_detected "*)
        if [ -n "$req_base" ]; then
          die "本脚本属于 $req_expected 平台，当前系统为 $req_detected；请改用 $req_base/$PROJECT_NAME/$req_detected/$req_entry" 2
        fi
        die "本脚本属于 $req_expected 平台，当前系统为 $req_detected；请改用 $req_detected 平台目录下的 $req_entry" 2
        ;;
      *)
        die "当前系统为 $req_detected；本项目仅发布 $PUBLISHED_PLATFORMS 平台，不提供 $req_detected 制品" 2
        ;;
    esac
  fi
  printf '%s' "$req_detected"
}

detect_shell() {
  if [ -n "$SHELL_CHOICE" ]; then
    printf '%s' "$SHELL_CHOICE"
    return 0
  fi
  shell_candidate=""
  if [ -n "${SHELL:-}" ]; then
    shell_candidate=${SHELL##*/}
  fi
  case "$shell_candidate" in
    bash|zsh) printf '%s' "$shell_candidate"; return 0 ;;
  esac
  shell_candidate=""
  if command -v ps >/dev/null 2>&1; then
    if ps_out=$(ps -o comm= -p "${PPID:-0}" 2>/dev/null); then
      shell_candidate=${ps_out##*/}
    fi
  fi
  case "$shell_candidate" in
    bash|zsh) printf '%s' "$shell_candidate" ;;
    *) die "无法确定当前 shell，请使用 --shell bash 或 --shell zsh" 2 ;;
  esac
}

download_file() {
  url=$1
  dest=$2
  if command -v curl >/dev/null 2>&1; then
    if [ "$INSECURE" -eq 1 ]; then
      curl -fLk --progress-bar --connect-timeout 15 -o "$dest" "$url"
    else
      curl -fL --progress-bar --connect-timeout 15 -o "$dest" "$url"
    fi
  elif command -v wget >/dev/null 2>&1; then
    if [ "$INSECURE" -eq 1 ]; then
      wget --no-check-certificate -O "$dest" "$url"
    else
      wget -O "$dest" "$url"
    fi
  else
    die "需要 curl 或 wget；无下载器时请使用离线安装：下载归档后解压并执行 ./install.sh" 1
  fi
}

sha256_of() {
  file=$1
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum -- "$file" | awk '{print $1}'
  elif command -v shasum >/dev/null 2>&1; then
    shasum -a 256 -- "$file" | awk '{print $1}'
  elif command -v openssl >/dev/null 2>&1; then
    openssl dgst -sha256 "$file" | awk '{print $NF}'
  else
    die "需要 sha256sum、shasum 或 openssl 之一用于校验" 1
  fi
}

sha256sums_line() {
  sums_file=$1
  platform=$2
  [ -s "$sums_file" ] || die "发布清单为空: $sums_file" 1
  line=$(awk -v p="$PROJECT_NAME-$platform" 'index($2, p "-") == 1 { print }' "$sums_file")
  count=$(printf '%s\n' "$line" | awk 'NF { n++ } END { print n+0 }')
  if [ "$count" -ne 1 ]; then
    die "发布清单中 $platform 平台条目数为 $count（应为 1），无法确定版本" 1
  fi
  printf '%s\n' "$line"
}

sha256sums_name() {
  sums_file=$1
  platform=$2
  line=$(sha256sums_line "$sums_file" "$platform")
  name=$(printf '%s\n' "$line" | awk '{print $2}')
  if ! printf '%s' "$name" | grep -Eq "^${PROJECT_NAME}-${platform}-v[0-9]+\.[0-9]+\.[0-9]+\.tar\.gz$"; then
    die "发布清单中的归档名非法: $name" 1
  fi
  printf '%s' "$name"
}

sha256sums_expected() {
  sums_file=$1
  platform=$2
  line=$(sha256sums_line "$sums_file" "$platform")
  expected=$(printf '%s\n' "$line" | awk '{print $1}')
  if ! printf '%s' "$expected" | grep -Eq '^[0-9a-fA-F]{64}$'; then
    die "发布清单中的 sha256 格式非法: $expected" 1
  fi
  printf '%s' "$expected"
}

current_user_name() {
  id -un
}

user_home_for() {
  awk -F: -v u="$1" '$1 == u { print $6; exit }' /etc/passwd 2>/dev/null
}

resolve_target_user() {
  TARGET_USER=${NGC_USER:-${SUDO_USER:-$(current_user_name)}}
  if [ "$TARGET_USER" = "$(current_user_name)" ]; then
    USER_HOME=${HOME:-}
    if [ -z "$USER_HOME" ]; then
      USER_HOME=$(user_home_for "$TARGET_USER")
    fi
  else
    USER_HOME=$(user_home_for "$TARGET_USER")
  fi
  if [ -z "$USER_HOME" ]; then
    die "无法确定用户 $TARGET_USER 的 home 目录" 2
  fi
  HOME=$USER_HOME
}

fix_owner() {
  fix_target=$1
  if [ "$(id -u)" -eq 0 ] && [ -n "${TARGET_USER:-}" ] && [ "$TARGET_USER" != "root" ]; then
    chown "$TARGET_USER" "$fix_target" || die "无法设置所有者: $fix_target" 8
  fi
}

ensure_dir() {
  ensure_target=$1
  if [ ! -d "$ensure_target" ]; then
    mkdir -p -- "$ensure_target" || die "无法创建目录: $ensure_target" 8
    fix_owner "$ensure_target"
  fi
  return 0
}

rc_file_for() {
  case "$1" in
    bash) printf '%s' "$HOME/.bashrc" ;;
    zsh) printf '%s' "${ZDOTDIR:-$HOME}/.zshrc" ;;
    *) die "未知 shell: $1" 2 ;;
  esac
}

rc_has_block() {
  [ -f "$1" ] && grep -Fq -- "$BLOCK_START" "$1"
}

rc_block_write() {
  rc_shell=$1
  rc_file=$(rc_file_for "$rc_shell")
  rc_dir=$(dirname -- "$rc_file")
  ensure_dir "$rc_dir"
  if [ ! -f "$rc_file" ]; then
    : > "$rc_file" || die "无法创建 $rc_file" 8
    fix_owner "$rc_file"
  fi
  rc_tmp="$rc_file.tmp.$$"
  awk -v s="$BLOCK_START" -v e="$BLOCK_END" '
    $0 == s { skip = 1; next }
    skip && $0 == e { skip = 0; next }
    skip { next }
    { print }
  ' "$rc_file" > "$rc_tmp" || die "处理 $rc_file 失败" 8
  {
    printf '%s\n' "$BLOCK_START"
    printf 'export PATH="%s/bin:$PATH"\n' "$PREFIX"
    if [ "$rc_shell" = "bash" ]; then
      printf '[ -f "%s/share/bash-completion/completions/%s" ] && . "%s/share/bash-completion/completions/%s"\n' \
        "$PREFIX" "$MAIN_COMMAND" "$PREFIX" "$MAIN_COMMAND"
    else
      printf 'fpath=("%s/share/zsh/site-functions" $fpath)\n' "$PREFIX"
      if ! grep -Fq 'compinit' "$rc_tmp"; then
        printf '%s\n' 'autoload -Uz compinit && compinit'
      fi
    fi
    printf '%s\n' "$BLOCK_END"
  } >> "$rc_tmp"
  chmod --reference="$rc_file" "$rc_tmp" || die "无法设置 $rc_file 的权限" 8
  mv -f -- "$rc_tmp" "$rc_file" || die "无法写入 $rc_file" 8
  fix_owner "$rc_file"
}

rc_block_remove() {
  rc_shell=$1
  rc_file=$(rc_file_for "$rc_shell")
  if [ ! -f "$rc_file" ]; then
    return 0
  fi
  if ! grep -Fq -- "$BLOCK_START" "$rc_file"; then
    return 0
  fi
  rc_tmp="$rc_file.tmp.$$"
  awk -v s="$BLOCK_START" -v e="$BLOCK_END" '
    $0 == s { skip = 1; next }
    skip && $0 == e { skip = 0; next }
    skip { next }
    { print }
  ' "$rc_file" > "$rc_tmp" || die "处理 $rc_file 失败" 8
  chmod --reference="$rc_file" "$rc_tmp" || die "无法设置 $rc_file 的权限" 8
  mv -f -- "$rc_tmp" "$rc_file" || die "无法写入 $rc_file" 8
  fix_owner "$rc_file"
}

record_dir() {
  printf '%s/share/%s' "$PREFIX" "$PROJECT_NAME"
}

record_path() {
  printf '%s/install-record' "$(record_dir)"
}

record_version() {
  record_file=$1
  sed -n 's/^# version: //p' "$record_file" | head -n 1
}

record_files() {
  record_file=$1
  awk '!/^#/ && NF { print }' "$record_file"
}

record_write_from_stdin() {
  rec_version=$1
  rec_dir=$(record_dir)
  ensure_dir "$rec_dir"
  rec_tmp=$(mktemp "$rec_dir/.install-record.XXXXXX") || die "无法创建安装记录" 8
  if ! {
    printf '# version: %s\n' "$rec_version"
    LC_ALL=C sort -u
  } > "$rec_tmp"; then
    rm -f -- "$rec_tmp"
    die "无法写入安装记录" 8
  fi
  chmod 0644 "$rec_tmp" || {
    rm -f -- "$rec_tmp"
    die "无法设置安装记录权限" 8
  }
  mv -f -- "$rec_tmp" "$(record_path)" || {
    rm -f -- "$rec_tmp"
    die "无法写入安装记录" 8
  }
  fix_owner "$(record_path)"
}

remove_empty_dir() {
  remove_target=$1
  if [ -d "$remove_target" ]; then
    if rmdir -- "$remove_target" 2>/dev/null; then
      :
    fi
  fi
}

prune_empty_parents() {
  prune_dir=$(dirname -- "$1")
  while [ "$prune_dir" != "$PREFIX" ] && [ "$prune_dir" != "/" ] && [ -n "$prune_dir" ]; do
    if rmdir -- "$prune_dir" 2>/dev/null; then
      prune_dir=$(dirname -- "$prune_dir")
    else
      break
    fi
  done
}

#!/usr/bin/env bash
# 卸载器正文：由 scripts/compose-install.sh 与 install/common.sh 拼装为发布根与归档内 uninstall.sh。

usage() {
  cat <<'EOF'
用法: uninstall.sh [选项]

选项:
  --prefix DIR      安装前缀（默认 ~/.local）
  --shell <名称>    bash 或 zsh（缺省自动识别；受管块会从两个 rc 中清理）
  --base-url URL    兼容参数；卸载不联网，此参数不生效
  --reinstall       兼容参数；仅安装有效，卸载忽略
  --force           无安装记录时按默认布局清理残留文件
  --insecure        兼容参数；卸载不联网，此参数不生效
  -h, --help        显示帮助
EOF
}

remove_path() {
  remove_file=$1
  if [ ! -f "$remove_file" ] && [ ! -L "$remove_file" ]; then
    return 0
  fi
  rm -f -- "$remove_file" || die "无法删除 $remove_file" 8
  removed_count=$((removed_count + 1))
  prune_empty_parents "$remove_file"
}

remove_rc_blocks() {
  if [ -f "$HOME/.bashrc" ] && rc_has_block "$HOME/.bashrc"; then
    rc_block_remove bash
    cleaned_rc+=("$HOME/.bashrc")
  fi
  if [ -f "${ZDOTDIR:-$HOME}/.zshrc" ] && rc_has_block "${ZDOTDIR:-$HOME}/.zshrc"; then
    rc_block_remove zsh
    cleaned_rc+=("${ZDOTDIR:-$HOME}/.zshrc")
  fi
}

report_residuals() {
  residual_count=0
  for residual_rel in \
    "bin/$MAIN_COMMAND" \
    "share/bash-completion/completions/$MAIN_COMMAND" \
    "share/zsh/site-functions/_$MAIN_COMMAND"; do
    residual_path="$PREFIX/$residual_rel"
    if [ -e "$residual_path" ] || [ -L "$residual_path" ]; then
      log "残留: $residual_path"
      residual_count=$((residual_count + 1))
    fi
  done
  residual_record_dir=$(record_dir)
  if [ -d "$residual_record_dir" ]; then
    residual_first=$(find "$residual_record_dir" -mindepth 1 -maxdepth 1 -print -quit)
    if [ -n "$residual_first" ]; then
      log "残留目录（非空）: $residual_record_dir"
      residual_count=$((residual_count + 1))
    fi
  fi
  if [ "$residual_count" -gt 0 ]; then
    log "提示: 以上残留未删除，请人工确认后再处理。"
  fi
}

main() {
  parse_args "$@"
  resolve_target_user
  platform=$(require_platform "$PLATFORM" uninstall.sh "$(peek_base_url)")
  log "平台校验通过: $platform"
  if [ -z "$PREFIX" ]; then
    PREFIX="$HOME/.local"
  fi
  case "$PREFIX" in
    /*) ;;
    *) die "--prefix 必须是绝对路径: $PREFIX" 2 ;;
  esac

  removed_count=0
  cleaned_rc=()
  record_file=$(record_path)

  if [ ! -f "$record_file" ]; then
    log "未在该前缀下发现安装记录: $record_file"
    if [ "$FORCE" -eq 1 ]; then
      remove_path "$PREFIX/bin/$MAIN_COMMAND"
      remove_path "$PREFIX/share/bash-completion/completions/$MAIN_COMMAND"
      remove_path "$PREFIX/share/zsh/site-functions/_$MAIN_COMMAND"
      remove_rc_blocks
      log "已按默认布局清理残留文件: $removed_count 个"
    fi
    report_residuals
    log "未删除任何用户配置或用户数据。"
    exit 0
  fi

  list_tmp=$(mktemp "${TMPDIR:-/tmp}/$PROJECT_NAME-uninstall.XXXXXX") || die "无法创建临时文件" 8
  TMP_DIR=$list_tmp
  record_files "$record_file" > "$list_tmp" || die "无法读取安装记录" 8
  while IFS= read -r record_entry; do
    [ -n "$record_entry" ] || continue
    case "$record_entry" in
      /*) ;;
      *) die "安装记录包含非法路径（非绝对路径）: $record_entry" 8 ;;
    esac
    case "$record_entry" in
      "$PREFIX"/*) ;;
      *) die "安装记录路径不在前缀内，拒绝删除: $record_entry" 8 ;;
    esac
    remove_path "$record_entry"
  done < "$list_tmp"
  remove_path "$record_file"
  remove_empty_dir "$(record_dir)"
  remove_rc_blocks

  log "已移除 $removed_count 个文件（前缀: $PREFIX）"
  if [ "${#cleaned_rc[@]}" -gt 0 ]; then
    for rc_item in "${cleaned_rc[@]}"; do
      log "已清理 rc: $rc_item"
    done
  fi
  report_residuals
  log "未删除用户配置（~/.config/$PROJECT_NAME/config）与旧配置（~/.config/ngc/config）。"
  log "卸载完成。"
}

main "$@"
