#!/bin/bash
# 云瞰 fnOS fpk 安装前钩子。
#
# 飞牛 docker app lifecycle:
#   1. wizard 收集字段(field 名 wizard_xxx,以 env 注入本脚本)
#   2. 解 fpk 表层文件(cmd/wizard/config/manifest/icon)到 TRIM_APPDEST
#   3. 调本脚本 install_init
#   4. 解 app.tgz 到 TRIM_APPDEST(会覆盖 docker-compose.yaml — 我们 *不* 改它)
#   5. docker compose up(飞牛把 wizard 字段 + TRIM_* env 注入 compose 进程,
#      docker compose 原生 ${VAR} substitution 替换 yaml 引用)
#   6. checkport=true 时探测 service_port
#   7. 调 install_callback
#
# install_init 只做 docker compose up 之前必须做的事:
#   A. docker pull 主镜像(否则 compose up 因 image not found 失败)
#   B. 从主镜像拷 /app/config/config.toml + 随机化 jwt_secret
#
# 不做:
#   - 改 docker-compose.yaml(飞牛 app.tgz 会覆盖)
#   - 写 .env(实测飞牛 docker compose 不读)
#   - 改 wizard 字段(飞牛不重读)

set -uo pipefail

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
die() { log "ERROR: $*"; exit 1; }

log "──────────────────────────────────────────────"
log "云瞰 fnOS install_init"
log "TRIM_APPNAME=${TRIM_APPNAME:-?}  TRIM_APPVER=${TRIM_APPVER:-?}"
log "TRIM_APPDEST=${TRIM_APPDEST:-?}"
log "TRIM_APPDEST_VOL=${TRIM_APPDEST_VOL:-<空>}"
log "TRIM_PKGVAR=${TRIM_PKGVAR:-?}"
log "TRIM_RUN_USERNAME=${TRIM_RUN_USERNAME:-?} (id: $(id 2>&1))"

# wizard 字段(field 名 wizard_yunkan_*)以 env 注入本脚本
YUNKAN_VARIANT="${wizard_yunkan_variant:-openvino}"
YUNKAN_VERSION="${wizard_yunkan_version:-latest}"
YUNKAN_PUBLIC_HOST="${wizard_yunkan_public_host:-}"
log "wizard: variant=${YUNKAN_VARIANT} version=${YUNKAN_VERSION} public_host=${YUNKAN_PUBLIC_HOST:-<空>}"

# 校验 variant
case "${YUNKAN_VARIANT}" in
  cpu|openvino) ;;
  *)
    log "WARN: variant=${YUNKAN_VARIANT} 不支持(fpk 只支持 cpu/openvino),降级到 openvino"
    YUNKAN_VARIANT="openvino"
    ;;
esac

REGISTRY="${YUNKAN_REGISTRY:-registry.cn-hangzhou.aliyuncs.com/yunkan}"
YUNKAN_IMAGE="${REGISTRY}/yunkan-${YUNKAN_VARIANT}:${YUNKAN_VERSION}"
log "主镜像: ${YUNKAN_IMAGE}"

# ─── A. docker pull 主镜像 ─────────────────────────────────────────
command -v docker >/dev/null 2>&1 || die "docker CLI 未找到(飞牛 OS 应自带)"
docker info >/dev/null 2>&1       || die "docker daemon 不可用(检查 run-as=root 是否生效)"

log "pull 主镜像中(国内 5-15 分钟)..."
docker pull "${YUNKAN_IMAGE}" || die "拉取 ${YUNKAN_IMAGE} 失败"

# updater 镜像可选 — pull 失败不阻断
log "pull updater 镜像..."
docker pull "${REGISTRY}/yunkan-updater:${YUNKAN_VERSION}" \
  || log "WARN: updater 拉取失败 — Web Admin 在线升级不可用"

# ─── B. 拷 config.toml + 随机化 jwt_secret ───────────────────────
CONFIG_FILE="${TRIM_PKGVAR}/config.toml"
mkdir -p "${TRIM_PKGVAR}" || die "创建 ${TRIM_PKGVAR} 失败"

# 用 -s 不用 -f:-s 同时检测"文件不存在" OR "大小为 0"。上次装失败留空文件时
# -f 会跳过,容器加载空 config.toml 会 crash;-s 重新生成更稳。
if [[ ! -s "${CONFIG_FILE}" ]]; then
  log "首次安装 / config.toml 为空:从镜像内拷 + 随机 jwt_secret"
  docker run --rm --entrypoint cat "${YUNKAN_IMAGE}" /app/config/config.toml > "${CONFIG_FILE}.tmp" \
    || die "从镜像 cat /app/config/config.toml 失败"
  [[ -s "${CONFIG_FILE}.tmp" ]] || die "拷出 config.toml 是空"
  mv "${CONFIG_FILE}.tmp" "${CONFIG_FILE}"

  RANDOM_JWT=$(openssl rand -hex 32 2>/dev/null || head -c 64 /dev/urandom | base64 | tr -d '=+/' | head -c 64)
  grep -qE '^jwt_secret[[:space:]]*=' "${CONFIG_FILE}" \
    || die "config.toml 缺 jwt_secret 字段"
  sed -i "s|^jwt_secret[[:space:]]*=.*|jwt_secret = \"${RANDOM_JWT}\"|" "${CONFIG_FILE}"
  # 必须验证 sed 真改了:set -uo pipefail 不带 -e,sed 静默失败会被吞;如果
  # jwt_secret 没替换,容器会用 config.toml 模板里的 "please-change-me-..."
  # 启动,任何人能伪造 admin token = 安全漏洞。yunkan-install.sh 同样套路。
  grep -qxF "jwt_secret = \"${RANDOM_JWT}\"" "${CONFIG_FILE}" \
    || die "jwt_secret 写入失败(sed 未生效) — config.toml 内容异常"
  chmod 600 "${CONFIG_FILE}"
  log "config.toml 已生成 + jwt_secret 已随机化 + 已验证 → ${CONFIG_FILE}"
else
  log "config.toml 已存在(升级 / 重装保留)"
fi

log "init 完成 — 飞牛接下来会解 app.tgz + docker compose up"
log "(compose.yaml 里 \${wizard_xxx} 和 \${TRIM_APPDEST_VOL} 由飞牛在 compose up 时注入)"
exit 0
