#!/usr/bin/env sh
set -eu
MODE="boat"
API_URL="https://boat.dev"
CHANNEL="prod"
INSTALL_DIR="$HOME/.ascii/bin"

case "$(uname -s)" in
  Linux) OS="linux" ;;
  Darwin) OS="darwin" ;;
  *) echo "Unsupported OS: $(uname -s)" >&2; exit 1 ;;
esac

case "$(uname -m)" in
  x86_64|amd64) ARCH="x64" ;;
  arm64|aarch64) ARCH="arm64" ;;
  *) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;;
esac

URL="$API_URL/api/boat/cli/download?platform=$OS-$ARCH&channel=$CHANNEL"
mkdir -p "$INSTALL_DIR"
TMP="$(mktemp)"
curl -fsSL "$URL" -o "$TMP"
chmod +x "$TMP"
mv "$TMP" "$INSTALL_DIR/$MODE"

CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/ascii/$MODE"
mkdir -p "$CONFIG_DIR"
cat > "$CONFIG_DIR/config.json" <<EOF
{
  "api_url": "$API_URL",
  "channel": "$CHANNEL"
}
EOF

CURRENT_ENV_NAME="BOAT_CURRENT_ID"
if [ "$MODE" = "boat-dev" ]; then CURRENT_ENV_NAME="BOAT_DEV_CURRENT_ID"; fi
if [ "$MODE" = "boat-staging" ]; then CURRENT_ENV_NAME="BOAT_STAGING_CURRENT_ID"; fi
CURRENT_CONVO_NAME="BOAT_CURRENT_CONVO"
if [ "$MODE" = "boat-dev" ]; then CURRENT_CONVO_NAME="BOAT_DEV_CURRENT_CONVO"; fi
if [ "$MODE" = "boat-staging" ]; then CURRENT_CONVO_NAME="BOAT_STAGING_CURRENT_CONVO"; fi
SHELL_NAME="$(basename "$SHELL" 2>/dev/null || echo sh)"
PROFILE="$HOME/.profile"
if [ "$SHELL_NAME" = "zsh" ]; then PROFILE="$HOME/.zshrc"; fi
if [ "$SHELL_NAME" = "bash" ]; then PROFILE="$HOME/.bashrc"; fi

# The rc file above is read by interactive shells only, so "zsh -c", "ssh host boat ...",
# make and CI never see the function. zsh reads .zshenv on every invocation; bash reads
# the first of these that exists on login and nothing at all when non-interactive.
ENVFILE=""
if [ "$SHELL_NAME" = "zsh" ]; then
  ENVFILE="$HOME/.zshenv"
elif [ "$SHELL_NAME" = "bash" ]; then
  if [ -f "$HOME/.bash_profile" ]; then ENVFILE="$HOME/.bash_profile"
  elif [ -f "$HOME/.bash_login" ]; then ENVFILE="$HOME/.bash_login"
  else ENVFILE="$HOME/.profile"; fi
fi

strip_boat_block() {
  [ -f "$1" ] || return 0
  _tmp="$(mktemp)"
  # sed matched substrings, so removing boat also removed boat-dev and boat-staging.
  awk -v start="# ASCII BOAT SHELL INTEGRATION START $MODE" -v end="# ASCII BOAT SHELL INTEGRATION END $MODE" '
    $0 == start { skip = 1; while (n > 0 && buf[n] ~ /^[[:space:]]*$/) n--; next }
    $0 == end { skip = 0; eat = 1; next }
    skip { next }
    eat && $0 ~ /^[[:space:]]*$/ { next }
    { eat = 0; buf[++n] = $0 }
    END { while (n > 0 && buf[n] ~ /^[[:space:]]*$/) n--; for (i = 1; i <= n; i++) print buf[i] }
  ' "$1" > "$_tmp"
  cat "$_tmp" > "$1"
  rm -f "$_tmp"
}

emit_path_block() {
  cat <<EOF
# ASCII BOAT SHELL INTEGRATION START $MODE
case ":\$PATH:" in
  *":$INSTALL_DIR:"*) ;;
  *) PATH="$INSTALL_DIR:\$PATH" ;;
esac
export PATH
# ASCII BOAT SHELL INTEGRATION END $MODE
EOF
}

# Prepended, not appended: a stock Ubuntu .bashrc returns on line 9 when the shell is
# not interactive, and ssh runs "bash -c cmd" through that same file. Anything after
# the return never runs for "ssh host boat list".
prepend_path_block() {
  _tmp="$(mktemp)"
  { emit_path_block; echo ""; [ -f "$1" ] && cat "$1"; } > "$_tmp"
  cat "$_tmp" > "$1"
  rm -f "$_tmp"
}

append_path_block() {
  { echo ""; emit_path_block; } >> "$1"
}

if [ "$SHELL_NAME" = "bash" ] || [ "$SHELL_NAME" = "zsh" ]; then
strip_boat_block "$PROFILE"
prepend_path_block "$PROFILE"
if [ "$ENVFILE" != "$PROFILE" ]; then
  strip_boat_block "$ENVFILE"
  append_path_block "$ENVFILE"
fi
cat >> "$PROFILE" <<EOF

