#!/usr/bin/env bash
# TokenomixAI: install OpenCode + konfigurasi API key (Linux & macOS).
# Pakai: bash <(curl -fsSL https://tokenomixai.com/install/opencode.sh)
# Balik ke config semula: bash <(curl -fsSL https://tokenomixai.com/install/opencode.sh) --restore
#   atau: RESTORE=1 bash <(curl -fsSL https://tokenomixai.com/install/opencode.sh)
# Ambil model baru tanpa install ulang: bash <(curl -fsSL https://tokenomixai.com/install/opencode.sh) --update-models
# Opsional: API_KEY="sk-tkx-..." BASE_URL="https://api.tokenomixai.com/v1" bash <(curl -fsSL ...)
set -euo pipefail

BASE_URL="${BASE_URL:-https://api.tokenomixai.com/v1}"
BASE_URL="${BASE_URL%/}"
SITE_URL="${SITE_URL:-https://tokenomixai.com}"
PREFERRED_DEFAULT="deepseek-v4-pro deepseek-v4-pro-0813 glm-5.2 glm-5.3"

echo "=== TokenomixAI x OpenCode ==="

# Mode restore: kembalikan config dari backup terbaru, balik ke setting semula.
RESTORE="${RESTORE:-}"
if [ "${1:-}" = "--restore" ]; then RESTORE=1; fi
if [ -n "$RESTORE" ]; then
  RESTORE_DIR="$HOME/.config/opencode"
  rm -f "$RESTORE_DIR/plugins/tokenomix-quota.js"
  LATEST="$(ls -t "$RESTORE_DIR"/opencode.json.bak-* 2>/dev/null | head -n1 || true)"
  if [ -z "$LATEST" ]; then
    echo "Error: backup tidak ditemukan di $RESTORE_DIR. Config tidak diubah, hubungi admin TokenomixAI." >&2
    exit 1
  fi
  STAMP_RESTORE="${LATEST##*.bak-}"
  cp "$LATEST" "$RESTORE_DIR/opencode.json"
  JSONC_BAK="$RESTORE_DIR/opencode.jsonc.bak-$STAMP_RESTORE"
  if [ -f "$JSONC_BAK" ]; then cp "$JSONC_BAK" "$RESTORE_DIR/opencode.jsonc"; fi
  chmod 600 "$RESTORE_DIR/opencode.json" 2>/dev/null || true
  if [ -f "$RESTORE_DIR/opencode.jsonc" ]; then chmod 600 "$RESTORE_DIR/opencode.jsonc"; fi
  echo "OK: config dikembalikan dari backup $LATEST."
  echo "Buka terminal baru lalu jalankan: opencode"
  exit 0
fi

# Mode update model: hanya daftar model TokenomixAI di config yang diganti, setting lain tidak disentuh.
UPDATE_MODELS="${UPDATE_MODELS:-}"
if [ "${1:-}" = "--update-models" ]; then UPDATE_MODELS=1; fi
CONFIG_DIR="$HOME/.config/opencode"
if [ -n "$UPDATE_MODELS" ]; then
  if ! command -v python3 >/dev/null 2>&1; then
    echo "Error: update model butuh python3. Jalankan command install biasa (tanpa --update-models)." >&2
    exit 1
  fi
  # Pakai key yang sudah tersimpan di config supaya tidak perlu ditempel ulang.
  API_KEY="${API_KEY:-}"
  for f in opencode.json opencode.jsonc; do
    [ -z "$API_KEY" ] && [ -f "$CONFIG_DIR/$f" ] || continue
    SAVED_KEY=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1]))['provider']['tokenomixai']['options']['apiKey'])" "$CONFIG_DIR/$f" 2>/dev/null || true)
    case "$SAVED_KEY" in sk-tkx-*) API_KEY="$SAVED_KEY" ;; esac
  done
  # Config manual dari Docs menyimpan key di env TOKENOMIXAI_API_KEY.
  API_KEY="${API_KEY:-${TOKENOMIXAI_API_KEY:-}}"
fi

API_KEY="${API_KEY:-}"
if [ -z "$API_KEY" ]; then
  printf "Tempel API key TokenomixAI (sk-tkx-..., tidak tampil saat diketik): "
  read -rs API_KEY < /dev/tty
  echo
