#!/usr/bin/env bash
# ============================================================================
# install_env.sh — llama-index 探针部署脚本（环境变量方式，Linux / macOS）
#
# 与 install.py（一键部署，参数直接传）的区别：
#   本脚本不接收配置参数，配置来源是"当前 shell 会话的环境变量"。
#   执行前必须先用下方命令刷新环境变量（每次打开新终端都要重刷）：
#
#   export agentarts_agentops_otel_agent_apm_enable=true
#   export agentarts_agentops_otel_agent_aom_enable=true
#
#   export agent_domain_id={{domain_id}}
#   export agentarts_project_id={{project_id}}
#   export agent_resource_id={{agent_id}}
#   export resource_type={{agent_type}}
#
#   export agentarts_agentops_apm_token={{trace_token}}
#   export agentarts_agentops_apm_exporter_endpoint={{trace_endpoint}}
#
#   export agentarts_agentops_aom_access_code={{metric_token}}
#   export agentarts_agentops_aom_exporter_endpoint={{metric_endpoint}}
#   export agentarts_agentops_aom_prometheus_id={{prom_id}}
#
# 用法：
#   sh install_env.sh huaweicloud_opentelemetry_instrumentation_llama_index-*.whl
#   或（有 +x 权限时）：./install_env.sh <whl>
#
# 效果与 install.py 完全一致：
#   1. pip install whl（--force-reinstall --no-deps，重复执行完全覆盖）
#   2. 读环境变量 → 写 ~/.llama-index-metrics/config.json（JSONC 注释模板）
#   3. 探针启动时读同一位置的 config.json（config.json otel 段 > 环境变量同名 key）
#
# 环境变量 key 与 config.json otel 段 key 同名（探针 _otel_value(key) 读取逻辑），
# 因此环境变量直接注入 config.json otel 段即可被探针识别。
# ============================================================================
set -euo pipefail

CONFIG_VERSION="0.1.0"
CONFIG_DIR="${HOME}/.llama-index-metrics"
CONFIG_FILE="${CONFIG_DIR}/config.json"
CONFIG_DATA_DIR="${CONFIG_DIR}/data"

echo "== llama-index 探针部署（环境变量方式）=="

# ---------- 1. 校验 whl 存在 ----------
WHL="${1:-}"
if [ -z "${WHL}" ]; then
    echo "用法: $0 <whl>"
    echo "示例: sh install_env.sh huaweicloud_opentelemetry_instrumentation_llama_index-*.whl"
    exit 1
fi
# 支持通配符：若传入的 whl 参数含 *，由脚本自行展开（与 PowerShell Resolve-Path 行为一致，
# 兼容 bash 未展开的情况，如 sh install_env.sh '*.whl' 带引号）
if echo "${WHL}" | grep -q '\*'; then
    # 注意：这里不能对 $WHL 加双引号——需要让 shell 对 * 做通配符展开
    # shellcheck disable=SC2012
    MATCHES=$(ls ${WHL} 2>/dev/null | head -n 1) || MATCHES=""
    if [ -z "${MATCHES}" ] || [ ! -f "${MATCHES}" ]; then
        echo "ERROR: 通配符无匹配文件: ${WHL}"
        exit 1
    fi
    WHL="${MATCHES}"
    echo "通配符展开: ${WHL}"
fi
if [ ! -f "${WHL}" ]; then
    echo "ERROR: whl 文件不存在: ${WHL}"
    exit 1
fi
echo "whl OK: ${WHL}"

# ---------- 2. 读取环境变量（11 个 key） ----------
# 与 config.json otel 段 key 同名；探针 config.json > 环境变量同名 key 读取。
get_env() {
    local key="$1"
    local val=""
    val="$(printenv "${key}" || true)"
    echo "${val}"
}

OTEL_APM_ENABLE=$(get_env "agentarts_agentops_otel_agent_apm_enable")
OTEL_AOM_ENABLE=$(get_env "agentarts_agentops_otel_agent_aom_enable")
DOMAIN_ID=$(get_env "agent_domain_id")
PROJECT_ID=$(get_env "agentarts_project_id")
AGENT_ID=$(get_env "agent_resource_id")
RESOURCE_TYPE=$(get_env "resource_type")
APM_TOKEN=$(get_env "agentarts_agentops_apm_token")
APM_ENDPOINT=$(get_env "agentarts_agentops_apm_exporter_endpoint")
AOM_ACCESS_CODE=$(get_env "agentarts_agentops_aom_access_code")
AOM_ENDPOINT=$(get_env "agentarts_agentops_aom_exporter_endpoint")
AOM_PROMETHEUS_ID=$(get_env "agentarts_agentops_aom_prometheus_id")

