#!/usr/bin/env bash
# claude-multiacc installer — macOS + Linux, idempotent, fully reversible.
# Installs an addon that PATH-shadows `claude`; NEVER touches the Claude Code app,
# its install dir, or its update machinery.
#
#   ./install.sh [--server user@host]     install or update (data untouched)
#   ./install.sh --uninstall              remove addon (keeps ~/.claude-accounts)
#   ./install.sh --uninstall --purge-data remove addon + all account data
set -u

REPO_DIR="$(cd "$(dirname "$0")" && pwd -P)"
# shellcheck source=lib/common.sh
. "$REPO_DIR/lib/common.sh"

MARK_BEGIN="# >>> claude-multiacc >>>"
MARK_END="# <<< claude-multiacc <<<"
CRON_TAG="# claude-multiacc"
PLIST_LIMITS="$HOME/Library/LaunchAgents/com.claude-multiacc.limits.plist"
PLIST_HEALTH="$HOME/Library/LaunchAgents/com.claude-multiacc.health.plist"
PLIST_UPDATE="$HOME/Library/LaunchAgents/com.claude-multiacc.update.plist"
PROFILED="/etc/profile.d/claude-multiacc.sh"

UNINSTALL=0
PURGE=0
SERVER_OVERRIDE=""
NO_SCHEDULE=0
while [ $# -gt 0 ]; do
  case "$1" in
    --uninstall) UNINSTALL=1; shift ;;
    --purge-data) PURGE=1; shift ;;
    --server) SERVER_OVERRIDE="${2:?--server requires a value}"; shift 2 ;;
    --no-schedule) NO_SCHEDULE=1; shift ;;
    *) echo "unknown flag: $1" >&2; exit 1 ;;
  esac
done

strip_block() { # remove our marked block from a file (portable, no sed -i)
  local f="$1"
  [ -f "$f" ] || return 0
  # Unmatched begin marker (end line hand-deleted): stripping would eat the rest
  # of the rc file. Leave it alone and say so.
  if grep -qF "$MARK_BEGIN" "$f" && ! grep -qF "$MARK_END" "$f"; then
    echo "  WARNING: $f has an unterminated claude-multiacc block — fix it by hand; not touching this file" >&2
    return 1
  fi
  awk -v b="$MARK_BEGIN" -v e="$MARK_END" '
    $0 == b { skip = 1; next }
    $0 == e { skip = 0; next }
    !skip { print }
  ' "$f" > "$f.claude-multiacc.tmp" && mv "$f.claude-multiacc.tmp" "$f"
}

path_block_body() {
  # Move (not just add) the shim dir to the front: later rc lines prepend
  # ~/.local/bin, so a plain add-once guard would leave the real binary first.
  printf 'PATH="$(printf %%s ":$PATH:" | sed '\''s|:%s/bin:|:|g; s|^:||; s|:$||'\'')"\n' "$REPO_DIR"
  printf 'export PATH="%s/bin:$PATH"\n' "$REPO_DIR"
}

append_block() { # strip then append our PATH block to a file
  local f="$1"
  strip_block "$f" || return 1   # never create a second block next to a broken one
  {
    printf '%s\n' "$MARK_BEGIN"
    path_block_body
    printf '%s\n' "$MARK_END"
  } >> "$f"
}

