#!/bin/bash
#
# Octop 本地版 — 安装后回调
#
# 密码策略（修复 issue #502：旧版写死 Octop123 被应用弱密码黑名单拒绝，
# 导致首次启动 octop init 报 "password is too common" 退出、应用无法启动）：
#   - 安装向导（wizard/install）提供两种方式：自己输入密码 / 自动生成随机密码；
#   - 自定义密码在这里按应用侧策略（≥8 位、含字母和数字、不在常见弱密码
#     黑名单）预校验，无效密码直接让安装失败并给出明确提示；
#   - 随机密码由 octop_generate_password 生成（16 位，含字母和数字）；
#   - 两种方式都会：(1) 写入 PKGVAR/.env 供首次启动 octop init 使用；
#     (2) 回落保存到数据目录 octop-login.txt；(3) 渲染进应用「设置」窗口，
#     用户随时打开设置即可查看当前密码，不必翻文件。
#
set -euo pipefail

# 共享函数库（find_python312 / fix_ownership_and_perms / free_octop_ports /
# octop_generate_password / octop_validate_password / octop_write_login_file /
# octop_render_config_wizard 等）
# 打包时由 scripts/build-fpk.sh 注入；仓库内运行无此文件时跳过（函数缺失时再报错）。
_OCTOP_COMMON="$(dirname "$0")/common.sh"
[ -f "$_OCTOP_COMMON" ] || _OCTOP_COMMON="/var/apps/octop-native/cmd/common.sh"
[ -f "$_OCTOP_COMMON" ] && source "$_OCTOP_COMMON"

# 释放 Octop 端口（8088=Docker 版，8089=本地版），杀掉残留/孤儿进程，避免重装端口冲突。
free_octop_ports

PKGVAR="${TRIM_PKGVAR:-/var/apps/octop-native/var}"
APPDEST="${TRIM_APPDEST:-/var/apps/octop-native}"
mkdir -p "$PKGVAR"
ENV_FILE="$PKGVAR/.env"

# 数据落在 FnOS 的 data-share 共享目录，升级时保留（凭据回落保存也在这里）。
if [ -n "${TRIM_DATA_SHARE_PATHS:-}" ]; then
    DATA_DIR="${TRIM_DATA_SHARE_PATHS%%:*}"
else
    DATA_DIR="${APPDEST}/shares/octop-native/data"
fi
mkdir -p "$DATA_DIR"

fail_install() {
    echo "[octop-native] $1" > "${TRIM_TEMP_LOGFILE:-/dev/null}" 2>&1 || true
    echo "[octop-native] $1" >&2 || true
    exit 1
}

# ---------------------------------------------------------------------------
# 解析向导字段（wizard/install 的 field 名即环境变量名）
# ---------------------------------------------------------------------------
ADMIN_USER="$(octop_sanitize_value "${wizard_admin_username:-admin}")"
PASSWORD_MODE="$(octop_sanitize_value "${wizard_password_mode:-random}")"
WIZARD_PASSWORD="$(octop_sanitize_value "${wizard_admin_password:-}")"
LOG_LEVEL="$(octop_sanitize_value "${wizard_log_level:-info}")"
OPENAI="$(octop_sanitize_value "${wizard_openai_api_key:-}")"
DASHSCOPE="$(octop_sanitize_value "${wizard_dashscope_api_key:-}")"

if [ -z "$ADMIN_USER" ]; then
    fail_install "管理员用户名不能为空"
fi
if ! printf '%s' "$ADMIN_USER" | grep -qE '^[a-zA-Z0-9][a-zA-Z0-9_.-]{1,31}$'; then
    fail_install "管理员用户名「${ADMIN_USER}」无效：只能包含字母、数字、点、下划线和连字符（2-32 位）"
fi

