#!/usr/bin/env bash
set -euo pipefail

usage() {
  cat <<'EOF'
Install SPL local daemon on macOS.

Options:
  --repo-root PATH        Repository root. Defaults to two levels above this script.
  --prefix PATH           Install root. Defaults to ~/Library/Application Support/SPLime/local-daemon.
  --home PATH             Daemon state directory. Defaults to ~/.spl-daemon.
  --python PATH           Python 3.13+ executable. Defaults to python3.13.
  --host HOST             Bind host. Defaults to 127.0.0.1.
  --port PORT             Preferred port. Defaults to 8765.
  --wheel-dir PATH        Install from local wheels with --find-links.
  --wheel-url URL         Download SPL wheel bundle. Defaults to https://splime.io/downloads/splime-wheels-0.1.0.zip.
  --no-wheel-download     Skip the default SPL wheel bundle and install from package index.
  --install-service       Install a launchd user LaunchAgent.
  --start                 Start/restart the LaunchAgent after install.
  -h, --help              Show this help.
EOF
}

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
PREFIX="${HOME}/Library/Application Support/SPLime/local-daemon"
DAEMON_HOME="${HOME}/.spl-daemon"
PYTHON_BIN="${PYTHON_BIN:-python3.13}"
HOST="127.0.0.1"
PORT="8765"
WHEEL_DIR=""
WHEEL_URL="${SPL_WHEEL_URL:-https://splime.io/downloads/splime-wheels-0.1.0.zip}"
INSTALL_SERVICE=0
START_SERVICE=0
CLI_BIN_DIR="${HOME}/.local/bin"

append_path_block() {
  local profile_file="$1"
  local begin_marker="# >>> SPLime local daemon >>>"
  local end_marker="# <<< SPLime local daemon <<<"
  mkdir -p "$(dirname "$profile_file")"
  touch "$profile_file"
  if grep -Fq "$begin_marker" "$profile_file"; then
    return 0
  fi
  cat >> "$profile_file" <<EOF

$begin_marker
if [ -d "$CLI_BIN_DIR" ]; then
  case ":\$PATH:" in
    *":$CLI_BIN_DIR:"*) ;;
    *) export PATH="$CLI_BIN_DIR:\$PATH" ;;
  esac
fi
$end_marker
EOF
}

install_cli_wrapper() {
  local wrapper_file="$CLI_BIN_DIR/spl-daemon"
  mkdir -p "$CLI_BIN_DIR"
  cat > "$wrapper_file" <<EOF
#!/usr/bin/env bash
exec "$VENV_DIR/bin/spl-daemon" "\$@"
EOF
  chmod +x "$wrapper_file"

  append_path_block "${HOME}/.zprofile"
  append_path_block "${HOME}/.zshrc"
  append_path_block "${HOME}/.bash_profile"
  append_path_block "${HOME}/.bashrc"
}

download_file() {
  local url="$1"
  local destination="$2"
  if command -v curl >/dev/null 2>&1; then
    curl -fL "$url" -o "$destination"
  elif command -v wget >/dev/null 2>&1; then
    wget -O "$destination" "$url"
  else
    "$VENV_DIR/bin/python" - "$url" "$destination" <<'PY'
import pathlib
import sys
import urllib.request

url = sys.argv[1]
destination = pathlib.Path(sys.argv[2])
with urllib.request.urlopen(url, timeout=120) as response:
    destination.write_bytes(response.read())
PY
  fi
}

install_downloaded_wheel_bundle() {
  local wheel_cache_dir="$PREFIX/wheel-cache"
  local archive_file="$wheel_cache_dir/splime-wheels.zip"
  local extract_dir="$wheel_cache_dir/extracted"
  rm -rf "$wheel_cache_dir"
  mkdir -p "$extract_dir"

  echo "Downloading SPL wheel bundle from $WHEEL_URL"
  download_file "$WHEEL_URL" "$archive_file"
  "$VENV_DIR/bin/python" -m zipfile -e "$archive_file" "$extract_dir"

  local framework_wheel
  local daemon_wheel
  framework_wheel="$(find "$extract_dir" -type f -name 'spl_framework-*.whl' | sort | tail -n 1)"
  daemon_wheel="$(find "$extract_dir" -type f -name 'spl_daemon-*.whl' | sort | tail -n 1)"
  if [[ -z "$framework_wheel" || -z "$daemon_wheel" ]]; then
    echo "Downloaded wheel bundle does not contain spl-framework and spl-daemon wheels." >&2
    exit 1
  fi

  "$VENV_DIR/bin/python" -m pip install --upgrade --force-reinstall "$framework_wheel" "$daemon_wheel"
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --repo-root) REPO_ROOT="$2"; shift 2 ;;
    --prefix) PREFIX="$2"; shift 2 ;;
    --home) DAEMON_HOME="$2"; shift 2 ;;
    --python) PYTHON_BIN="$2"; shift 2 ;;
    --host) HOST="$2"; shift 2 ;;
    --port) PORT="$2"; shift 2 ;;
    --wheel-dir) WHEEL_DIR="$2"; shift 2 ;;
    --wheel-url) WHEEL_URL="$2"; shift 2 ;;
    --no-wheel-download) WHEEL_URL=""; shift ;;
    --install-service) INSTALL_SERVICE=1; shift ;;
    --start) START_SERVICE=1; shift ;;
    -h|--help) usage; exit 0 ;;
    *) echo "Unknown option: $1" >&2; usage; exit 2 ;;
  esac
