#!/bin/sh
# Soloniq Code — sets up OpenCode (open source, MIT, opencode.ai) to use Soloniq's EU-hosted models.
#
#   curl -fsSL https://soloniq.com/code.sh | sh
#
# What it does:
#   1. Installs OpenCode with its official installer, if it is not installed yet.
#   2. Asks for your Soloniq API key (or reads SOLONIQ_API_KEY) and checks it.
#   3. Writes ~/.config/soloniq/opencode.json: Soloniq as the only provider, session sharing off.
#   4. Adds the command `soloniq`, which starts OpenCode with that configuration.
#      `soloniq --remote` makes this folder usable from the Soloniq Code app on your phone.
# Your other OpenCode settings are not changed. New key: soloniq --key. Remove: soloniq --uninstall
set -eu

API="${SOLONIQ_API_URL:-https://api.soloniq.com/v1}"
SITE="${SOLONIQ_SITE_URL:-https://soloniq.com}"
OPENCODE_VERSION="${SOLONIQ_OPENCODE_VERSION:-1.19.5}"   # tested with Soloniq
CONF="${XDG_CONFIG_HOME:-$HOME/.config}/soloniq"
BIN="$HOME/.local/bin"

say() { printf '%s\n' "$*"; }
die() { printf '\nError: %s\n' "$*" >&2; exit 1; }
# Hidden key input turns terminal echo off; always turn it back on, also on Ctrl+C.
ECHO_OFF=""
restore() { [ -n "$ECHO_OFF" ] && stty echo < /dev/tty 2>/dev/null; ECHO_OFF=""; }
trap 'restore' EXIT
trap 'restore; printf "\nCancelled. Run the same command again to finish the setup.\n" >&2; exit 130' INT TERM

[ "$(uname -s)" = "Linux" ] || [ "$(uname -s)" = "Darwin" ] || die "Linux or macOS only. On Windows, run this inside WSL."
command -v curl >/dev/null 2>&1 || die "curl is required."

say ""
say "Soloniq Code: OpenCode with AI models on servers in the EU."
say ""

# 1. OpenCode
OC=""
if command -v opencode >/dev/null 2>&1; then
  OC="$(command -v opencode)"
  say "OpenCode is already installed ($("$OC" --version 2>/dev/null || echo "unknown version"))."
elif [ -x "$HOME/.opencode/bin/opencode" ]; then
  OC="$HOME/.opencode/bin/opencode"
else
  say "Installing OpenCode $OPENCODE_VERSION from opencode.ai ..."
  curl -fsSL https://opencode.ai/install | bash -s -- --version "$OPENCODE_VERSION" --no-modify-path >/dev/null \
    || die "OpenCode could not be installed. See https://opencode.ai/docs"
  OC="$HOME/.opencode/bin/opencode"
fi
[ -x "$OC" ] || die "OpenCode was not found after installing."

# 2. API key: from SOLONIQ_API_KEY, else the saved one, else ask.
mkdir -p "$CONF"
chmod 700 "$CONF"
KEY="${SOLONIQ_API_KEY:-}"
if [ -z "$KEY" ] && [ -z "${SOLONIQ_NEW_KEY:-}" ] && [ -s "$CONF/api-key" ]; then
  KEY="$(cat "$CONF/api-key")"
  say "Using your saved Soloniq key (set SOLONIQ_API_KEY to use another)."
fi
if [ -z "$KEY" ]; then
  [ -r /dev/tty ] || die "No terminal to ask for the key. Run with SOLONIQ_API_KEY=sq_live_... set."
  say "Paste your Soloniq API key (create one at https://app.soloniq.com under Keys)."
  printf 'Key (hidden): '
  ECHO_OFF=1
  stty -echo < /dev/tty 2>/dev/null || true
  read -r KEY < /dev/tty || true
  restore
  say ""
fi
KEY="$(printf '%s' "$KEY" | tr -d '[:space:]')"
[ -n "$KEY" ] || die "No key entered. OpenCode is installed; when you have a key, run the same command again:
  curl -fsSL https://soloniq.com/code.sh | sh"
case "$KEY" in sq_live_*) ;; *) die "That does not look like a Soloniq key (it starts with sq_live_). Run the same command again to retry." ;; esac

MODELS_JSON="$(curl -fsS -m 20 -H "Authorization: Bearer $KEY" "$API/models" 2>/dev/null)" \
  || die "The key was not accepted by $API. Check it in the console under Keys."
