name: 'Install Lemonade (.deb)'
description: 'Downloads and extracts Lemonade .deb package, then verifies installation'
inputs:
  version:
    description: 'Version string for the .deb package (e.g., 0.5.0)'
    required: true
  artifact-name:
    description: 'Name of the artifact to download'
    required: false
    default: 'lemonade-deb'
  extract-path:
    description: 'Path where the .deb should be extracted'
    required: false
    default: './deb-extract'
  download-artifact:
    description: 'Whether to download the artifact (set to false if already downloaded)'
    required: false
    default: 'true'
  port:
    description: "Port to start lemond on. Use 'auto' to pick a free port (needed on shared self-hosted runners where the default port may be taken)."
    required: false
    default: '13305'

outputs:
  bin-path:
    description: 'Path to the extracted binaries directory'
    value: ${{ steps.extract.outputs.bin-path }}

runs:
  using: "composite"
  steps:
    - name: Download .deb package
      if: ${{ inputs.download-artifact == 'true' }}
      uses: actions/download-artifact@v7
      with:
        name: ${{ inputs.artifact-name }}
        path: .

    - name: Extract .deb package
      id: extract
      shell: bash
      run: |
        set -e

        VERSION="${{ inputs.version }}"
        EXTRACT_PATH="${{ inputs.extract-path }}"

        # Try to find the .deb file - it may have ~24.04 suffix from dpkg-buildpackage
        DEB_FILE=$(ls lemonade-server_${VERSION}*_amd64.deb 2>/dev/null | head -n1)

        if [ -z "$DEB_FILE" ]; then
            echo "ERROR: .deb file not found matching pattern: lemonade-server_${VERSION}*_amd64.deb"
            ls -la *.deb 2>/dev/null || echo "No .deb files found in current directory"
            exit 1
        fi

        echo "Extracting .deb package: $DEB_FILE"

        # This action extracts the .deb instead of installing it system-wide.
        # Install the package's declared runtime dependencies first, otherwise
        # newly linked shared libraries such as mbedcrypto are missing when the
        # extracted binaries are executed below.
        DEB_DEPENDS=$(dpkg-deb -f "$DEB_FILE" Depends 2>/dev/null || true)
        if [ -n "$DEB_DEPENDS" ] && command -v apt-get >/dev/null 2>&1; then
            echo "Installing .deb runtime dependencies: $DEB_DEPENDS"
            if [ "$(id -u)" -eq 0 ]; then
                apt-get update
                apt-get satisfy -y "$DEB_DEPENDS"
            elif command -v sudo >/dev/null 2>&1 && sudo -n true >/dev/null 2>&1; then
                sudo apt-get update
                sudo apt-get satisfy -y "$DEB_DEPENDS"
            else
                echo "No root/passwordless sudo available; assuming runtime dependencies are already installed."
            fi
        fi

        # Extract the .deb package
        mkdir -p "$EXTRACT_PATH"
        dpkg-deb -x "$DEB_FILE" "$EXTRACT_PATH"

        # Copy resources to user's local share (path_utils.cpp checks here)
        mkdir -p ~/.local/share/lemonade-server
        cp -r "$EXTRACT_PATH/usr/share/lemonade-server/"* ~/.local/share/lemonade-server/

        # Make llama directory writable for backend downloads
        mkdir -p "$EXTRACT_PATH/usr/share/lemonade-server/llama"
        chmod 777 "$EXTRACT_PATH/usr/share/lemonade-server/llama"

        # Make binaries executable
        chmod +x "$EXTRACT_PATH/usr/bin/lemond"
        chmod +x "$EXTRACT_PATH/usr/bin/lemonade" 2>/dev/null || true

        # Add binaries to PATH for subsequent steps
        BIN_PATH="$(pwd)/$EXTRACT_PATH/usr/bin"
        echo "$BIN_PATH" >> $GITHUB_PATH
        echo "bin-path=$BIN_PATH" >> $GITHUB_OUTPUT

        echo "Package extracted successfully to: $EXTRACT_PATH"
        echo "Binaries available at: $BIN_PATH"

    - name: Verify binaries work
      shell: bash
      run: |
        set -e

        EXTRACT_PATH="${{ inputs.extract-path }}"

        echo "Verifying binaries..."

        # Test version commands
        "$EXTRACT_PATH/usr/bin/lemond" --version
        "$EXTRACT_PATH/usr/bin/lemonade" --version

        echo "Binaries verified successfully!"

    - name: Start server and wait for ready
      shell: bash
      run: |
        # The .deb extract doesn't install a systemd service, so start manually.
        # lemond logs to stdout (SinkCout), so redirect to a file for
        # the capture-server-logs action to find.
        EXTRACT_PATH="${{ inputs.extract-path }}"
        SERVER_BIN="$EXTRACT_PATH/usr/bin/lemond"
        CACHE_DIR="./"
        LOG_FILE="$RUNNER_TEMP/lemonade-server.log"

        echo "Starting lemonade server with cache dir $CACHE_DIR (logging to $LOG_FILE)..."
        mkdir -p "$RUNNER_TEMP/xdg-runtime"
        chmod 700 "$RUNNER_TEMP/xdg-runtime"
        echo "XDG_RUNTIME_DIR=$RUNNER_TEMP/xdg-runtime" >> "$GITHUB_ENV"
        export XDG_RUNTIME_DIR="$RUNNER_TEMP/xdg-runtime"

        # With port=auto, start on a job-unique free port instead of the default
        # 13305. Non-containerized self-hosted jobs share the host network, so a
        # concurrent job may already hold 13305 — and lemond now refuses to bind
        # an in-use port. The resolved port is exported so the test harness
        # (LEMONADE_TEST_PORT) and the lemonade CLI (LEMONADE_PORT) target it.
        REQUESTED_PORT="${{ inputs.port }}"

        # Print a free TCP port (loopback). Prefer an OS-assigned ephemeral port
        # via python3; fall back to a random high port checked with ss.
        pick_free_port() {
          if command -v python3 >/dev/null 2>&1; then
            python3 -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1",0)); print(s.getsockname()[1]); s.close()' && return 0
          fi
          for _ in $(seq 1 50); do
            local p=$(( (RANDOM % 20000) + 20000 ))
            if ! ss -ltn 2>/dev/null | grep -q ":$p "; then
              echo "$p"; return 0
            fi
          done
          return 1
        }

        # Start lemond; with auto, retry on a fresh port if the chosen one got
        # taken in the race between picking and binding.
        started=0
        for start_attempt in $(seq 1 5); do
          if [ "$REQUESTED_PORT" = "auto" ]; then
            PORT=$(pick_free_port) || { echo "ERROR: could not find a free port"; exit 1; }
          else
            PORT="$REQUESTED_PORT"
          fi
          echo "Attempt $start_attempt: starting lemond on 127.0.0.1:$PORT..."
          "$SERVER_BIN" "$CACHE_DIR" --port "$PORT" > "$LOG_FILE" 2>&1 &
          SERVER_PID=$!

          for i in $(seq 1 30); do
            if curl -sf "http://127.0.0.1:$PORT/live" > /dev/null 2>&1; then
              echo "Server is running and healthy on port $PORT (PID $SERVER_PID)"
              echo "LEMONADE_TEST_PORT=$PORT" >> "$GITHUB_ENV"
              echo "LEMONADE_PORT=$PORT" >> "$GITHUB_ENV"
              started=1
              break
            fi
            if ! kill -0 $SERVER_PID 2>/dev/null; then
              echo "Server (PID $SERVER_PID) exited prematurely on port $PORT"
              echo "=== Server log ==="
              cat "$LOG_FILE" 2>/dev/null || echo "(no log file)"
              break
            fi
            echo "Waiting for server... ($i/30)"
            sleep 2
          done

          [ "$started" = "1" ] && break
          # Only an auto port is worth retrying (a fixed port won't change).
          if [ "$REQUESTED_PORT" != "auto" ]; then
            break
          fi
          echo "Start attempt $start_attempt failed; retrying on a new port..."
          kill -9 $SERVER_PID 2>/dev/null || true
          sleep 1
        done

        if [ "$started" != "1" ]; then
          echo "ERROR: server failed to start after multiple attempts"
          echo "=== Server log (last 50 lines) ==="
          tail -50 "$LOG_FILE" 2>/dev/null || echo "(no log file)"
          exit 1
        fi
