
if ! type "include" > /dev/null 2>&1; then
  include() {
    . "$(cd "$(dirname "$1")" && pwd)/${2}";
  };
fi
include "${BASH_SOURCE[0]}" ../pragma_once.bash
if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi
include "${BASH_SOURCE[0]}" ./global_rely/export.bash
include "${BASH_SOURCE[0]}" ./other.bash
# shellcheck source=./global_rely/export.bash
# shellcheck source=./other.bash



# =========================
# template.bash
# 纯 Bash 模板渲染
# 占位符格式: {{KEY}}
# =========================

# 判断某个 key 是否合法
_template_validate_key() {
  local key="$1"
  [[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]
}

# 转义 replacement，避免 sed 替换时特殊字符出问题
_template_escape_replacement() {
  local s="$1"
  s="${s//\\/\\\\}"
  s="${s//&/\\&}"
  s="${s//|/\\|}"
  printf '%s' "$s"
}

# 核心：对一个字符串做渲染
# 用法：
#   template_render_string "hello {{NAME}}" NAME "wyc" AGE "18"
template_render_string() {
  if [ $# -lt 1 ]; then
    echo "template_render_string: missing template string" >&2
    return 1
  fi

  local template_str="$1"
  shift

  if [ $(( $# % 2 )) -ne 0 ]; then
    echo "template_render_string: key/value arguments must be paired" >&2
    return 1
  fi

  local rendered="$template_str"
  local key=""
  local value=""
  local escaped_value=""

  while [ $# -gt 0 ]; do
    key="$1"
    value="$2"
    shift 2

    if ! _template_validate_key "$key"; then
      echo "template_render_string: invalid key: $key" >&2
      return 1
    fi

    escaped_value="$(_template_escape_replacement "$value")"
    rendered="$(printf '%s' "$rendered" | sed "s|{{${key}}}|${escaped_value}|g")"
  done

  printf '%s' "$rendered"
}

# 从模板文件渲染到 stdout
# 用法：
#   template_render_file /tmp/a.tpl NAME "wyc" AGE "18"
template_render_file() {
  if [ $# -lt 1 ]; then
    echo "template_render_file: missing template file" >&2
    return 1
  fi

  local template_file="$1"
  shift

  if [ ! -f "$template_file" ]; then
    echo "template_render_file: template file not found: $template_file" >&2
    return 1
  fi

  local content=""
  content="$(cat "$template_file")" || return 1
  template_render_string "$content" "$@"
}

# 从模板文件渲染到目标文件
# 用法：
#   template_render_to_file /tmp/a.tpl /tmp/out.conf NAME "wyc"
template_render_to_file() {
  if [ $# -lt 2 ]; then
    echo "template_render_to_file: usage: template_render_to_file <template> <output> [KEY VALUE ...]" >&2
    return 1
  fi

  local template_file="$1"
  local output_file="$2"
  shift 2

  local output_dir=""
  output_dir="$(dirname "$output_file")"

  mkdir -p "$output_dir" || return 1

  template_render_file "$template_file" "$@" > "$output_file" || return 1
}

# 检查模板里还有哪些未替换占位符
# 输出唯一 key 列表
# 用法：
#   template_list_placeholders /tmp/a.tpl
template_list_placeholders() {
  if [ $# -ne 1 ]; then
    echo "template_list_placeholders: usage: template_list_placeholders <template_file>" >&2
    return 1
  fi

  local template_file="$1"

  if [ ! -f "$template_file" ]; then
    echo "template_list_placeholders: template file not found: $template_file" >&2
    return 1
  fi

  grep -o '{{[A-Za-z_][A-Za-z0-9_]*}}' "$template_file" \
    | sed 's/^{{//; s/}}$//' \
    | sort -u
}

#   模板文件示例
#   server_name={{SERVER_NAME}}
#   server_port={{SERVER_PORT}}
#   build_type={{BUILD_TYPE}}
#   install_prefix={{INSTALL_PREFIX}}

#  调用方式

#    template_render_to_file_strict \
#      /ae/bash/demo/app.conf.tpl \
#      /ae/bash/demo/out/app.conf \
#      SERVER_NAME "demo-server" \
#      SERVER_PORT "8080" \
#      BUILD_TYPE "Release" \
#      INSTALL_PREFIX "/opt/demo"

# 严格模式：如果还有未替换占位符则报错
# 用法：
#   template_render_to_file_strict /tmp/a.tpl /tmp/out.conf NAME "wyc"
template_render_to_file_strict() {
  if [ $# -lt 2 ]; then
    echo "template_render_to_file_strict: usage: template_render_to_file_strict <template> <output> [KEY VALUE ...]" >&2
    return 1
  fi

  local template_file="$1"
  local output_file="$2"
  shift 2
  check_file_var template_file
  template_render_to_file "$template_file" "$output_file" "$@" || return 1

  if grep -q '{{[A-Za-z_][A-Za-z0-9_]*}}' "$output_file"; then
    echo "template_render_to_file_strict: unresolved placeholders found in: $output_file" >&2
    grep -o '{{[A-Za-z_][A-Za-z0-9_]*}}' "$output_file" | sort -u >&2
    return 1
  fi
}


#     declare -A tpl_vars
#     tpl_vars[SERVER_NAME]="demo-server"
#     tpl_vars[SERVER_PORT]="8080"
#     tpl_vars[BUILD_TYPE]="Debug"
#     tpl_vars[INSTALL_PREFIX]="/opt/demo"
#
#     template_render_file_by_assoc \
#       /ae/bash/demo/app.conf.tpl \
#       tpl_vars \
#       > /ae/bash/demo/out/app.conf

template_render_file_by_assoc() {
  if [ $# -ne 2 ]; then
    echo "template_render_file_by_assoc: usage: template_render_file_by_assoc <template_file> <assoc_name>" >&2
    return 1
  fi

  local template_file="$1"
  local assoc_name="$2"

  check_file_var template_file

  if [ ! -f "$template_file" ]; then
    echo "template_render_file_by_assoc: template file not found: $template_file" >&2
    return 1
  fi

  local content=""
  content="$(cat "$template_file")" || return 1

  local key=""
  local value=""
  local escaped_value=""

  local rendered="$content"
  local -n kv_ref="$assoc_name"

  for key in "${!kv_ref[@]}"; do
    if ! _template_validate_key "$key"; then
      echo "template_render_file_by_assoc: invalid key: $key" >&2
      return 1
    fi
    value="${kv_ref[$key]}"
    escaped_value="$(_template_escape_replacement "$value")"
    rendered="$(printf '%s' "$rendered" | sed "s|{{${key}}}|${escaped_value}|g")"
  done

  printf '%s' "$rendered"
}



