#!/usr/bin/env bash
# ════════════════════════════════════════════════════════════════
# 根据探测档位动态生成资源调优 · tune-from-env.sh
# Sovereign: TCS-0002∞ · 国作登字-2026-A-00037559
# 守护: 铸渊 · ICE-GL-ZY001
# ════════════════════════════════════════════════════════════════
#
# 读 detect-env.sh 写出的 server-env.json, 依据 size_tier 生成:
#   1. $DATA_ROOT/lighthouse/.env.tune  — 决策快照
#      含 SIZE_TIER / PG_SHARED_BUFFERS / PG_WORK_MEM / PG_MAX_CONN
#      / GITEA_CACHE_POOL / GITEA_QUEUE_LENGTH / RUNNER_DEFAULT_ENABLED
#   2. 决策回执 -> $DEPLOY_ROOT/_logs/tune-decision-*.json
#
# ⚠️  当前 .env.tune 的真实作用域 (2026-05-08 修正, 别再被注释误导):
#   .env.tune 不是 docker-compose 的 env_file. compose 启动时不会
#   自动读它 (docker-compose.yml 没有 env_file: .env.tune 声明).
#
#   bootstrap.sh 会在调 docker compose up 之前 `source .env.tune`,
#   **当前真正影响行为的只有 RUNNER_DEFAULT_ENABLED** — 它决定 update
#   阶段是否带 `--profile runner` 起 runner 容器.
#
#   PG_SHARED_BUFFERS / PG_WORK_MEM / PG_MAX_CONN / GITEA_CACHE_POOL /
#   GITEA_QUEUE_LENGTH 这些字段目前**只是档位决策的存档**, 写到 .env.tune
#   是为了:
#     a) tune-decision-*.json 回执留痕 (霜砚 / 冰朔可追溯)
#     b) 后续如果在 docker-compose.yml 加上 `env_file: ./.env.tune` +
#        在 postgres / gitea 服务里用 `${PG_SHARED_BUFFERS}` 引用,
#        这一份就立刻生效, 不用改 tune-from-env.sh
#
#   也就是说: 这个脚本现在做的事 = "决策 + 留档", 不是"实时调 PG".
#   要让 PG 调优真的生效, 需要在 docker-compose.yml 里手动加引用
#   (TODO 见 §下方).
#
# 档位策略 (因果链):
#   tiny   <4G  : runner 关掉, postgres shared_buffers=64M, gitea cache 减半
#   small  4-6G : runner 关掉, postgres shared_buffers=128M
#   medium 6-12G: runner=optional (默认关), postgres shared_buffers=256M
#   large  12-24G: runner=on,        postgres shared_buffers=512M
#   xlarge >=24G: runner=on,        postgres shared_buffers=1G
#
# 设计理念:
#   不再硬假设 4C16G. 2C8G 来了也能跑(只是 runner 默认关, 不会同时塞下);
#   8C32G 来了也能跑(自动放大 PG buffer). 这一层是"动态适配"的根基.
# ════════════════════════════════════════════════════════════════

set -euo pipefail

ENV_FILE="${ENV_FILE:-/opt/guanghu/_logs/server-env.json}"
DATA_ROOT="${DATA_ROOT:-/data}"
DEPLOY_ROOT="${DEPLOY_ROOT:-/opt/guanghu}"

if [ ! -f "$ENV_FILE" ]; then
  echo "❌ [tune] 找不到 $ENV_FILE, 请先跑 detect-env.sh" >&2
  exit 1
fi
if ! command -v jq >/dev/null 2>&1; then
  echo "❌ [tune] 需要 jq (apt-get install -y jq)" >&2
  exit 1
fi

SIZE_TIER="$(jq -r '.compute.size_tier' "$ENV_FILE")"
MEM_MB="$(jq -r '.compute.memory_total_mb' "$ENV_FILE")"
CPU="$(jq -r '.compute.cpu_count' "$ENV_FILE")"

