#!/bin/sh
set -e

API_BASE_URL="https://lux-turris-api.lubis-eda.com"

# 1. Detect Architecture
ARCH="$(uname -m)"
case "$ARCH" in
    x86_64) ARCH="amd64" ;;
    *) echo "Error: Unsupported architecture: $ARCH"; exit 1 ;;
esac

# 2. Detect the distribution and its version. A rolling distribution carries no VERSION_ID, so
# the platform then has three parts instead of four.
OS_TYPE="linux"
DISTRO="linux"
DISTRO_VERSION=""
if [ -f /etc/os-release ]; then
    DISTRO=$(grep ^ID= /etc/os-release | cut -d= -f2 | tr -d '"')
    DISTRO_VERSION=$(grep ^VERSION_ID= /etc/os-release | cut -d= -f2 | tr -d '"')
fi

PLATFORM="$OS_TYPE-$ARCH-$DISTRO"
if [ -n "$DISTRO_VERSION" ]; then
    PLATFORM="$PLATFORM-$DISTRO_VERSION"
fi

# 3. Handle Arguments
INSTALL_DIR="$HOME/.lubis"
PLATFORM_OVERRIDE=""

for arg in "$@"; do
  case $arg in
    -g|--global) INSTALL_DIR="/opt/lubis" ;;
    -l|--local) INSTALL_DIR="$HOME/.lubis" ;;
    --dir=*) INSTALL_DIR="${arg#*=}" ;;
    --platform=*)
      PLATFORM="${arg#*=}"
      PLATFORM_OVERRIDE="$PLATFORM"
      ;;
  esac
done

if [ -n "$INSTALL_DIR" ]; then
  case "$INSTALL_DIR" in
    /*) ;;
    *) INSTALL_DIR="$PWD/$INSTALL_DIR" ;;
  esac
fi

BINARY_DIR="$INSTALL_DIR/bin"

# 4. Refuse an install dir that lubisup already owns. A state.json there means tools are
# installed and tracked; writing over it would orphan them. lubisup manages that directory
# from here on.
if [ -e "$INSTALL_DIR/state.json" ]; then
    echo "Error: $INSTALL_DIR is already a LUBIS installation (state.json found)."
    echo "Use 'lubisup update lubisup' to update it, or pick another directory with --dir=."
    exit 1
fi

# Fail on an unwritable directory before asking anyone to log in.
if ! mkdir -p "$INSTALL_DIR" 2>/dev/null; then
    echo "Error: Cannot create $INSTALL_DIR (Permission denied)"
    exit 1
fi

RESP=""
BOOTSTRAP_DIR=""
cleanup() {
    [ -n "$RESP" ] && rm -f "$RESP"
    [ -n "$BOOTSTRAP_DIR" ] && rm -rf "$BOOTSTRAP_DIR"
    return 0
}
trap cleanup EXIT
trap 'exit 130' INT TERM

# 5. Obtain an Access Key via the device-pairing login
json_string_field() {
    echo "$1" | sed -n 's/.*"'"$2"'":"\([^"]*\)".*/\1/p'
}

json_number_field() {
    echo "$1" | sed -n 's/.*"'"$2"'":\([0-9]*\).*/\1/p'
}

RESP=$(mktemp) || { echo "Error: Could not create a temporary file."; exit 1; }

HTTP=$(curl -s -o "$RESP" -w '%{http_code}' -X POST "$API_BASE_URL/login/app/start" \
    -H 'Content-Type: application/json' \
    -d '{"app_name":"lubisup installer","reason":"Install the LUBIS toolsuite"}') || HTTP=000

case "$HTTP" in
    200|201) ;;
    *)
        echo "Error: Failed to start login (HTTP $HTTP)."
        exit 1
        ;;
esac

START_BODY=$(cat "$RESP")
DEVICE_CODE=$(json_string_field "$START_BODY" device_code)
USER_CODE=$(json_string_field "$START_BODY" user_code)
VERIFICATION_URL=$(json_string_field "$START_BODY" verification_url)
EXPIRES_IN=$(json_number_field "$START_BODY" expires_in)
INTERVAL=$(json_number_field "$START_BODY" interval)

if [ -z "$DEVICE_CODE" ] || [ -z "$USER_CODE" ] || [ -z "$VERIFICATION_URL" ]; then
    echo "Error: Invalid response from the login service."
    exit 1
fi

if [ -z "$EXPIRES_IN" ]; then
    EXPIRES_IN=600
fi
if [ -z "$INTERVAL" ] || [ "$INTERVAL" -lt 1 ] 2>/dev/null; then
    INTERVAL=5
fi

echo "To finish signing in, open $VERIFICATION_URL and confirm the code $USER_CODE"
echo "Waiting for approval..."

DEADLINE=$(($(date +%s) + EXPIRES_IN))
API_KEY=""
NET_FAILS=0
MAX_NET_FAILS=5

