#!/bin/sh
set -eu

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

RESP=""
BOOTSTRAP_DIR=""
cleanup() {
    [ -n "$RESP" ] && rm -f "$RESP"
    [ -n "$BOOTSTRAP_DIR" ] && rm -rf "$BOOTSTRAP_DIR"
    return 0
}

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

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

# The body lives in main, called on the last line. A download cut off
# mid-script then fails to parse and runs nothing.
main() {
    # The key file and the default install dir live under $HOME.
    if [ -z "${HOME:-}" ]; then
        echo "Error: HOME is not set."
        exit 1
    fi

    # 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

    trap cleanup EXIT
    trap 'exit 130' INT TERM

    # 5. Obtain an Access Key via the device-pairing login
    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=$(printf '{"device_code":"%s"}' "$DEVICE_CODE" | \
            curl -s -o "$RESP" -w '%{http_code}' -X POST "$API_BASE_URL/login/app/poll" \
            -H 'Content-Type: application/json' \
            -d @-) || 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 ! printf 'Authorization: Bearer %s\n' "$API_KEY" | \
        curl -f -L -H @- "$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" lubisup; then
        echo "Error: Failed to extract archive"
        exit 1
    fi
    rm -f "$BOOTSTRAP_ARCHIVE"

    # A link could point chmod and the exec below at any file on the machine.
    if [ -L "$BOOTSTRAP_BIN" ] || [ ! -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
    case "$INSTALL_DIR" in
      "$HOME"/*) IN_HOME=true ;;
      *) IN_HOME=false ;;
    esac

    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."
}

main "$@"