mac_schedule_install() {
  mkdir -p "$HOME/Library/LaunchAgents"
  cat > "$PLIST_LIMITS" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
  <key>Label</key><string>com.claude-multiacc.limits</string>
  <key>ProgramArguments</key><array>
    <string>$REPO_DIR/bin/claude-accounts</string>
    <string>limits</string>
    <string>--quiet</string>
  </array>
  <key>StartInterval</key><integer>60</integer>
  <key>RunAtLoad</key><true/>
  <key>StandardOutPath</key><string>/dev/null</string>
  <key>StandardErrorPath</key><string>/dev/null</string>
</dict></plist>
EOF
  cat > "$PLIST_HEALTH" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
  <key>Label</key><string>com.claude-multiacc.health</string>
  <key>ProgramArguments</key><array>
    <string>$REPO_DIR/bin/claude-accounts</string>
    <string>health</string>
  </array>
  <key>StartCalendarInterval</key><dict>
    <key>Weekday</key><integer>1</integer>
    <key>Hour</key><integer>9</integer>
    <key>Minute</key><integer>17</integer>
  </dict>
  <key>StandardOutPath</key><string>/dev/null</string>
  <key>StandardErrorPath</key><string>/dev/null</string>
</dict></plist>
EOF
  # Weekly auto-update (Sunday 04:07). No-op unless this is an npm or git install.
  cat > "$PLIST_UPDATE" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
  <key>Label</key><string>com.claude-multiacc.update</string>
  <key>ProgramArguments</key><array>
    <string>$REPO_DIR/bin/claude-accounts</string>
    <string>self-update</string>
    <string>--quiet</string>
  </array>
  <key>StartCalendarInterval</key><dict>
    <key>Weekday</key><integer>0</integer>
    <key>Hour</key><integer>4</integer>
    <key>Minute</key><integer>7</integer>
  </dict>
  <key>StandardOutPath</key><string>/dev/null</string>
  <key>StandardErrorPath</key><string>/dev/null</string>
</dict></plist>
EOF
  launchctl unload "$PLIST_LIMITS" 2>/dev/null || true
  launchctl unload "$PLIST_HEALTH" 2>/dev/null || true
  launchctl unload "$PLIST_UPDATE" 2>/dev/null || true
  launchctl load -w "$PLIST_LIMITS" 2>/dev/null || echo "  (launchctl load limits agent failed — limits refresh will rely on the shim's opportunistic kick)"
  launchctl load -w "$PLIST_HEALTH" 2>/dev/null || true
  [ "${CLAUDE_MULTIACC_AUTOUPDATE:-1}" = "1" ] && launchctl load -w "$PLIST_UPDATE" 2>/dev/null || true
  echo "  launchd: limits refresh every 60s + weekly health check + weekly auto-update"
}

mac_schedule_remove() {
  launchctl unload "$PLIST_LIMITS" 2>/dev/null || true
  launchctl unload "$PLIST_HEALTH" 2>/dev/null || true
  launchctl unload "$PLIST_UPDATE" 2>/dev/null || true
  rm -f "$PLIST_LIMITS" "$PLIST_HEALTH" "$PLIST_UPDATE"
}

linux_schedule_install() {
  local tmp
  tmp="$(mktemp)"
  { crontab -l 2>/dev/null | grep -v "$CRON_TAG" || true; } > "$tmp"
  {
    echo "* * * * * $REPO_DIR/bin/claude-accounts limits --quiet >/dev/null 2>&1 $CRON_TAG"
    echo "17 9 * * 1 $REPO_DIR/bin/claude-accounts health >/dev/null 2>&1 $CRON_TAG"
    [ "${CLAUDE_MULTIACC_AUTOUPDATE:-1}" = "1" ] && \
      echo "7 4 * * 0 $REPO_DIR/bin/claude-accounts self-update --quiet >/dev/null 2>&1 $CRON_TAG"
  } >> "$tmp"
  crontab "$tmp"
  rm -f "$tmp"
  echo "  cron: limits refresh every 60s + weekly health check + weekly auto-update"
}

linux_schedule_remove() {
  local tmp
  tmp="$(mktemp)"
  { crontab -l 2>/dev/null | grep -v "$CRON_TAG" || true; } > "$tmp"
  crontab "$tmp"
  rm -f "$tmp"
}

do_uninstall() {
  echo "claude-multiacc: uninstalling (restoring stock behavior)"
  strip_block "$HOME/.zshenv"
  strip_block "$HOME/.zprofile"
  strip_block "$HOME/.zshrc"
  strip_block "$HOME/.bashrc"
  strip_block "$HOME/.bash_profile"
  strip_block "$HOME/.profile"
  if [ "$(machine_kind)" = "mac" ]; then
    mac_schedule_remove
  else
    linux_schedule_remove
    [ -f "$PROFILED" ] && rm -f "$PROFILED"
    if [ -L /usr/local/bin/claude ] && [ "$(canon_path /usr/local/bin/claude)" = "$(canon_path "$REPO_DIR/bin/claude")" ]; then
      rm -f /usr/local/bin/claude
      echo "  removed /usr/local/bin/claude shim symlink"
    fi
  fi
  if [ "$PURGE" = "1" ]; then
    case "$ACC_ROOT" in
      */.claude-accounts) rm -rf "$ACC_ROOT"; echo "  purged $ACC_ROOT" ;;
      *) echo "  refusing to purge unusual ACC_ROOT: $ACC_ROOT" >&2 ;;
    esac
  else
    echo "  account data kept at $ACC_ROOT (use --purge-data to remove)"
  fi
  echo "uninstall complete — stock claude behavior restored"
}

