#!/usr/bin/env bash
# -----------------------------------------
# A script to download, unpack, and install CedarDB
# Downloaded from get.cedardb.com
# -----------------------------------------

set -euo pipefail

# ------------------------
# Defaults (overridable by env)
# ------------------------
YES="${CEDARDB_YES:-0}"
INSTALL_DIR="${CEDARDB_INSTALL_DIR:-$PWD}"
WITH_SYMLINK="${CEDARDB_WITH_SYMLINK:-0}"
WITH_SYSTEMD="${CEDARDB_WITH_SYSTEMD:-0}"
SYSTEMD_SCOPE="${CEDARDB_SYSTEMD_SCOPE:-user}"  # user|system
SYSTEMD_ENABLE="${CEDARDB_SYSTEMD_ENABLE:-0}"
SYSTEMD_START="${CEDARDB_SYSTEMD_START:-0}"
PG_PORT="${CEDARDB_PG_PORT:-5432}"
DB_DIR="${CEDARDB_DB_DIR:-$INSTALL_DIR/cedar/db}"

# ------------------------
# CLI parsing
# ------------------------
print_help() {
  cat <<'EOF'
CedarDB installer

Usage:
  install.sh [options]

General:
  -y, --yes                 Non-interactive (auto-accept prompts, uses defaults if not explicitly set)
  --install-dir DIR         Where to install CedarDB (default: $PWD)
  --with-symlink            Create a symlink 'cedardb' in /usr/local/bin (default: no)

Systemd (opt-in):
  --with-systemd[=SCOPE]    Install systemd units; SCOPE: 'user' (default) or 'system'
  --port N                  TCP port (default: 5432)
  --db-dir DIR              Database directory (default: $INSTALL_DIR/cedar/db)
  --systemd-enable          Enable the socket unit at boot (default: no)
  --systemd-start           Start the socket after install (default: no)

Help:
  -h, --help                Show this help and exit

Environment variables (same as flags):
  CEDARDB_YES, CEDARDB_INSTALL_DIR, CEDARDB_WITH_SYMLINK,
  CEDARDB_WITH_SYSTEMD, CEDARDB_SYSTEMD_SCOPE, CEDARDB_PG_PORT,
  CEDARDB_DB_DIR, CEDARDB_SYSTEMD_ENABLE, CEDARDB_SYSTEMD_START
EOF
}

while [ $# -gt 0 ]; do
  case "$1" in
    -y|--yes) YES=1; shift ;;
    --install-dir) INSTALL_DIR="${2:?--install-dir requires DIR}"; shift 2 ;;
    --with-symlink) WITH_SYMLINK=1; shift ;;
    --with-systemd) WITH_SYSTEMD=1; shift ;;
    --with-systemd=*) WITH_SYSTEMD=1; SYSTEMD_SCOPE="${1#*=}"; shift ;;
    --port) PG_PORT="${2:?--port requires N}"; shift 2 ;;
    --db-dir) DB_DIR="${2:?--db-dir requires DIR}"; shift 2 ;;
    --systemd-enable) SYSTEMD_ENABLE=1; shift ;;
    --systemd-start) SYSTEMD_START=1; shift ;;
    -h|--help) print_help; exit 0 ;;
    *) echo "Unknown option: $1"; echo; print_help; exit 1 ;;
  esac
done

# ------------------------
# Colors
# ------------------------
GREEN="\033[0;32m"; CYAN="\033[0;36m"; RED="\033[0;31m"; RESET="\033[0m"

# ------------------------
# Helpers
# ------------------------
panic() { echo -e "$1" >&2; exit 1; }


tty_read() { # prompt, varname, default
  local prompt="$1" var="$2" def="$3" ans
  if read -r -p "$prompt [$def] " ans < /dev/tty; then
    eval "$var=\"\${ans:-$def}\""
    return
  fi
  eval "$var=\"$def\""
}

# Normalize a boolean-ish string to 0/1 (accepts y/yes/true/1 and n/no/false/0)
normalize_bool() {
  case "$(echo "${1:-}" | tr '[:upper:]' '[:lower:]')" in
    y|yes|true|1) echo 1 ;;
    n|no|false|0|'') echo 0 ;;
    *) echo 0 ;;
  esac
}