# ---------- 3. pip install whl（两步：探针强制重装 + 缺失依赖补装） ----------
# 满足"只对探针 whl 强制 --force-reinstall，其他已装组件不动"：
#   第 1 步 --force-reinstall --no-deps：只强制重装探针本体（覆盖旧文件），
#     不连带重装任何依赖。
#   第 2 步（不带 force）再装一次 whl：pip 发现探针已装，只补装**缺失**的
#     依赖（opentelemetry-instrumentation 等）；已存在的依赖显示
#     "already satisfied" 跳过，不强制重装、不覆盖用户已有的版本。
echo ""
echo "== pip install 第 1 步：探针强制重装（--force-reinstall --no-deps）=="
python3 -m pip install --force-reinstall --no-deps --no-cache-dir "${WHL}" || {
    echo "ERROR: 探针 pip install 失败" >&2
    exit 1
}
echo "探针 whl 强制重装 OK"

echo ""
echo "== pip install 第 2 步：补装缺失依赖（已存在的跳过）=="
python3 -m pip install --no-cache-dir "${WHL}" || {
    echo "ERROR: 依赖补装失败" >&2
    exit 1
}
echo "依赖补装 OK（已存在的组件 pip 自动跳过，不强制重装）"

# ---------- 3a. 检查并安装 llama-index（探针运行期强依赖） ----------
# 探针的 callback.py / agent_events.py / _instrument() 都 import llama_index
#（pyproject 的 dependencies 不含它——它是业务库，被打包成"业务代码自装"）。
# 部署脚本负责把探针装进新环境，必须保证 llama-index 也存在，否则
# opentelemetry-instrument 启动时 distro 加载即 ModuleNotFoundError。
# 仅"未安装"时安装（不 --force-reinstall，避免覆盖用户已装的业务版本）。
echo ""
echo "== 检查 llama-index =="
if python3 -m pip show llama-index >/dev/null 2>&1; then
    echo "llama-index 已安装，跳过（$(python3 -m pip show llama-index 2>/dev/null | grep -E '^Version:' | head -n1)）"
else
    echo "llama-index 未安装，执行 pip install llama-index ..."
    if ! python3 -m pip install --no-cache-dir llama-index; then
        echo "ERROR: pip install llama-index 失败" >&2
        exit 1
    fi
    echo "llama-index 安装 OK"
fi

# ---------- 4. 写 config.json（JSONC 注释模板 + 环境变量注入） ----------
echo ""
echo "== 写 config.json =="
mkdir -p "${CONFIG_DIR}"