ALLOWED="$(printf '%s' "$MODELS_JSON" | tr ',' '\n' | sed -n 's/.*"id" *: *"soloniq\/\([^"]*\)".*/\1/p')"
[ -n "$ALLOWED" ] || die "This key may not use any model. Add models to it in the console."

umask 077
printf '%s' "$KEY" > "$CONF/api-key"

# 3. Configuration. Model facts: id|name|context tokens|accepts images
CATALOG="agent|Agent (default)|1000000|true
agent-fast|Agent Fast|1000000|true
agent-pro|Agent Pro|1000000|false
kimi-k2.7-code|Kimi K2.7 Code|256000|true
glm-5.3|GLM-5.3|1000000|false
deepseek-v4-pro|DeepSeek V4 Pro|1000000|false
glm-5.3-flash|GLM-5.3-Flash|1000000|true
deepseek-v4.1-flash|DeepSeek V4.1 Flash|1000000|true
deepseek-v4-flash|DeepSeek V4 Flash|1000000|false
qwen-3.8|Qwen 3.8|256000|false
qwen-3.8-flash|Qwen 3.8 Flash|256000|true
minimax-m3|MiniMax M3|1000000|true
kimi-k3|Kimi K3|1000000|true"

MODELS=""
FIRST=""
for id in $(printf '%s\n' "$CATALOG" | cut -d'|' -f1); do
  printf '%s\n' "$ALLOWED" | grep -qx "$id" || continue
  line="$(printf '%s\n' "$CATALOG" | grep "^$id|")"
  name="$(printf '%s' "$line" | cut -d'|' -f2)"
  ctx="$(printf '%s' "$line" | cut -d'|' -f3)"
  img="$(printf '%s' "$line" | cut -d'|' -f4)"
  [ -z "$FIRST" ] && FIRST="$id"
  [ -n "$MODELS" ] && MODELS="$MODELS,"
  MODELS="$MODELS
        \"$id\": { \"name\": \"$name\", \"tool_call\": true, \"attachment\": $img, \"limit\": { \"context\": $ctx, \"output\": 32768 } }"
done
[ -n "$FIRST" ] || die "None of this key's models are known to this installer. Please update: curl -fsSL https://soloniq.com/code.sh | sh"
DEFAULT="$FIRST"; printf '%s\n' "$ALLOWED" | grep -qx agent && DEFAULT="agent"
SMALL="$DEFAULT"; printf '%s\n' "$ALLOWED" | grep -qx agent-fast && SMALL="agent-fast"

cat > "$CONF/opencode.json" <<EOF
{
  "\$schema": "https://opencode.ai/config.json",
  "provider": {
    "soloniq": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "Soloniq (EU)",
      "options": { "baseURL": "$API", "apiKey": "{file:$CONF/api-key}" },
      "models": {$MODELS
      }
    }
  },
  "model": "soloniq/$DEFAULT",
  "small_model": "soloniq/$SMALL",
  "enabled_providers": ["soloniq"],
  "share": "disabled"
}
EOF

# Themes: Tokyonight in terminals with full colour support; elsewhere the terminal's own colours, so it stays readable.
printf '{ "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" }\n' > "$CONF/tui.json"
printf '{ "$schema": "https://opencode.ai/tui.json", "theme": "system" }\n' > "$CONF/tui-basic.json"

# Bridge for the phone app (soloniq --remote). Runs inside OpenCode's own runtime; nothing else to install.
curl -fsS -m 30 "$SITE/code/remote.js" -o "$CONF/remote.js.new" 2>/dev/null && mv "$CONF/remote.js.new" "$CONF/remote.js" \
  || say "Note: the phone bridge could not be downloaded; soloniq --remote will not work until you run this again."
# Keeps OpenCode's exit hint pointing at `soloniq -s <session>` instead of plain `opencode` (not set up for Soloniq).
curl -fsS -m 30 "$SITE/code/tty.js" -o "$CONF/tty.js.new" 2>/dev/null && mv "$CONF/tty.js.new" "$CONF/tty.js" || rm -f "$CONF/tty.js.new"

# 4. The `soloniq` command
mkdir -p "$BIN"
cat > "$BIN/soloniq" <<EOF
#!/bin/sh
# Soloniq Code: OpenCode with Soloniq's EU models. Set up by https://soloniq.com/code.sh
if [ "\${1:-}" = "--uninstall" ]; then
  rm -rf "$CONF" "$BIN/soloniq"
  echo "Soloniq Code removed. OpenCode itself stays installed (remove it with: opencode uninstall)."
  exit 0
fi
if [ "\${1:-}" = "--key" ]; then
  curl -fsSL https://soloniq.com/code.sh | SOLONIQ_NEW_KEY=1 sh
  exit \$?
fi
export OPENCODE_CONFIG="$CONF/opencode.json"
case "\${SOLONIQ_THEME:-\${COLORTERM:-}}" in
  truecolor|24bit|tokyonight) export OPENCODE_TUI_CONFIG="$CONF/tui.json" ;;
  *) export OPENCODE_TUI_CONFIG="$CONF/tui-basic.json" ;;
esac
export OPENCODE_DISABLE_MODELS_FETCH=1
# Stay on the OpenCode version tested with Soloniq; re-run the installer to move to a newer tested one.
export OPENCODE_DISABLE_AUTOUPDATE=1
if [ "\${1:-}" = "--remote" ]; then
  shift
  [ -f "$CONF/remote.js" ] || { echo "Run the installer again to add the phone bridge: curl -fsSL $SITE/code.sh | sh"; exit 1; }
  # BUN_BE_BUN=1 makes the OpenCode binary run our bridge script; the bridge starts OpenCode itself without it.
  BUN_BE_BUN=1 exec "$OC" "$CONF/remote.js" --conf "$CONF" --opencode "$OC" "\$@"
fi
[ -f "$CONF/tty.js" ] && BUN_BE_BUN=1 exec "$OC" "$CONF/tty.js" "$OC" "\$@"
exec "$OC" "\$@"
EOF
chmod 755 "$BIN/soloniq"

say "Done. Models for this key: $(printf '%s' "$ALLOWED" | tr '\n' ' ')"
say ""
case ":$PATH:" in
  *":$BIN:"*) say "Start it in your project folder:  soloniq" ;;
  *)
    # Put ~/.local/bin on the PATH for new shells (once), like most installers do.
    for rc in "$HOME/.bashrc" "$HOME/.zshrc"; do
      if [ -f "$rc" ] && ! grep -q '# Soloniq Code' "$rc"; then
        printf '\nexport PATH="$HOME/.local/bin:$PATH"  # Soloniq Code\n' >> "$rc"
      fi
    done
    say "Open a new terminal (or run: export PATH=\"\$HOME/.local/bin:\$PATH\"),"
    say "then start it in your project folder:  soloniq" ;;
esac
say "Change the key later with:  soloniq --key"
say "Work from your phone (Soloniq Code app):  soloniq --remote"
say ""
say "Your code is processed only in the EU and never stored. Usage and budgets: https://app.soloniq.com"
