#!/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 拼装为发布根 install.sh。

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

选项:
  --base-url URL    覆盖下载基地址
  --prefix DIR      安装前缀（默认 ~/.local）
  --shell <名称>    bash 或 zsh（缺省自动识别当前 shell）
  --reinstall       同版本已安装时也重新安装
  --force           允许降级、覆盖异常现场
  --insecure        跳过 TLS 证书校验（自签/私有 CA）
  -h, --help        显示帮助
EOF
}

main() {
  parse_args "$@"
  resolve_target_user

  base_url=$(resolve_base_url)
  platform=$(require_platform "$PLATFORM" install.sh "$base_url")
  shell_name=$(detect_shell)
  arch=$(uname -m 2>/dev/null || printf 'unknown')

  if [ -z "$PREFIX" ]; then
    PREFIX="$HOME/.local"
  fi
  case "$PREFIX" in
    /*) ;;
    *) die "--prefix 必须是绝对路径: $PREFIX" 2 ;;
  esac

  dl_root="$base_url/$PROJECT_NAME/$platform"

  TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/$PROJECT_NAME-install.XXXXXX") || die "无法创建临时目录" 8

  log "[1/8] 解析基地址: $base_url"
  log "[2/8] 校验平台: $platform（与制品平台 $PLATFORM 一致）架构=$arch shell=$shell_name"
  log "[3/8] 下载发布清单: $dl_root/sha256sums"
  sums_file="$TMP_DIR/sha256sums"
  if ! download_file "$dl_root/sha256sums" "$sums_file"; then
    die "下载发布清单失败: $dl_root/sha256sums" 1
  fi
  archive_name=$(sha256sums_name "$sums_file" "$platform")
  expected_sha=$(sha256sums_expected "$sums_file" "$platform")
  archive_version=$(printf '%s' "$archive_name" | sed -E "s/^${PROJECT_NAME}-${platform}-//; s/\.tar\.gz$//")

  log "[4/8] 下载制品: $archive_name"
  archive_file="$TMP_DIR/$archive_name"
  if ! download_file "$dl_root/$archive_name" "$archive_file"; then
    die "下载制品失败: $dl_root/$archive_name" 1
  fi

  log "[5/8] 校验 sha256"
  actual_sha=$(sha256_of "$archive_file")
  if [ "$expected_sha" != "$actual_sha" ]; then
    rm -f -- "$archive_file"
    die "sha256 校验失败: 期望 $expected_sha，实际 $actual_sha" 1
  fi

  log "[6/8] 解压制品"
  extract_dir="$TMP_DIR/extract"
  mkdir -p -- "$extract_dir" || die "无法创建解压目录" 8
  if ! tar -xzf "$archive_file" -C "$extract_dir"; then
    die "解压失败: $archive_name" 1
  fi
  if [ ! -f "$extract_dir/install.sh" ]; then
    die "归档中缺少 install.sh" 1
  fi

  log "[7/8] 运行包内安装器（版本 $archive_version）"
  install_args=(--prefix "$PREFIX" --shell "$shell_name")
  if [ "$REINSTALL" -eq 1 ]; then
    install_args+=(--reinstall)
  fi
  if [ "$FORCE" -eq 1 ]; then
    install_args+=(--force)
  fi
  if [ "$INSECURE" -eq 1 ]; then
    eval "export $INSECURE_ENV=1"
  fi
  export NGC_UPDATE_BASE_URL="$base_url"
  "$shell_name" "$extract_dir/install.sh" \
    ${install_args[@]+"${install_args[@]}"} < /dev/null

  if [ "$INSECURE" -eq 1 ]; then
    log "[8/8] 安装完成: $archive_version（已跳过 TLS 校验）"
  else
    log "[8/8] 安装完成: $archive_version"
  fi
  log "前缀: $PREFIX"
  log "Shell: $shell_name"
  rc_file=$(rc_file_for "$shell_name")
  log "rc: $rc_file"
  log "生效: source $rc_file"
  log "验证: $PREFIX/bin/$MAIN_COMMAND version"
}

main "$@"