# JSON 字符串转义（值内引号/反斜杠，Windows 路径用不上但统一处理）
json_escape() {
    local s="$1"
    if [ -z "${s}" ]; then echo ""; return; fi
    # 反斜杠 → \\，双引号 → \"，换行 → \n
    s=$(printf '%s' "${s}" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\n/\\n/g')
    printf '%s' "${s}"
}

# 缺端口自动补 4317（OTLP gRPC 标准端口）
ensure_port() {
    local ep="$1"
    if [ -z "${ep}" ]; then echo ""; return; fi
    if echo "${ep}" | grep -q ":"; then
        echo "${ep}"
    else
        echo "${ep}:4317"
    fi
}

APM_ENDPOINT=$(ensure_port "${APM_ENDPOINT}")
AOM_ENDPOINT=$(ensure_port "${AOM_ENDPOINT}")

DOMAIN_ID=$(json_escape "${DOMAIN_ID}")
PROJECT_ID=$(json_escape "${PROJECT_ID}")
AGENT_ID=$(json_escape "${AGENT_ID}")
RESOURCE_TYPE=$(json_escape "${RESOURCE_TYPE}")
APM_TOKEN=$(json_escape "${APM_TOKEN}")
APM_ENDPOINT=$(json_escape "${APM_ENDPOINT}")
AOM_ACCESS_CODE=$(json_escape "${AOM_ACCESS_CODE}")
AOM_ENDPOINT=$(json_escape "${AOM_ENDPOINT}")
AOM_PROMETHEUS_ID=$(json_escape "${AOM_PROMETHEUS_ID}")

cat > "${CONFIG_FILE}" <<EOF
{
  "version": "${CONFIG_VERSION}",
  // 插件总开关
  "enabled": true,
  // 日志输出目录（日志存放位置：outputDir/logs/plugin-YYYY-MM-DD.log）。
  "outputDir": "${CONFIG_DATA_DIR}",
  // 用户 ID（注入 user.id）：为空/不设置则兜底主机名上报
  "user.id": "",
  "features": {
    "debug": true,                 // debug 日志开关：false=关闭（默认），true=开启（打印 AOM 上报属性明细）
    "captureMessageContent": true   // 是否采集 trace 输入/输出消息内容：true=展示（默认），false=不展示
  },
  // ============ OTel 上报配置（AgentArts） ============
  "otel": {
    // APM（Trace 上报）开关：true 开启，false 关闭
    "agentarts_agentops_otel_agent_apm_enable": true,
    // AOM（Metrics 上报）开关：true 开启，false 关闭
    "agentarts_agentops_otel_agent_aom_enable": true,
    // 账号/租户 ID（Wiki 必填维度 domain.id）
    "agent_domain_id": "${DOMAIN_ID}",
    // AgentArts 项目 ID
    "agentarts_project_id": "${PROJECT_ID}",
    // 智能体 ID（AgentArts 创建接入时分配，页面图表必须绑定此值才能看到数据）
    "agent_resource_id": "${AGENT_ID}",
    // 资源类型：单智能体填 "agent"，多智能体 "multiagents"，工作流 "workflow"
    "resource_type": "${RESOURCE_TYPE}",
    // APM 上报认证 token（敏感信息，勿外泄）
    "agentarts_agentops_apm_token": "${APM_TOKEN}",
    // APM 上报端点（gRPC，端口 4317）
    "agentarts_agentops_apm_exporter_endpoint": "${APM_ENDPOINT}",
    // AOM 上报认证 access code（敏感信息，勿外泄）
    "agentarts_agentops_aom_access_code": "${AOM_ACCESS_CODE}",
    // AOM 上报端点（gRPC，端口 4317）
    "agentarts_agentops_aom_exporter_endpoint": "${AOM_ENDPOINT}",
    // AOM Prometheus 实例 ID
    "agentarts_agentops_aom_prometheus_id": "${AOM_PROMETHEUS_ID}"
  }
}
EOF
echo "config.json 写入: ${CONFIG_FILE}"

# 缺失的环境变量提示（探针侧会服务级跳过，不阻断整体）
echo ""
echo "== 环境变量缺失检查 =="
missing=0
for key in agentarts_agentops_otel_agent_apm_enable agentarts_agentops_otel_agent_aom_enable \
           agent_domain_id agentarts_project_id agent_resource_id resource_type \
           agentarts_agentops_apm_token agentarts_agentops_apm_exporter_endpoint \
           agentarts_agentops_aom_access_code agentarts_agentops_aom_exporter_endpoint \
           agentarts_agentops_aom_prometheus_id; do
    if [ -z "$(printenv "${key}" || true)" ]; then
        echo "  WARN: 环境变量 ${key} 未设置（对应服务可能被探针跳过）"
        missing=1
    fi
done
if [ "${missing}" -eq 0 ]; then
    echo "全部 11 个环境变量已设置。"
fi

# ---------- 5. 提示启动方式 ----------
echo ""
echo "== 完成 =="
echo "启动方式（三选一）："
echo "  [方式1] opentelemetry-instrument python app.py   # 零代码侵入（推荐，entry point 自动装配）"
echo "  [方式2] sitecustomize.py 放 PYTHONPATH（调 auto_instrument()）"
echo "  [方式3] 业务代码里 from opentelemetry.instrumentation.huawei_llama_index import auto_instrument; auto_instrument()"
echo "日志目录: ${CONFIG_DATA_DIR}/logs/"
exit 0