fi
API_KEY="$(printf '%s' "$API_KEY" | tr -d '[:space:]')"
if ! printf '%s' "$API_KEY" | grep -Eq '^sk-tkx-[A-Za-z0-9]+$'; then
  echo "Error: API key harus diawali sk-tkx-. Cek lagi key dari halaman sukses order atau bot Telegram." >&2
  exit 1
fi

# Validasi key dulu sebelum mengubah apa pun di komputer ini.
echo "-> Mengecek API key..."
TMP_BODY=$(mktemp)
HTTP_CODE=$(curl -sS -o "$TMP_BODY" -w '%{http_code}' "$BASE_URL/models" -H "Authorization: Bearer $API_KEY" || echo 000)
MODELS_RESPONSE="$(cat "$TMP_BODY")"
rm -f "$TMP_BODY"
case "$HTTP_CODE" in
  200) ;;
  401) echo "Error: API key salah atau tidak dikenal." >&2; exit 1 ;;
  403) echo "Error: API key nonaktif. Hubungi admin TokenomixAI." >&2; exit 1 ;;
  *) echo "Error: gagal menghubungi $BASE_URL (HTTP $HTTP_CODE). Cek koneksi lalu coba lagi." >&2; exit 1 ;;
esac

if command -v python3 >/dev/null 2>&1; then
  MODEL_IDS=$(printf '%s' "$MODELS_RESPONSE" | python3 -c "import sys,json; [print(m['id']) for m in json.load(sys.stdin).get('data',[])]")
  VISION_MODELS=$(printf '%s' "$MODELS_RESPONSE" | python3 -c "import sys,json; [print(m['id']) for m in json.load(sys.stdin).get('data',[]) if m.get('vision') is True]")
elif command -v jq >/dev/null 2>&1; then
  MODEL_IDS=$(printf '%s' "$MODELS_RESPONSE" | jq -r '.data[].id')
  VISION_MODELS=$(printf '%s' "$MODELS_RESPONSE" | jq -r '.data[] | select(.vision == true) | .id')
else
  MODEL_IDS=$(printf '%s' "$MODELS_RESPONSE" | grep -o '"id":"[^"]*"' | sed 's/"id":"//; s/"$//')
  VISION_MODELS=""
fi
# ID model ditulis mentah ke JSON: buang yang bukan karakter ID biasa supaya tidak bisa menyisipkan config.
MODEL_IDS=$(printf '%s\n' "$MODEL_IDS" | grep -E '^[A-Za-z0-9._:/-]+$' || true)
if [ -z "$MODEL_IDS" ]; then
  echo "Error: daftar model kosong. Coba lagi beberapa saat." >&2
  exit 1
fi

DEFAULT_MODEL=""
for m in $PREFERRED_DEFAULT; do
  if printf '%s\n' "$MODEL_IDS" | grep -Fxq "$m"; then DEFAULT_MODEL="$m"; break; fi
done
[ -n "$DEFAULT_MODEL" ] || DEFAULT_MODEL=$(printf '%s\n' "$MODEL_IDS" | head -n1)
echo "OK: $(printf '%s\n' "$MODEL_IDS" | wc -l | tr -d ' ') model, default: $DEFAULT_MODEL"

if [ -n "$UPDATE_MODELS" ]; then
  # Script ditaruh di variabel: heredoc di dalam $(...) gagal di-parse bash 3.2 (macOS).
  read -r -d '' MERGE_PY <<'PY' || true
import json, os, sys
src, dst = sys.argv[1], sys.argv[2]
with open(src) as f:
    data = json.load(f)
provider = data["provider"]["tokenomixai"]
if not isinstance(provider, dict):
    raise SystemExit(1)
old = provider.get("models") if isinstance(provider.get("models"), dict) else {}
vision = set(os.environ["VISION_MODELS"].split("\n"))
ids = [m for m in os.environ["MODEL_IDS"].split("\n") if m]
provider["models"] = {m: {"name": m, "modalities": {"input": ["text", "image"] if m in vision else ["text"], "output": ["text"]}} for m in ids}
with open(dst, "w") as f:
    json.dump(data, f, indent=2)
    f.write("\n")