# ASCII BOAT SHELL INTEGRATION START $MODE
$MODE() {
EOF
cat >> "$PROFILE" <<'EOF'
  current_file=$(mktemp)
  convo_file=$(mktemp)
  old_current_file=${BOAT_CURRENT_ID_FILE-}
  old_convo_file=${BOAT_CURRENT_CONVO_FILE-}
  export BOAT_CURRENT_ID_FILE="$current_file"
  export BOAT_CURRENT_CONVO_FILE="$convo_file"
EOF
cat >> "$PROFILE" <<EOF
  command "$INSTALL_DIR/$MODE" "\$@"
EOF
cat >> "$PROFILE" <<'EOF'
  boat_status=$?
  if [ "$boat_status" -eq 0 ]; then
    case "${1:-}" in
      new|start|fork)
        if [ -s "$current_file" ]; then
          current_id=$(tr -d '[:space:]' < "$current_file")
EOF
cat >> "$PROFILE" <<EOF
          if [ -n "\$current_id" ]; then export $CURRENT_ENV_NAME="\$current_id"; fi
EOF
cat >> "$PROFILE" <<'EOF'
        fi
        ;;
    esac
    case "${1:-}" in
      prompt)
        if [ -s "$convo_file" ]; then
          IFS= read -r current_convo < "$convo_file" || current_convo=""
EOF
cat >> "$PROFILE" <<EOF
          if [ -n "\$current_convo" ]; then export $CURRENT_CONVO_NAME="\$current_convo"; fi
EOF
cat >> "$PROFILE" <<'EOF'
        fi
        ;;
    esac
  fi
  if [ -n "$old_current_file" ]; then export BOAT_CURRENT_ID_FILE="$old_current_file"; else unset BOAT_CURRENT_ID_FILE; fi
  if [ -n "$old_convo_file" ]; then export BOAT_CURRENT_CONVO_FILE="$old_convo_file"; else unset BOAT_CURRENT_CONVO_FILE; fi
  rm -f "$current_file" "$convo_file"
  return "$boat_status"
}
EOF
cat >> "$PROFILE" <<EOF
# ASCII BOAT SHELL INTEGRATION END $MODE
EOF
if [ "$ENVFILE" != "$PROFILE" ]; then
  echo "Updated $MODE shell integration in $PROFILE and $ENVFILE."
else
  echo "Updated $MODE shell integration in $PROFILE."
fi
PROFILE_UPDATED=1
else
echo "Shell integration for 'current' is available for bash and zsh. Use explicit boat IDs in $SHELL_NAME."
PROFILE_UPDATED=0
fi

# cron and systemd read no shell startup file, so no PATH line can reach them. A symlink
# in a directory they already have on PATH is the only fix. Attempted only where it costs
# nothing: an existing foreign file is never touched, and sudo is never invoked here.
SYSTEM_DIR=/usr/local/bin
SYSTEM_LINK=""
if [ -d "$SYSTEM_DIR" ]; then
  SYSTEM_TARGET="$SYSTEM_DIR/$MODE"
  if [ ! -e "$SYSTEM_TARGET" ] || [ "$(readlink "$SYSTEM_TARGET" 2>/dev/null)" = "$INSTALL_DIR/$MODE" ]; then
    if [ -w "$SYSTEM_DIR" ] && ln -sfn "$INSTALL_DIR/$MODE" "$SYSTEM_TARGET" 2>/dev/null; then
      SYSTEM_LINK=linked
    else
      SYSTEM_LINK=needs_sudo
    fi
  fi
fi

echo "Installed $MODE to $INSTALL_DIR/$MODE"
if [ "$SYSTEM_LINK" = "linked" ]; then
  echo "Linked $SYSTEM_TARGET so cron and systemd find it too."
fi
case ":$PATH:" in
  *":$INSTALL_DIR:"*)
    echo "$INSTALL_DIR is already on PATH."
    ;;
  *)
    echo ""
    if [ "$PROFILE_UPDATED" = "1" ]; then
      echo "Added $INSTALL_DIR to PATH in $PROFILE. This terminal needs one line:"
    else
      echo "$INSTALL_DIR is not on PATH. To use $MODE, run:"
    fi
    echo "  export PATH=\"$INSTALL_DIR:\$PATH\""
    if [ "$PROFILE_UPDATED" = "1" ]; then
      echo "  # or '. $PROFILE', which also loads the $MODE shell function"
    else
      echo "  # add that line to your shell startup file to make it permanent"
    fi
    ;;
esac
echo ""
onboard_status=0
if [ -r /dev/tty ]; then
  "$INSTALL_DIR/$MODE" onboard < /dev/tty || onboard_status=$?
else
  "$INSTALL_DIR/$MODE" onboard || onboard_status=$?
fi

# After onboarding, not before: the interactive flow scrolls over anything printed
# ahead of it, which is the bug this branch exists to fix.
if [ "$SYSTEM_LINK" = "needs_sudo" ]; then
  echo ""
  echo "Optional. cron and systemd read no shell startup file, so if you run $MODE from"
  echo "one of those, either set PATH where you declare the job:"
  echo "  PATH=$INSTALL_DIR:/usr/bin:/bin          # crontab"
  echo "  Environment=PATH=$INSTALL_DIR:/usr/bin:/bin   # systemd unit"
  echo "or link it once, system-wide:"
  echo "  sudo ln -sfn \"$INSTALL_DIR/$MODE\" \"$SYSTEM_DIR/$MODE\""
fi
exit "$onboard_status"