while [ "$(date +%s)" -lt "$DEADLINE" ]; do
    sleep "$INTERVAL"

    HTTP=$(curl -s -o "$RESP" -w '%{http_code}' -X POST "$API_BASE_URL/login/app/poll" \
        -H 'Content-Type: application/json' \
        -d "{\"device_code\":\"$DEVICE_CODE\"}") || HTTP=000

    case "$HTTP" in
        200)
            API_KEY=$(json_string_field "$(cat "$RESP")" api_key)
            break
            ;;
        202)
            NET_FAILS=0
            ;;
        403)
            echo "Login was denied."
            exit 1
            ;;
        410|404)
            echo "Login expired or was not found; re-run the installer."
            exit 1
            ;;
        000)
            NET_FAILS=$((NET_FAILS + 1))
            echo "Network problem reaching the login service; retrying..."
            if [ "$NET_FAILS" -ge "$MAX_NET_FAILS" ]; then
                echo "Error: Could not reach the login service after $MAX_NET_FAILS attempts."
                exit 1
            fi
            ;;
        *)
            echo "Unexpected response from login (HTTP $HTTP)."
            exit 1
            ;;
    esac
done

if [ -z "$API_KEY" ]; then
    echo "Login timed out."
    exit 1
fi

rm -f "$RESP"
RESP=""

# 6. Save Access Key
# The key is tied to the user, not the install location, so it always goes
# under $HOME regardless of --global/--dir. Must match internal/config/keys.go.
# It is written before the handoff below, because the lubisup binary reads it
# to fetch the tool catalog.
KEY_DIR="$HOME/.lubis/keys"
KEY_FILE="$KEY_DIR/lubisup-lux-turris.key"
mkdir -p "$KEY_DIR"
chmod 700 "$KEY_DIR"
printf '%s' "$API_KEY" > "$KEY_FILE"
chmod 600 "$KEY_FILE"

# 7. Fetch a throwaway lubisup binary
BOOTSTRAP_DIR=$(mktemp -d) || { echo "Error: Could not create a temporary directory."; exit 1; }
BOOTSTRAP_ARCHIVE="$BOOTSTRAP_DIR/lubisup.tar.gz"
BOOTSTRAP_BIN="$BOOTSTRAP_DIR/lubisup"
DOWNLOAD_URL="$API_BASE_URL/tools/installer/download?platform=$PLATFORM"

echo "Downloading lubisup for $PLATFORM..."
if ! curl -f -L -H "Authorization: Bearer $API_KEY" "$DOWNLOAD_URL" -o "$BOOTSTRAP_ARCHIVE"; then
    echo "Error: Download failed from $API_BASE_URL"
    exit 1
fi

echo "Extracting archive..."
if ! tar -xzf "$BOOTSTRAP_ARCHIVE" -C "$BOOTSTRAP_DIR"; then
    echo "Error: Failed to extract archive"
    exit 1
fi
rm -f "$BOOTSTRAP_ARCHIVE"

if [ ! -f "$BOOTSTRAP_BIN" ]; then
    echo "Error: The archive holds no lubisup binary."
    exit 1
fi
chmod +x "$BOOTSTRAP_BIN"

# 8. Hand over to lubisup, which installs itself the way it installs every tool.
# This writes installations/<tool id>/<platform>/<version>, the bin/ symlink and state.json.
echo "Installing lubisup into $INSTALL_DIR..."
# --initial-installation: there is no state file yet, and step 9 sets PATH up,
# so lubisup must not warn about either.
if [ -n "$PLATFORM_OVERRIDE" ]; then
    "$BOOTSTRAP_BIN" --dir "$INSTALL_DIR" --initial-installation install lubisup --platform "$PLATFORM_OVERRIDE"
else
    "$BOOTSTRAP_BIN" --dir "$INSTALL_DIR" --initial-installation install lubisup
fi

rm -rf "$BOOTSTRAP_DIR"
BOOTSTRAP_DIR=""

# 9. Update PATH
if [ -z "$HOME" ]; then
  IN_HOME=false
else
  case "$INSTALL_DIR" in
    "$HOME"/*) IN_HOME=true ;;
    *) IN_HOME=false ;;
  esac
fi

if [ "$IN_HOME" = false ]; then
  if [ -d "/etc/profile.d" ] && [ -w "/etc/profile.d" ]; then
      echo "export PATH=\"\$PATH:$BINARY_DIR\"" > "/etc/profile.d/lubis.sh"
      echo "alias lubup=lubisup" >> "/etc/profile.d/lubis.sh"
      echo "Added $BINARY_DIR to /etc/profile.d/lubis.sh"
      echo "Restart your terminal to reload PATH."
  else
      echo "Warning: Could not write /etc/profile.d. Add $BINARY_DIR to PATH manually."
  fi
else
  # Home install: update the user's shell rc.
  PROFILE_FILE="$HOME/.profile"
  if [ -f "$HOME/.zshrc" ]; then PROFILE_FILE="$HOME/.zshrc";
  elif [ -f "$HOME/.bashrc" ]; then PROFILE_FILE="$HOME/.bashrc"; fi

  if ! grep -q "$BINARY_DIR" "$PROFILE_FILE" 2>/dev/null; then
    echo "# LUBIS installer ---------------------------" >> "$PROFILE_FILE"
    echo "export PATH=\"$BINARY_DIR:\$PATH\"" >> "$PROFILE_FILE"
    echo "alias lubup=lubisup" >> "$PROFILE_FILE"
    echo "# LUBIS installer ---------------------------" >> "$PROFILE_FILE"
    echo "Added $BINARY_DIR to $PROFILE_FILE"
    echo "Run 'source $PROFILE_FILE' to use it."
  fi
fi

echo "Installation complete."