print("\n".join(m for m in ids if m not in old))
PY
  umask 077
  STAMP=$(date +%Y%m%d-%H%M%S)
  UPDATED=""
  NEW_MODELS=""
  for f in opencode.json opencode.jsonc; do
    FILE="$CONFIG_DIR/$f"
    [ -f "$FILE" ] || continue
    TMP_CFG=$(mktemp "$CONFIG_DIR/.$f.XXXXXX")
    if FILE_NEW=$(MODEL_IDS="$MODEL_IDS" VISION_MODELS="$VISION_MODELS" python3 -c "$MERGE_PY" "$FILE" "$TMP_CFG" 2>/dev/null); then
      cp "$FILE" "$FILE.bak-$STAMP"
      mv "$TMP_CFG" "$FILE"
      chmod 600 "$FILE"
      echo "Backup: $FILE.bak-$STAMP"
      UPDATED="$UPDATED $f"
      [ -n "$NEW_MODELS" ] || NEW_MODELS="$FILE_NEW"
    else
      rm -f "$TMP_CFG"
      echo "Peringatan: $FILE bukan JSON biasa atau belum berisi provider TokenomixAI, dilewati." >&2
    fi
  done
  if [ -z "$UPDATED" ]; then
    echo "Error: config TokenomixAI tidak ditemukan di $CONFIG_DIR. Jalankan command install biasa (tanpa --update-models)." >&2
    exit 1
  fi
  echo "OK: daftar model diperbarui di$UPDATED"
  if [ -n "$NEW_MODELS" ]; then
    echo "Model baru:"
    printf '%s\n' "$NEW_MODELS" | sed 's/^/  /'
  else
    echo "Tidak ada model baru sejak update terakhir."
  fi
  echo
  echo "Tutup lalu buka lagi opencode, pilih model dengan /models"
  exit 0
fi

if command -v opencode >/dev/null 2>&1; then
  # Versi < 1.0.216 rentan CVE-2026-22812 (server lokal tanpa auth bisa menjalankan perintah).
  OC_VERSION=$(opencode --version 2>/dev/null | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n1 || true)
  if [ -n "$OC_VERSION" ] && [ "$(printf '%s\n%s\n' "$OC_VERSION" 1.0.216 | sort -t. -k1,1n -k2,2n -k3,3n | head -n1)" != 1.0.216 ]; then
    echo "-> opencode $OC_VERSION terlalu lama, memperbarui..."
    opencode upgrade || echo "Peringatan: update opencode gagal. Jalankan manual: opencode upgrade" >&2
  fi
  echo "OK: opencode sudah terpasang"
else
  echo "-> Menginstall opencode..."
  curl -fsSL https://opencode.ai/install | bash
  echo "OK: opencode terpasang"
fi

# File config & backup berisi API key: hanya bisa dibaca user ini sejak dibuat.
umask 077
mkdir -p "$CONFIG_DIR"
STAMP=$(date +%Y%m%d-%H%M%S)
for f in opencode.json opencode.jsonc; do
  if [ -f "$CONFIG_DIR/$f" ]; then
    cp "$CONFIG_DIR/$f" "$CONFIG_DIR/$f.bak-$STAMP"
    echo "Backup: $CONFIG_DIR/$f.bak-$STAMP"
  fi
done

FRESH_CFG=$(mktemp "$CONFIG_DIR/.opencode.fresh.XXXXXX")
{
  echo '{'
  echo '  "$schema": "https://opencode.ai/config.json",'
  echo '  "provider": {'
  echo '    "tokenomixai": {'
  echo '      "name": "TokenomixAI",'
  echo '      "npm": "@ai-sdk/openai-compatible",'
  echo '      "options": {'
  echo "        \"baseURL\": \"$BASE_URL\","
  echo "        \"apiKey\": \"$API_KEY\""
  echo '      },'
  echo '      "models": {'
  TOTAL=$(printf '%s\n' "$MODEL_IDS" | wc -l | tr -d ' ')
  COUNT=0
  while IFS= read -r model; do
    COUNT=$((COUNT + 1))
    COMMA=","; [ "$COUNT" -lt "$TOTAL" ] || COMMA=""
    INPUT='["text"]'
    if printf '%s\n' "$VISION_MODELS" | grep -Fxq "$model"; then INPUT='["text", "image"]'; fi
    echo "        \"$model\": { \"name\": \"$model\", \"modalities\": { \"input\": $INPUT, \"output\": [\"text\"] } }$COMMA"
  done <<< "$MODEL_IDS"
  echo '      }'
  echo '    }'
  echo '  },'
  echo "  \"model\": \"tokenomixai/$DEFAULT_MODEL\""
  echo '}'
} > "$FRESH_CFG"