# ─── 档位 → 参数表 ────────────────────────────────────────────
case "$SIZE_TIER" in
  tiny)
    PG_SHARED_BUFFERS="64MB"
    PG_WORK_MEM="2MB"
    PG_MAX_CONN="40"
    GITEA_CACHE_POOL="50"
    RUNNER_DEFAULT_ENABLED="false"
    GITEA_QUEUE_LENGTH="100"
    NOTE="资源极少, runner 必关, 不要同时跑大型 git push"
    ;;
  small)
    PG_SHARED_BUFFERS="128MB"
    PG_WORK_MEM="4MB"
    PG_MAX_CONN="60"
    GITEA_CACHE_POOL="100"
    RUNNER_DEFAULT_ENABLED="false"
    GITEA_QUEUE_LENGTH="200"
    NOTE="2C8G 档. Gitea+PG+Redis 能跑, runner 默认关 (按需手动 docker compose --profile runner up)"
    ;;
  medium)
    PG_SHARED_BUFFERS="256MB"
    PG_WORK_MEM="8MB"
    PG_MAX_CONN="100"
    GITEA_CACHE_POOL="100"
    RUNNER_DEFAULT_ENABLED="false"
    GITEA_QUEUE_LENGTH="500"
    NOTE="主流档. runner 默认关, 大型构建任务时再开"
    ;;
  large)
    PG_SHARED_BUFFERS="512MB"
    PG_WORK_MEM="16MB"
    PG_MAX_CONN="200"
    GITEA_CACHE_POOL="200"
    RUNNER_DEFAULT_ENABLED="true"
    GITEA_QUEUE_LENGTH="1000"
    NOTE="原计划 4C16G 主灯塔. runner 默认开"
    ;;
  xlarge)
    PG_SHARED_BUFFERS="1GB"
    PG_WORK_MEM="32MB"
    PG_MAX_CONN="300"
    GITEA_CACHE_POOL="300"
    RUNNER_DEFAULT_ENABLED="true"
    GITEA_QUEUE_LENGTH="2000"
    NOTE="超规格, 全部组件并行无忧"
    ;;
  *)
    echo "❌ [tune] 未知 size_tier=$SIZE_TIER" >&2
    exit 1
    ;;
esac

# ─── 写 .env.tune (compose 第二份 .env) ───────────────────────
TUNE_FILE="$DATA_ROOT/lighthouse/.env.tune"
mkdir -p "$(dirname "$TUNE_FILE")"
cat > "$TUNE_FILE" <<EOF
# Generated by tune-from-env.sh @ $(date -u +%Y-%m-%dT%H:%M:%SZ)
# 档位: $SIZE_TIER (基于 ${MEM_MB}MB 内存 / ${CPU} 核)
# 注: $NOTE
#
# ⚠️  作用域说明 (避免误判):
#   - bootstrap.sh source 这个文件, 当前**只读 RUNNER_DEFAULT_ENABLED**,
#     用它决定是否带 --profile runner 启 runner 容器.
#   - 下面的 PG_* / GITEA_* 字段是**档位决策的快照**, docker-compose.yml
#     当前并未通过 env_file 引用本文件, 所以这些值不会自动生效到 Postgres
#     / Gitea 容器内. 它们的用途是: (a) 留档可追溯 (b) 未来在 compose 里
#     加引用就能立刻生效, 无需改本脚本.
SIZE_TIER=$SIZE_TIER
PG_SHARED_BUFFERS=$PG_SHARED_BUFFERS
PG_WORK_MEM=$PG_WORK_MEM
PG_MAX_CONN=$PG_MAX_CONN
GITEA_CACHE_POOL=$GITEA_CACHE_POOL
GITEA_QUEUE_LENGTH=$GITEA_QUEUE_LENGTH
RUNNER_DEFAULT_ENABLED=$RUNNER_DEFAULT_ENABLED
EOF
chmod 644 "$TUNE_FILE"

# ─── 决策回执 ─────────────────────────────────────────────────
TS="$(date -u +%Y%m%d-%H%M%S)"
RECEIPT="$DEPLOY_ROOT/_logs/tune-decision-$TS.json"
mkdir -p "$DEPLOY_ROOT/_logs"
cat > "$RECEIPT" <<EOF
{
  "_sovereign": "TCS-0002∞ · 国作登字-2026-A-00037559",
  "decided_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "input": {
    "size_tier": "$SIZE_TIER",
    "memory_mb": $MEM_MB,
    "cpu_count": $CPU
  },
  "decision": {
    "PG_SHARED_BUFFERS": "$PG_SHARED_BUFFERS",
    "PG_WORK_MEM": "$PG_WORK_MEM",
    "PG_MAX_CONN": $PG_MAX_CONN,
    "GITEA_CACHE_POOL": $GITEA_CACHE_POOL,
    "GITEA_QUEUE_LENGTH": $GITEA_QUEUE_LENGTH,
    "RUNNER_DEFAULT_ENABLED": $RUNNER_DEFAULT_ENABLED
  },
  "note": "$NOTE",
  "tune_file": "$TUNE_FILE"
}
EOF

echo "═══════════════════════════════════════════════════════════"
echo "  [tune] 动态调优决策"
echo "═══════════════════════════════════════════════════════════"
echo "  档位:           $SIZE_TIER  (${MEM_MB}MB / ${CPU} 核)"
echo "  PG shared_buf:  $PG_SHARED_BUFFERS"
echo "  PG max_conn:    $PG_MAX_CONN"
echo "  Gitea cache:    $GITEA_CACHE_POOL"
echo "  Runner 默认:    $RUNNER_DEFAULT_ENABLED"
echo "  注:             $NOTE"
echo "  写入:           $TUNE_FILE"
echo "  回执:           $RECEIPT"
echo "═══════════════════════════════════════════════════════════"