do_install() {
  local kind
  kind="$(machine_kind)"
  echo "claude-multiacc: installing (mode: $kind, repo: $REPO_DIR)"

  [ -x "$REPO_DIR/bin/claude" ] || chmod +x "$REPO_DIR/bin/claude" 2>/dev/null || true
  [ -x "$REPO_DIR/bin/claude-accounts" ] || chmod +x "$REPO_DIR/bin/claude-accounts" 2>/dev/null || true

  local real
  if real="$(find_real_claude "$REPO_DIR/bin/claude")"; then
    echo "  real claude binary: $real ($("$real" --version 2>/dev/null | head -1 || echo 'version unknown'))"
  else
    echo "  WARNING: no real claude binary found yet — install Claude Code first (https://claude.com/claude-code)" >&2
  fi

  # Keychain-mode detection: per-dir /login isolation needs file-based credentials.
  if [ "$kind" = "mac" ] && [ ! -f "$HOME/.claude/.credentials.json" ] \
    && security find-generic-password -s "Claude Code-credentials" >/dev/null 2>&1; then
    echo "  WARNING: this Mac stores Claude Code credentials in the Keychain, not files." >&2
    echo "  Per-directory logins may not isolate; use token-based accounts (claude-accounts mint/import --token-file)." >&2
  fi

  manifest_init "${SERVER_OVERRIDE:-$DEFAULT_SERVER}"
  if [ -n "$SERVER_OVERRIDE" ]; then
    "$PYBIN" - "$MANIFEST" "$SERVER_OVERRIDE" <<'PYEOF'
import json, os, sys
doc = json.load(open(sys.argv[1]))
doc['server'] = sys.argv[2]
with open(sys.argv[1] + '.tmp', 'w') as f:
    json.dump(doc, f, indent=2)
    f.write('\n')
os.replace(sys.argv[1] + '.tmp', sys.argv[1])
PYEOF
  fi
  echo "  account pool: $ACC_ROOT (manifest ready)"

  if [ "$kind" = "mac" ]; then
    # .zshenv covers non-interactive zsh; the .zshrc block must be LAST so it wins
    # over ~/.local/bin re-prepends done earlier in .zshrc/.zprofile.
    # zsh reads: .zshenv always; .zprofile for login; .zshrc for interactive.
    # The block must end each file that later re-prepends ~/.local/bin.
    touch "$HOME/.zshenv"
    append_block "$HOME/.zshenv"
    touch "$HOME/.zprofile"
    append_block "$HOME/.zprofile"
    touch "$HOME/.zshrc"
    append_block "$HOME/.zshrc"
    [ -f "$HOME/.bash_profile" ] && append_block "$HOME/.bash_profile"
    [ -f "$HOME/.bashrc" ] && append_block "$HOME/.bashrc"
    echo "  PATH block: end of ~/.zshenv, ~/.zprofile, ~/.zshrc (+ bash rc files if present)"
    [ "$NO_SCHEDULE" = "1" ] || mac_schedule_install
  else
    touch "$HOME/.bashrc"
    append_block "$HOME/.bashrc"
    if [ -w /etc/profile.d ] 2>/dev/null || [ "$(id -u)" = "0" ]; then
      {
        printf '%s\n' "$MARK_BEGIN"
        path_block_body
        printf '%s\n' "$MARK_END"
      } > "$PROFILED"
      echo "  PATH block: ~/.bashrc + $PROFILED"
    fi
    if [ "$(id -u)" = "0" ]; then
      if [ -e /usr/local/bin/claude ] && [ ! -L /usr/local/bin/claude ]; then
        echo "  WARNING: /usr/local/bin/claude exists and is a real file — NOT overwriting." >&2
      else
        ln -sfn "$REPO_DIR/bin/claude" /usr/local/bin/claude
        echo "  shim: /usr/local/bin/claude -> $REPO_DIR/bin/claude (systemd-PATH compatible)"
      fi
    fi
    [ "$NO_SCHEDULE" = "1" ] || linux_schedule_install
  fi

  echo
  echo "install complete. Open a new shell (or 'export PATH=\"$REPO_DIR/bin:\$PATH\"'), then:"
  echo "  claude-accounts list      # see the pool"
  echo "  claude-accounts status    # auth + limits detail"
}

if [ "$UNINSTALL" = "1" ]; then
  do_uninstall
else
  do_install
fi