# TTY y/n prompt that writes 0/1 into the given var name
tty_yesno() {
  local prompt="$1" var="$2" def="${3:-n}" ans
  local def_disp; def_disp=$(echo "$def" | tr '[:lower:]' '[:upper:]')
  read -r -p "$prompt [y/N] " ans < /dev/tty || true
  # If nothing typed, use default
  ans="${ans:-$def}"
  eval "$var=\"$(normalize_bool "$ans")\""
}

main() {
  # ------------------------
  # Optional interactive wizard
  # ------------------------
  if [ "$YES" -eq 0 ]; then
    echo -e "${CYAN}CedarDB install wizard${RESET}"
    tty_read "Install directory" INSTALL_DIR "$INSTALL_DIR"
    tty_yesno "Create a symlink in /usr/local/bin? (requires sudo) [y/N]" WITH_SYMLINK "n"
    tty_yesno "Install systemd units? [y/N]" WITH_SYSTEMD "n"
    if [ "$WITH_SYSTEMD" -eq 1 ]; then
      tty_read "Systemd scope ('user' or 'system')" SYSTEMD_SCOPE "${SYSTEMD_SCOPE}"
      tty_read "Port" PG_PORT "${PG_PORT}"
      DB_DIR="${CEDARDB_DB_DIR:-$INSTALL_DIR/cedar/db}"
      tty_read "Database directory" DB_DIR "$DB_DIR"
      tty_yesno "Enable socket at boot? [y/N]" SYSTEMD_ENABLE "n"
      tty_yesno "Start socket now? [y/N]"      SYSTEMD_START  "n"
    fi
    INSTALL_DIR="${INSTALL_DIR/#\~/$HOME}"
    DB_DIR="${DB_DIR/#\~/$HOME}"
  echo
  fi

  # ------------------------
  # Platform checks
  # ------------------------
  command -v curl >/dev/null 2>&1 || panic "Could not find curl"
  OS=$(uname -s); ARCH=$(uname -m)
  [ "$OS" = "Darwin" ] && panic "${RED}Running natively on macOS is unsupported. Use the docker image.${RESET}"
  [ "$OS" = "Linux" ] || panic "${RED}Operating system '${OS}' is not supported.${RESET}"

  # ------------------------
  # glibc detection
  # ------------------------
  detect_glibc() {
    local version_line; version_line=$(ldd --version | head -n 1 || true)
    GLIBC_VERSION=$(echo "$version_line" | grep -oE '[0-9]+\.[0-9]+' | tail -1)
    [ -n "${GLIBC_VERSION:-}" ] || panic "${RED}Could not detect glibc version.${RESET}"
  }
  version_lt() { [ "$(printf '%s\n' "$1" "$2" | sort -V | head -n1)" != "$2" ]; }

  detect_glibc
  if version_lt "$GLIBC_VERSION" "2.27"; then
    panic "${RED}glibc '${GLIBC_VERSION}' not supported. Need >= 2.27.${RESET}"
  elif version_lt "$GLIBC_VERSION" "2.36"; then
    TARGET=legacy
  else
    TARGET=current
  fi

  # ------------------------
  # Arch resolution
  # ------------------------
  case "$ARCH" in
    x86_64|amd64) RESOLVED_ARCH="amd64" ;;
    aarch64|arm64) RESOLVED_ARCH="arm64" ;;
    *) panic "${RED}Architecture '${ARCH}' is not supported.${RESET}" ;;
  esac

  # ------------------------
  # Paths
  # ------------------------
  mkdir -p "$INSTALL_DIR" || panic "${RED}Cannot create install directory '${INSTALL_DIR}'. Check that the parent directory exists and you have write permission.${RESET}"

  ARCHIVE_NAME="cedar-${TARGET}-${RESOLVED_ARCH}.tar.xz"
  URL="https://download.cedardb.com/latest/${ARCHIVE_NAME}"
  ON_DISK_NAME="$INSTALL_DIR/$ARCHIVE_NAME"
  BIN_ABS="$INSTALL_DIR/cedar/cedardb"

  echo "Installing CedarDB to '$INSTALL_DIR/cedar'"

  # Overwrite existing archives
  if [ -f "$ON_DISK_NAME" ]; then
    rm -f "$ON_DISK_NAME"
  fi

  # Download & extract
  echo; echo -e "Downloading ${URL} into ${ON_DISK_NAME}..."; echo
  (
    cd "$INSTALL_DIR"
    curl -fsSL "${URL}" -o "${ON_DISK_NAME}" \
      && tar -xvf "${ON_DISK_NAME}" \
      && chmod a+x "cedar/cedardb"
  ) || panic "Download or extraction failed!"

  # Smoke test
  THE_ANSWER=$("$BIN_ABS" -inmemory -interactive '' <(echo 'select sqrt(1764);') 2>/dev/null | tail -n 1 || true)
  [ "$THE_ANSWER" = "42" ] || panic "Testing CedarDB binary '$BIN_ABS' failed"

  # Optional bin symlink
  if [ "$WITH_SYMLINK" -eq 1 ]; then
    DEST_BIN="/usr/local/bin/cedardb"
    ln -sf "$BIN_ABS" "$DEST_BIN"
  fi

  # ------------------------
  # Systemd (opt-in)
  # ------------------------
  install_systemd_units() {
    local scope="$1" pg_port="$2" sock_path="$3"
    local units_dir svc_file="cedardb.service" sock_file="cedardb.socket"

    if [ "$scope" = "user" ]; then
      units_dir="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user"
    else
      units_dir="/etc/systemd/system"
    fi


    local svc_content="[Unit]
  Description=CedarDB server
  After=network.target

  [Service]
  Type=simple
  ExecStart=${BIN_ABS} -createdb ${DB_DIR} -port ${PG_PORT} -createSSLFiles
  "

    local sock_content="[Unit]
  Description=Socket activation unit for CedarDB server
  PartOf=cedardb.service

  [Socket]
  ListenStream=${sock_path}
  ListenStream=127.0.0.1:${pg_port}
  ListenStream=[::1]:${pg_port}
  "

    printf "%s" "$svc_content" > "$units_dir/$svc_file"
    printf "%s" "$sock_content" > "$units_dir/$sock_file"

    if [ "$scope" = "user" ]; then
      systemctl --user daemon-reload
    else
      systemctl daemon-reload
    fi

    # Enable/start socket if requested
    if [ "$SYSTEMD_ENABLE" -eq 1 ]; then
      if [ "$scope" = "user" ]; then systemctl --user enable cedardb.socket
      else systemctl enable cedardb.socket; fi
    fi
    if [ "$SYSTEMD_START" -eq 1 ]; then
      if [ "$scope" = "user" ]; then systemctl --user start cedardb.socket
      else systemctl start cedardb.socket; fi
    fi

    echo -e "${GREEN}Installed systemd units (${scope})${RESET}"
    echo "  Service: $units_dir/$svc_file"
    echo "  Socket : $units_dir/$sock_file"
  }

  if [ "$WITH_SYSTEMD" -eq 1 ]; then
    command -v systemctl >/dev/null 2>&1 || panic "${RED}systemctl not found; cannot install systemd units.${RESET}"
    echo
    echo "Preparing to install systemd units (scope: ${SYSTEMD_SCOPE})"
    echo "  ExecStart=${BIN_ABS} -createdb ${DB_DIR} -createSSLFiles"
    echo "  ListenStream (unix): /tmp/.s.PGSQL.${PG_PORT}"
    echo "  ListenStream (tcp):  127.0.0.1:${PG_PORT} and [::1]:${PG_PORT}"
    install_systemd_units "$SYSTEMD_SCOPE" "$PG_PORT" "/tmp/.s.PGSQL.${PG_PORT}"
  fi

  # ------------------------
  # Done
  # ------------------------
  echo
  echo -e "${GREEN}Successfully installed CedarDB!${RESET}"
  echo -e "Interactive shell:\n  ${CYAN}$BIN_ABS -interactive${RESET}"
  echo -e "Start a postgres-compatible server:\n  ${CYAN}$BIN_ABS -createdb ~/mydatabase${RESET}\n(connect via psql -h /tmp -U postgres)"
  if [ "$WITH_SYMLINK" -eq 1 ]; then
    echo -e "Symlinked binary:\n  ${CYAN}/usr/local/bin/cedardb${RESET}"
  fi
  if [ "$WITH_SYSTEMD" -eq 1 ]; then
    if [ "$SYSTEMD_SCOPE" = "user" ]; then
      echo "Manage socket: systemctl --user start|stop|status cedardb.socket"
      echo "Enable linger for boot activation (optional): sudo loginctl enable-linger \"$(id -un)\""
    else
      echo "Manage socket: sudo systemctl start|stop|status cedardb.socket"
    fi
  fi
  echo -e "Docs: https://cedardb.com/docs"
}
main
