#!/bin/bash
# pg_recommend_for_spec.sh — 給定 target + 新 SPEC（CPU/RAM），輸出 pgtune 推薦值 JSON
#   （workload / max_connections / 個別 param 皆吃 pg_analyzer.conf，與掃描頁 pg_analyzer.sh 一致）
#
# 用法：
#   pg_recommend_for_spec.sh TARGET NEW_CPU NEW_RAM_GB
#   NEW_CPU = 邏輯 CPU（機器上的 nproc；OCI x86 Flex = OCPU×2，前端 MS_PG_CPU_FACTOR 已換算）
#
# 輸出（stdout）：
#   JSON array [{"name":"...","value":"..."}, ...]，只含 PGAPPLY_WHITELIST 內的 param
#
# 用途：
#   spec_orchestrator resize chain pre-stage 餵 pg_apply_batch.sh --no-restart；
#   ajax 端 pg_diff_for_resize 也可用此 wrapper 出 JSON 給前端 diff 表。

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=./_lib_pg_apply.sh
source "${SCRIPT_DIR}/_lib_pg_apply.sh"
# conf 解析與掃描頁共用同一套（classify_workload / config_lookup / PGCONF_OVERRIDE_KEYS）
# shellcheck source=./_lib_pg_conf.sh
source "${SCRIPT_DIR}/_lib_pg_conf.sh"

TARGET="${1:-}"
NEW_CPU="${2:-}"
NEW_RAM_GB="${3:-}"

[[ -z "$TARGET" || -z "$NEW_CPU" || -z "$NEW_RAM_GB" ]] && {
    echo "Usage: $0 TARGET NEW_CPU NEW_RAM_GB" >&2; exit 1; }

# 1. SSH target 取 PG version（與 pg_apply_batch.sh 同一支 collector）
spec_data=$(pgapply_collect_spec "$TARGET" 2>/dev/null || true)
[[ -z "$spec_data" ]] && { echo "SSH 失敗：${TARGET}" >&2; exit 2; }
PG_VER=$(echo "$spec_data" | awk -F= '/^PG_VERSION=/ {print $2}')
[[ -z "$PG_VER" ]] && PG_VER=16

# 2. workload / connections：與掃描頁同邏輯，吃 pg_analyzer.conf
#    TARGET 即 PG primary alias（大寫，如 GAMEDB10 / WORLDDB1001），直接當 alias 查 conf
WORKLOAD=$(classify_workload "$TARGET")
CONNS=$(config_lookup "max_connections" "$TARGET" 2>/dev/null || true)

# 3. 跑 pgtune_cli.py
PGTUNE="${SCRIPT_DIR}/pgtune_cli.py"
[[ -x "$PGTUNE" ]] || { echo "PGTUNE not executable: $PGTUNE" >&2; exit 3; }
CONN_ARG=()
[[ -n "$CONNS" ]] && CONN_ARG=(--connections "$CONNS")
RAW=$("$PGTUNE" --db-version "$PG_VER" --os linux --db-type "$WORKLOAD" \
    --cpu "$NEW_CPU" --ram "$NEW_RAM_GB" --ram-unit GB --hd-type hdd \
    --db-size mid_ram "${CONN_ARG[@]}" 2>/dev/null || true)
[[ -z "$RAW" ]] && { echo "pgtune 無輸出" >&2; exit 4; }

# 4. 個別 param override：conf 指定就蓋掉 pgtune 出的值（與掃描頁 8-key override 一致）
OVERRIDES=""
for key in $PGCONF_OVERRIDE_KEYS; do
    oval=$(config_lookup "$key" "$TARGET" 2>/dev/null || true)
    [[ -n "$oval" ]] && OVERRIDES+="${key}=${oval}"$'\n'
done

# 5. 用 base64 把 RAW + override 安全餵給 python，過白名單後組 JSON
RAW_B64=$(printf '%s' "$RAW" | base64 -w0)
OVERRIDES_B64=$(printf '%s' "$OVERRIDES" | base64 -w0)
WHITELIST_CSV=$(IFS=','; echo "${PGAPPLY_WHITELIST[*]}")

python3 - "$RAW_B64" "$WHITELIST_CSV" "$OVERRIDES_B64" <<'PY'
import base64, json, sys
raw = base64.b64decode(sys.argv[1]).decode("utf-8", "replace")
whitelist = set(sys.argv[2].split(","))
overrides = {}
if len(sys.argv) > 3 and sys.argv[3]:
    ov_raw = base64.b64decode(sys.argv[3]).decode("utf-8", "replace")
    for line in ov_raw.splitlines():
        line = line.strip()
        if "=" not in line:
            continue
        k, _, v = line.partition("=")
        k = k.strip(); v = v.strip()
        if k in whitelist and v != "":
            overrides[k] = v
result = []
seen = set()
for line in raw.splitlines():
    line = line.strip()
    if not line or line.startswith("#"):
        continue
    if "=" not in line:
        continue
    k, _, v = line.partition("=")
    k = k.strip(); v = v.strip()
    if k not in whitelist or v == "":
        continue
    if k in overrides:
        v = overrides[k]
    result.append({"name": k, "value": v})
    seen.add(k)
# conf override 指定、但 pgtune 沒輸出的 key 也要補進去（與掃描頁 recommend[key]=val 一致）
for k, v in overrides.items():
    if k not in seen:
        result.append({"name": k, "value": v})
print(json.dumps(result))
PY