# ---------------------------------------------------------------------------
# 密码：两种方式（自定义 / 随机生成），无效密码让安装直接失败并给出原因
# ---------------------------------------------------------------------------
case "$PASSWORD_MODE" in
    custom)
        if [ -z "$WIZARD_PASSWORD" ]; then
            fail_install "您选择了自己输入密码，但密码为空。请返回安装向导输入密码，或改选「自动生成随机密码」。"
        fi
        if ! ADMIN_PASS_REASON="$(octop_validate_password "$WIZARD_PASSWORD" 2>&1)"; then
            fail_install "管理员密码不符合要求：${ADMIN_PASS_REASON}（要求：至少 8 位，且同时包含字母和数字，不能使用过于常见的密码）"
        fi
        ADMIN_PASS="$WIZARD_PASSWORD"
        ;;
    random)
        ADMIN_PASS="$(octop_generate_password 16)"
        ;;
    *)
        fail_install "密码设置方式无效：${PASSWORD_MODE}（应为 custom 或 random）"
        ;;
esac

{
    echo "OCTOP_PORT=8089"
    echo "OCTOP_BIND_HOST=0.0.0.0"
    echo "OCTOP_LOG_LEVEL=${LOG_LEVEL}"
    echo "OCTOP_ADMIN_USERNAME=${ADMIN_USER}"
    echo "OCTOP_DEFAULT_PASSWORD=${ADMIN_PASS}"
    echo "OCTOP_ADMIN_DISPLAY_NAME=Admin"
    echo "OPENAI_API_KEY=${OPENAI}"
    echo "DASHSCOPE_API_KEY=${DASHSCOPE}"
} > "$ENV_FILE"

chmod 600 "$ENV_FILE"
echo "[octop-native] 已写入配置: $ENV_FILE" > "${TRIM_TEMP_LOGFILE:-/dev/null}" 2>/dev/null || true

# ---------------------------------------------------------------------------
# 管理员凭据回落保存（octop-login.txt，数据共享目录内，升级保留）+「设置」窗口渲染。
# 用户随时可以：打开应用「设置」查看当前密码；或从数据目录的 octop-login.txt 找回。
# ---------------------------------------------------------------------------
octop_write_login_file "$DATA_DIR" "$ADMIN_USER" "$ADMIN_PASS" 8089

WIZARD_TEMPLATE="$APPDEST/wizard/config.template"
WIZARD_DIR="$(dirname "$APPDEST")/wizard"
[ -f "$WIZARD_TEMPLATE" ] || WIZARD_TEMPLATE="${APPDEST}/../wizard/config"
octop_render_config_wizard "$WIZARD_TEMPLATE" "$WIZARD_DIR" "$ADMIN_USER" "$ADMIN_PASS"

# ---------------------------------------------------------------------------
# 修正属主/权限：.env 与 appdata 改回 octop-native，避免服务以 octop-native 启动
# 时 . "$PKGVAR/.env" 报 Permission denied（root 写 root 属主，低权限用户读不了）。
# ---------------------------------------------------------------------------
fix_ownership_and_perms "$PKGVAR" "$ENV_FILE"

# 校验 Python 3.12 是否存在
if ! PY="$(find_python312)"; then
    echo "[octop-native] 错误：飞牛系统中未找到 Python 3.12。" > "${TRIM_TEMP_LOGFILE:-/dev/null}" 2>&1 || true
    echo "请先前往飞牛应用中心 → 开发工具 → 安装「Python 3.12」，然后重新安装 Octop 本地版。" > "${TRIM_TEMP_LOGFILE:-/dev/null}" 2>&1 || true
    exit 1
fi

echo "[octop-native] 已检测到 Python 3.12: $PY" > "${TRIM_TEMP_LOGFILE:-/dev/null}" 2>&1 || true

# ---------------------------------------------------------------------------
# 让 Octop 本地版“开箱即用”：
#   1) 给 octop-native 系统账户设置已知密码（= 管理员密码），
#      便于工作台终端等场景使用。
#   2) 授予 octop-native 免密码 sudo（NOPASSWD）。
#      Octop 的远程桌面/浏览器等组件在运行时会以 octop-native 身份执行
#      `sudo -n ...`（例如 desktop/setup.py 的 install/start/resize/uninstall），
#      若 sudo 需要密码就会失败报 “a password is required”。
#      这里在安装回调（root 权限）阶段一次性配好，之后用户在界面里安装
#      远程桌面 / 在工作台终端里执行 sudo 都不再需要输入密码。
# ---------------------------------------------------------------------------
OCTOP_USER="octop-native"

