#!/usr/bin/env sh
# Medalion Platform installer — served at https://get.medalion.tech
#
#   curl -fsSL https://get.medalion.tech | sh                      # asks for the key
#   curl -fsSL https://get.medalion.tech | sh -s -- --dir /opt/medalion
#   MEDALION_LICENSE=XXXXX-… curl -fsSL https://get.medalion.tech | sh     # unattended
#
# Installs uv (brings its own Python — no system Python, no Xcode), then runs
# `medalion init` from the licensed package index: it verifies the key, checks this
# machine (disk, memory, ffmpeg, llama.cpp, service manager), writes medalion.yaml +
# pyproject.toml for exactly the modules you bought and syncs them. Re-running the
# installer on an existing directory updates it instead of overwriting anything.
set -eu

DIR="${MEDALION_HOME:-$HOME/medalion}"
INDEX="${MEDALION_INDEX_URL:-https://pypi.medalion.tech/simple}"
VERSION="${MEDALION_VERSION:-}"
PROFILE="native"
SERVICE=1
PULL=1
FORCE=0
OPEN=1

usage() {
  cat <<'USAGE'
Usage: install.sh [options]
  --license KEY     license key (or set MEDALION_LICENSE; asked for if absent)
  --dir PATH        where to install                       [~/medalion]
  --version X.Y.Z   pin the platform version               [latest]
  --index URL       package index                          [pypi.medalion.tech]
  --profile native|compose
  --no-pull         download model weights at first start, not now
  --no-service      do not install the autostart service
  --no-open         do not open the Studio in a browser when it is ready
  --force           install even if the preflight checks fail
USAGE
}

while [ $# -gt 0 ]; do
  case "$1" in
    --license|-l) MEDALION_LICENSE="$2"; shift 2 ;;
    --dir|-d) DIR="$2"; shift 2 ;;
    --version) VERSION="$2"; shift 2 ;;
    --index) INDEX="$2"; shift 2 ;;
    --profile) PROFILE="$2"; shift 2 ;;
    --no-pull) PULL=0; shift ;;
    --no-service) SERVICE=0; shift ;;
    --no-open) OPEN=0; shift ;;
    --force) FORCE=1; shift ;;
    -h|--help) usage; exit 0 ;;
    *) echo "unknown option: $1" >&2; usage >&2; exit 2 ;;
  esac
done

die() { echo "error: $*" >&2; exit 1; }

# `curl | sh` gives the script the download as stdin, so prompts must read the terminal.
if [ -z "${MEDALION_LICENSE:-}" ]; then
  if [ -r /dev/tty ]; then
    printf "License key (XXXXX-XXXXX-XXXXX-XXXXX-XXXXX): "
    read -r MEDALION_LICENSE < /dev/tty
  else
    die "no license key: pass --license KEY or set MEDALION_LICENSE (no terminal to ask on)"
  fi
fi
case "$MEDALION_LICENSE" in
  [A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]-*) ;;
  *) die "that does not look like a license key (XXXXX-XXXXX-XXXXX-XXXXX-XXXXX)" ;;
esac

if ! command -v uv >/dev/null 2>&1; then
  echo "installing uv …"
  curl -LsSf https://astral.sh/uv/install.sh | sh >/dev/null
fi
PATH="$HOME/.local/bin:/opt/homebrew/bin:/usr/local/bin:$PATH"
export PATH
command -v uv >/dev/null 2>&1 || die "uv is not on PATH after installing it — open a new shell and re-run"

# The key travels in the environment, never in argv (ps/history are readable by other users).
MEDALION_LICENSE_KEY="$MEDALION_LICENSE"
UV_INDEX_MEDALION_USERNAME="license"
UV_INDEX_MEDALION_PASSWORD="$MEDALION_LICENSE"
MEDALION_INDEX_URL="$INDEX"
export MEDALION_LICENSE_KEY UV_INDEX_MEDALION_USERNAME UV_INDEX_MEDALION_PASSWORD MEDALION_INDEX_URL
unset MEDALION_LICENSE

