#!/bin/bash
#
# Octop 本地版 — 启动器
# 运行在飞牛主机上，依赖飞牛应用商店提供的 Python 3.12（不内置 Python 运行时）。
# 包内仅含 Octop 核心 whl + 核心依赖 site-packages；浏览器/专家/技能由用户按需安装。
# 首次启动用向导配置的 .env 初始化管理员账号，然后启动服务。
#
set -euo pipefail

# 共享函数库（find_python312 / fix_ownership_and_perms / free_octop_ports）
# 打包时由 scripts/build-fpk.sh 注入；仓库内运行无此文件时跳过（函数缺失时再报错）。
# 注意：FPK 解包后 cmd/ 落在 /var/apps/octop-native/cmd（管理目录），而本文件位于
# 负载目录 $TRIM_APPDEST/bin，`$0/../cmd` 指向载荷内不存在的位置，故需回退到
# 外层 cmd 的实际落点。
_OCTOP_COMMON="$(dirname "$0")/../cmd/common.sh"
[ -f "$_OCTOP_COMMON" ] || _OCTOP_COMMON="/var/apps/octop-native/cmd/common.sh"
[ -f "$_OCTOP_COMMON" ] && source "$_OCTOP_COMMON"

APPDEST="${TRIM_APPDEST:-/var/apps/octop-native}"
PKGVAR="${TRIM_PKGVAR:-/var/apps/octop-native/var}"

# 数据落在 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" "$PKGVAR"

# 加载向导配置（install_callback / config_callback 写入）
if [ -f "$PKGVAR/.env" ]; then
    set -a
    . "$PKGVAR/.env"
    set +a
fi

export HOME="$DATA_DIR"
export OCTOP_HOME="${DATA_DIR}/.octop"
export OCTOP_DATA_DIR="$DATA_DIR"

# 查找飞牛系统上的 Python 3.12（优先应用商店安装路径，再 PATH）


PY="$(find_python312)" || {
    echo "[octop-native] 错误：未找到 Python 3.12。" >&2
    echo "请先前往飞牛应用中心安装「Python 3.12」开发工具，再重新安装本应用。" >&2
    exit 1
}

SITE_PACKAGES="$APPDEST/site-packages"
export PYTHONPATH="${SITE_PACKAGES}${PYTHONPATH:+:${PYTHONPATH}}"

# 内置在线升级优先使用 uv（pip 对 orcakit-harness-agent[all] 依赖树解析会卡死）。
# 系统无 uv 且当前为 root 时自动安装一次（装到系统 Python bin，软链到 /usr/local/bin）。
if [ "$(id -u)" = "0" ] && ! command -v uv >/dev/null 2>&1; then
    "$PY" -m pip install -q --disable-pip-version-check uv 2>/dev/null || true
    if [ -x "$(dirname "$PY")/uv" ]; then
        ln -sf "$(dirname "$PY")/uv" /usr/local/bin/uv 2>/dev/null || true
    fi
fi

# 飞牛 FPK 部署标识 + 打包 site-packages 路径：内置在线升级安装到此目录
# （launcher 实际加载的位置），重启服务后即加载新版，升级真正生效
# （见 src/octop/infra/setup/self_update.py 的 _run_fpk_upgrade）。
export OCTOP_INSTALL_MODE="fpk-native"
export OCTOP_FPK_SITE_PACKAGES="$SITE_PACKAGES"

# 兜底：若包内 site-packages 中未检测到 octop（升级异常 / 损坏等），
# 用内置核心 whl 就地离线安装，避免用户联网下载。
if ! "$PY" -c "import octop" >/dev/null 2>&1; then
    echo "[octop-native] 未检测到已安装的 Octop，正在用内置核心 whl 离线安装 ..."
    "$PY" -m pip install --no-cache --no-index --find-links "$SITE_PACKAGES" "$SITE_PACKAGES/octop.whl" >/dev/null 2>&1 || {
        echo "[octop-native] 离线安装失败，请检查网络或手动执行：$PY -m pip install $SITE_PACKAGES/octop.whl" >&2
        exit 1
    }
fi

OCTOP_PORT="${OCTOP_PORT:-8089}"
OCTOP_LOG_LEVEL="${OCTOP_LOG_LEVEL:-info}"
OCTOP_BIND_HOST="${OCTOP_BIND_HOST:-0.0.0.0}"

mkdir -p "$OCTOP_HOME"

octop_cmd() {
    "$PY" -m octop.cli.main "$@"
}

# 首次初始化管理员账号（仅当数据库尚未建立）。
# 密码兜底链（修复 issue #502）：
#   1) .env 未写密码（旧包/异常安装）→ 自动生成随机密码；
#   2) init 因密码策略被拒（如旧版写死的 Octop123 在弱密码黑名单内，
#      报 "password is too common"）→ 换随机强密码重试一次；
#   3) 重试后同步回写 .env 与 octop-login.txt 回落备份，保证凭据一致、用户不丢密码。
if [ ! -f "$OCTOP_HOME/octop.db" ]; then
    echo "[octop-native] 首次启动，正在初始化管理员账号 ..."
    INIT_PW="${OCTOP_DEFAULT_PASSWORD:-}"
    if [ -z "$INIT_PW" ]; then
        INIT_PW="$(octop_generate_password 16)"
        echo "[octop-native] .env 未配置初始密码，已自动生成随机密码。"
    fi
    if ! octop_cmd init --yes \
        --admin-username "${OCTOP_ADMIN_USERNAME:-admin}" \
        --admin-password "$INIT_PW" \
        ${OCTOP_ADMIN_DISPLAY_NAME:+--admin-display-name "$OCTOP_ADMIN_DISPLAY_NAME"}; then
        echo "[octop-native] 初始密码未通过应用密码策略（过弱或过于常见），改用随机密码重试 ..."
        INIT_PW="$(octop_generate_password 16)"
        octop_cmd init --yes \
            --admin-username "${OCTOP_ADMIN_USERNAME:-admin}" \
            --admin-password "$INIT_PW" \
            ${OCTOP_ADMIN_DISPLAY_NAME:+--admin-display-name "$OCTOP_ADMIN_DISPLAY_NAME"} || {
            echo "[octop-native] 错误：管理员账号初始化失败，请查看上方日志。" >&2
            exit 1
        }
    fi
    # .env 里的密码与实际生效密码不一致时（随机重试/自动生成路径），回写 .env，
    # 让「设置」窗口显示、octop-cli 改密等链路拿到的都是真实凭据。
    if [ "$INIT_PW" != "${OCTOP_DEFAULT_PASSWORD:-}" ]; then
        octop_env_set "$PKGVAR/.env" OCTOP_DEFAULT_PASSWORD "$INIT_PW"
        export OCTOP_DEFAULT_PASSWORD="$INIT_PW"
    fi
    octop_write_login_file "$DATA_DIR" "${OCTOP_ADMIN_USERNAME:-admin}" "$INIT_PW" "${OCTOP_PORT:-8089}"
fi

echo "[octop-native] 正在启动 Octop，$OCTOP_BIND_HOST:$OCTOP_PORT ..."
exec "$PY" -m octop.cli.main run --host "$OCTOP_BIND_HOST" --port "$OCTOP_PORT" --log-level "${OCTOP_LOG_LEVEL}"