# 设置 octop-native 登录密码为向导管理员密码（若账户不存在则跳过）
if id "$OCTOP_USER" >/dev/null 2>&1; then
    echo "${OCTOP_USER}:${ADMIN_PASS}" | chpasswd 2>/dev/null || true
    echo "[octop-native] 已为 ${OCTOP_USER} 设置登录密码（与管理员密码一致）" > "${TRIM_TEMP_LOGFILE:-/dev/null}" 2>&1 || true
fi

# 写入免密码 sudo 规则并做语法校验。
# 这是本地版“远程桌面/浏览器/工作台终端”能正常工作的关键，必须成功；
# 因此这里不使用 || true 静默失败，若写入或校验失败则让安装回调直接返回非零，
# 避免飞牛显示“安装成功”但实际功能不可用（之前 printf+||true 导致文件被清空）。
SUDOERS_FILE="/etc/sudoers.d/octop-native"
cat > "$SUDOERS_FILE" <<'EOF'
# 允许 octop-native 免密码执行任意命令（Octop 远程桌面/浏览器/工作台终端需要）
# !requiretty：Octop 以内嵌子进程方式调用 `sudo -n ...`，没有 controlling tty；
# 若系统 sudoers 默认开启 requiretty，这里必须显式关闭，否则会报
# "sorry, you must have a tty to run sudo" 而让远程桌面/浏览器安装失败。
Defaults:octop-native !requiretty
octop-native ALL=(ALL) NOPASSWD: ALL
EOF
chmod 0440 "$SUDOERS_FILE"
if command -v visudo >/dev/null 2>&1; then
    if ! visudo -c -f "$SUDOERS_FILE" >/dev/null 2>&1; then
        echo "[octop-native] 错误：写入的 sudoers 语法校验失败，请检查 ${SUDOERS_FILE}" > "${TRIM_TEMP_LOGFILE:-/dev/null}" 2>&1 || true
        exit 1
    fi
fi
echo "[octop-native] 已配置 ${OCTOP_USER} 免密码 sudo" > "${TRIM_TEMP_LOGFILE:-/dev/null}" 2>&1 || true

# ---------------------------------------------------------------------------
# 将官方 octop CLI 暴露到 PATH，让用户安装后像官方一样直接用 `octop` 命令
# （例如 `octop --help` / `octop provider list` / `octop agent list` /
#   `octop user list` / `octop user passwd` / `octop skills ...` /
#   `octop backup ...`）。真正的服务由飞牛应用中心托管（cmd/main 拉起
#   bin/octop），本 CLI 仅作命令行入口。
# 并做一次冒烟验证：CLI 能真实执行并输出版本号才算注册成功。
# ---------------------------------------------------------------------------
CLI_SRC="$APPDEST/bin/octop-cli"
if [ -f "$CLI_SRC" ]; then
    chmod +x "$CLI_SRC" 2>/dev/null || true
    ln -sf "$CLI_SRC" /usr/local/bin/octop-cli
    ln -sf "$CLI_SRC" /usr/local/bin/octop
    echo "[octop-native] 已注册命令：octop / octop-cli -> $CLI_SRC" > "${TRIM_TEMP_LOGFILE:-/dev/null}" 2>&1 || true
    # CLI 冒烟验证（不阻塞安装：失败只告警，首次启动后仍可用）
    if "$CLI_SRC" version >/dev/null 2>&1; then
        echo "[octop-native] CLI 冒烟验证通过：octop version 可正常执行" > "${TRIM_TEMP_LOGFILE:-/dev/null}" 2>&1 || true
    else
        echo "[octop-native] 警告：CLI 冒烟验证未通过（octop version 执行失败）；首次启动会自动用内置 whl 离线安装，之后 CLI 即可用。" > "${TRIM_TEMP_LOGFILE:-/dev/null}" 2>&1 || true
    fi
fi

exit 0