# Check the key against the index first: a rejected key otherwise surfaces as uv's
# "medalion-core was not found in the package registry", which sends people hunting the wrong bug.
code=$(curl -s -o /dev/null -w '%{http_code}' -u "license:$MEDALION_LICENSE_KEY" "$INDEX/" 2>/dev/null || true)
case "${code:-000}" in
  200) ;;
  401|403) die "the license key was rejected by $INDEX (expired, suspended, or mistyped)" ;;
  000) die "cannot reach $INDEX — check the network, a proxy, or --index" ;;
  *) echo "warning: $INDEX answered HTTP $code for the license check; continuing" >&2 ;;
esac

mkdir -p "$DIR"
SITE="$DIR/.venv/bin/medalion"
CORE="medalion-core"
[ -n "$VERSION" ] && CORE="medalion-core==$VERSION"

if [ -f "$DIR/medalion.yaml" ] && [ -x "$SITE" ]; then
  # Existing install: never re-render medalion.yaml, just bring it in line with the license.
  echo "found an install in $DIR — updating it"
  if [ -n "$VERSION" ]; then
    "$SITE" update --dir "$DIR" --profile "$PROFILE" --version "$VERSION"
  else
    "$SITE" update --dir "$DIR" --profile "$PROFILE"
  fi
else
  # Bootstrap CLI runs from uv's cache and leaves nothing behind; the site gets its own venv.
  set -- init --dir "$DIR" --profile "$PROFILE"
  [ -n "$VERSION" ] && set -- "$@" --version "$VERSION"
  [ "$PULL" = 1 ] && set -- "$@" --pull
  [ "$FORCE" = 1 ] && set -- "$@" --force
  # medalion-core is public on PyPI, so the bootstrap needs no credentials; the licensed modules
  # are pinned to $INDEX in the pyproject that `init` renders.
  # --python 3.12: what the platform supports. Without it uv picks the newest interpreter it can
  # find, then quietly resolves an older medalion-core that fits (or fails with "not found").
  uvx --python 3.12 --from "$CORE" medalion "$@"
fi

[ "$PROFILE" = "native" ] || exit 0
[ -x "$SITE" ] || die "$SITE is missing — the sync step did not finish; see the output above"

# One `medalion` on PATH afterwards: the site's own, with every licensed module.
if [ -d "$HOME/.local/bin" ] && [ ! -e "$HOME/.local/bin/medalion" ]; then
  ln -s "$SITE" "$HOME/.local/bin/medalion" 2>/dev/null || true
fi

if [ "$SERVICE" = 1 ]; then
  if ! "$SITE" service install --dir "$DIR" --config "$DIR/medalion.yaml"; then
    echo "the service was not installed — start the platform yourself with:" >&2
    echo "  $SITE serve --config $DIR/medalion.yaml" >&2
    exit 1
  fi
  echo "waiting for the models to load (first start also downloads weights) …"
  "$SITE" status --config "$DIR/medalion.yaml" --wait 900 || {
    echo "not everything is ready yet — check: $SITE status --config $DIR/medalion.yaml" >&2
    exit 1
  }
fi

API="$("$SITE" status --config "$DIR/medalion.yaml" 2>/dev/null | awk '/^api /{print $2}')"
[ -n "$API" ] || API="http://127.0.0.1:8000"

# The Studio ships as a wheel and is served by the API itself — same port, no Node, no extra service.
STUDIO=""
if [ "$SERVICE" = 1 ] && "$SITE" status --config "$DIR/medalion.yaml" 2>/dev/null | grep -q '^studio '; then
  STUDIO="$API/"
  if [ "$OPEN" = 1 ]; then
    if command -v open >/dev/null 2>&1; then open "$STUDIO" >/dev/null 2>&1 || true
    elif command -v xdg-open >/dev/null 2>&1; then xdg-open "$STUDIO" >/dev/null 2>&1 || true
    fi
  fi
fi

cat <<EOM

Medalion is installed in $DIR
  Studio   ${STUDIO:-not installed}
  API      $API   (docs at $API/docs)
  status   medalion status --config $DIR/medalion.yaml
  config   $DIR/medalion.yaml   (models, devices, ports — yours to edit)
  update   medalion update --dir $DIR       after buying a module
  remove   medalion uninstall --dir $DIR
EOM