# Config lama digabung, bukan ditimpa: MCP, plugin, dan provider lain milik user tetap ada.
# Yang diganti hanya provider tokenomixai + model default. Entry MCP/plugin yang salah menunjuk ke
# tokenomix-quota.js (plugin, bukan MCP) dibuang. File berisi komentar (JSONC) atau tanpa python3 = ditulis ulang.
read -r -d '' CONFIG_MERGE_PY <<'PY' || true
import json, sys
existing, fresh, out = sys.argv[1], sys.argv[2], sys.argv[3]
with open(fresh) as f:
    new = json.load(f)
with open(existing, encoding="utf-8-sig") as f:
    data = json.load(f)
if not isinstance(data, dict):
    raise SystemExit(1)
def is_quota(v):
    return "tokenomix-quota" in json.dumps(v)
if isinstance(data.get("mcp"), dict):
    data["mcp"] = {k: v for k, v in data["mcp"].items() if not is_quota(k) and not is_quota(v)}
if isinstance(data.get("plugin"), list):
    data["plugin"] = [p for p in data["plugin"] if not is_quota(p)]
data.setdefault("$schema", new["$schema"])
if not isinstance(data.get("provider"), dict):
    data["provider"] = {}
data["provider"]["tokenomixai"] = new["provider"]["tokenomixai"]
data["model"] = new["model"]
with open(out, "w") as f:
    json.dump(data, f, indent=2, ensure_ascii=False)
    f.write("\n")
PY
for f in opencode.json opencode.jsonc; do
  FILE="$CONFIG_DIR/$f"
  TMP_CFG=$(mktemp "$CONFIG_DIR/.$f.XXXXXX")
  if [ -f "$FILE" ] && command -v python3 >/dev/null 2>&1 && python3 -c "$CONFIG_MERGE_PY" "$FILE" "$FRESH_CFG" "$TMP_CFG" 2>/dev/null; then
    echo "OK: $f diperbarui, setting lain tetap"
  else
    if [ -f "$FILE" ]; then echo "Info: $f berisi komentar atau tidak bisa dibaca, ditulis ulang (backup di atas)"; fi
    cp "$FRESH_CFG" "$TMP_CFG"
  fi
  mv "$TMP_CFG" "$FILE"
  chmod 600 "$FILE"
done
rm -f "$FRESH_CFG"

echo "OK: config ditulis ke $CONFIG_DIR/opencode.json"

# Plugin peringatan sisa kuota (toast di OpenCode). Gagal unduh = dilewati, OpenCode tetap jalan.
mkdir -p "$CONFIG_DIR/plugins"
QUOTA_PLUGIN="$CONFIG_DIR/plugins/tokenomix-quota.js"
if curl -fsSL "$SITE_URL/install/opencode-quota.js" -o "$QUOTA_PLUGIN.tmp" && head -n1 "$QUOTA_PLUGIN.tmp" | grep -q '^// TokenomixAI: peringatan sisa kuota'; then
  mv "$QUOTA_PLUGIN.tmp" "$QUOTA_PLUGIN"
  echo "OK: peringatan sisa kuota aktif (muncul di OpenCode setelah AI selesai menjawab)"
else
  rm -f "$QUOTA_PLUGIN.tmp"
  echo "Info: plugin sisa kuota gagal diunduh, dilewati. Cek sisa kuota di https://tokenomixai.com/portal"
fi
echo
echo "=== Selesai ==="
echo "Buka terminal baru lalu jalankan: opencode"
echo "Model default: tokenomixai/$DEFAULT_MODEL (ganti model di OpenCode dengan /models)"
echo "Ada model baru di katalog? Jalankan:"
echo "  bash <(curl -fsSL https://tokenomixai.com/install/opencode.sh) --update-models"
echo
echo "Mau balik ke config semula? Jalankan:"
echo "  bash <(curl -fsSL https://tokenomixai.com/install/opencode.sh) --restore"