done

REPO_ROOT="$(cd "$REPO_ROOT" && pwd)"
PREFIX="$(mkdir -p "$PREFIX" && cd "$PREFIX" && pwd)"
DAEMON_HOME="$(mkdir -p "$DAEMON_HOME" && cd "$DAEMON_HOME" && pwd)"
VENV_DIR="$PREFIX/venv"
LOG_DIR="${HOME}/Library/Logs/SPLime"
PLIST_DIR="${HOME}/Library/LaunchAgents"
PLIST_FILE="$PLIST_DIR/io.splime.daemon.plist"

"$PYTHON_BIN" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 13) else "Python 3.13+ is required")'

echo "Creating private virtual environment: $VENV_DIR"
"$PYTHON_BIN" -m venv "$VENV_DIR"
"$VENV_DIR/bin/python" -m pip install --upgrade pip

if [[ -n "$WHEEL_DIR" ]]; then
  WHEEL_DIR="$(cd "$WHEEL_DIR" && pwd)"
  echo "Installing spl-framework and spl-daemon from wheels in $WHEEL_DIR"
  "$VENV_DIR/bin/python" -m pip install --upgrade --force-reinstall --no-index --find-links "$WHEEL_DIR" spl-framework spl-daemon
elif [[ -d "$REPO_ROOT/spl-core" && -d "$REPO_ROOT/spl-daemon" ]]; then
  echo "Installing spl-framework and spl-daemon from source checkout"
  "$VENV_DIR/bin/python" -m pip install --upgrade --force-reinstall "$REPO_ROOT/spl-core" "$REPO_ROOT/spl-daemon"
elif [[ -n "$WHEEL_URL" ]]; then
  install_downloaded_wheel_bundle
else
  echo "Installing spl-daemon from package index"
  "$VENV_DIR/bin/python" -m pip install --upgrade --force-reinstall spl-daemon
fi

echo "Installing/updating certifi CA bundle for HTTPS verification"
"$VENV_DIR/bin/python" -m pip install --upgrade certifi
CA_BUNDLE="$("$VENV_DIR/bin/python" -c 'import certifi; print(certifi.where())')"
if [[ ! -f "$CA_BUNDLE" ]]; then
  echo "certifi CA bundle was not found: $CA_BUNDLE" >&2
  exit 1
fi

"$VENV_DIR/bin/python" -c 'from spl.client import SPLClient; import spl.daemon.server; print("SPL daemon import check ok")'

mkdir -p "$PREFIX" "$DAEMON_HOME" "$LOG_DIR"
cat > "$PREFIX/daemon.env" <<EOF
SPL_DAEMON_HOME=$DAEMON_HOME
SPL_DAEMON_HOST=$HOST
SPL_DAEMON_PORT=$PORT
SSL_CERT_FILE=$CA_BUNDLE
REQUESTS_CA_BUNDLE=$CA_BUNDLE
EOF

install_cli_wrapper

if [[ "$INSTALL_SERVICE" -eq 1 ]]; then
  mkdir -p "$PLIST_DIR"
  cat > "$PLIST_FILE" <<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>io.splime.daemon</string>
  <key>ProgramArguments</key>
  <array>
    <string>$VENV_DIR/bin/spl-daemon</string>
    <string>serve</string>
    <string>--host</string>
    <string>$HOST</string>
    <string>--port</string>
    <string>$PORT</string>
    <string>--home</string>
    <string>$DAEMON_HOME</string>
  </array>
  <key>EnvironmentVariables</key>
  <dict>
    <key>SPL_DAEMON_HOME</key>
    <string>$DAEMON_HOME</string>
    <key>SSL_CERT_FILE</key>
    <string>$CA_BUNDLE</string>
    <key>REQUESTS_CA_BUNDLE</key>
    <string>$CA_BUNDLE</string>
  </dict>
  <key>WorkingDirectory</key>
  <string>$DAEMON_HOME</string>
  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <true/>
  <key>StandardOutPath</key>
  <string>$LOG_DIR/spl-daemon.out.log</string>
  <key>StandardErrorPath</key>
  <string>$LOG_DIR/spl-daemon.err.log</string>
</dict>
</plist>
EOF
  launchctl bootout "gui/$(id -u)" "$PLIST_FILE" >/dev/null 2>&1 || true
  launchctl bootstrap "gui/$(id -u)" "$PLIST_FILE"
  launchctl enable "gui/$(id -u)/io.splime.daemon"
  echo "Installed LaunchAgent: $PLIST_FILE"
  if [[ "$START_SERVICE" -eq 1 ]]; then
    launchctl kickstart -k "gui/$(id -u)/io.splime.daemon"
    echo "Started io.splime.daemon"
  fi
elif [[ "$START_SERVICE" -eq 1 ]]; then
  echo "--start requires --install-service on macOS" >&2
  exit 2
fi

echo "Installed SPL local daemon."
echo "Binary: $VENV_DIR/bin/spl-daemon"
echo "CLI:    $CLI_BIN_DIR/spl-daemon"
echo "Home:   $DAEMON_HOME"
