#!/usr/bin/env bash
# Absolute DB v7.5.2
# Copyright (c) 2024-2026 D.H.Maree. All rights reserved.
# Author/Creator: David H Maree
# Owner: D.H.Maree (ABN 21 498 105 915) — sole IP holder
# Licensed to: SupportCALL AU — primary distributor
# SPDX-License-Identifier: BSL-1.1
# https://absolutedb.com/

# https://absolutedb.com/install.sh
#
# Usage:
#   curl -fsSL https://absolutedb.com/install.sh | bash
#   curl -fsSL https://absolutedb.com/install.sh | bash -s -- --uninstall
#   curl -fsSL https://absolutedb.com/install.sh | bash -s -- --no-service
#
# Copyright 2024-2026 SupportCALL AU & D.H.Maree
# License: Proprietary (Free Community Edition)

set -euo pipefail

# ─── Configuration ────────────────────────────────────────────────────────────
VERSION="7.5.2"
REPO="https://github.com/supportcall/AbsoluteDB.git"
INSTALL_DIR="${HOME}/AbsoluteDB"
BIN_DIR="/usr/local/bin"
DATA_DIR="/var/lib/absdb"
SERVICE_NAME="absdb"
SERVICE_USER="absdb"
PG_PORT=5433
REST_PORT=8080

# ─── Colours ──────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GRN='\033[0;32m'; YLW='\033[0;33m'
BLU='\033[0;34m'; CYN='\033[0;36m'; NC='\033[0m'; BOLD='\033[1m'

info()  { echo -e "${BLU}[INFO]${NC}  $*"; }
ok()    { echo -e "${GRN}[ OK ]${NC}  $*"; }
warn()  { echo -e "${YLW}[WARN]${NC}  $*"; }
err()   { echo -e "${RED}[FAIL]${NC}  $*" >&2; }
step()  { echo -e "\n${BOLD}${CYN}═══ $* ═══${NC}"; }
die()   { err "$*"; exit 1; }

# ─── Parse arguments ──────────────────────────────────────────────────────────
OPT_UNINSTALL=0
OPT_NO_SERVICE=0
OPT_NO_INSTALL=0   # build but don't copy to /usr/local/bin

for arg in "${@:-}"; do
  case "$arg" in
    --uninstall)   OPT_UNINSTALL=1 ;;
    --no-service)  OPT_NO_SERVICE=1 ;;
    --no-install)  OPT_NO_INSTALL=1 ;;
    --help|-h)
      echo "Absolute DB Installer v${VERSION}"
      echo ""
      echo "Usage:"
      echo "  curl -fsSL https://absolutedb.com/install.sh | bash"
      echo "  curl -fsSL https://absolutedb.com/install.sh | bash -s -- [OPTIONS]"
      echo ""
      echo "Options:"
      echo "  --uninstall   Remove Absolute DB from the system"
      echo "  --no-service  Skip systemd service setup"
      echo "  --no-install  Build only, do not copy to /usr/local/bin"
      echo "  --help        Show this help"
      exit 0
      ;;
    "") : ;;  # ignore empty (from piped bash)
    *) warn "Unknown option: $arg" ;;
  esac
done

# ─── Banner ───────────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}╔═══════════════════════════════════════════╗${NC}"
echo -e "${BOLD}║   Absolute DB v${VERSION} Installer            ║${NC}"
echo -e "${BOLD}║   https://absolutedb.com/                 ║${NC}"
echo -e "${BOLD}╚═══════════════════════════════════════════╝${NC}"
echo ""

# ─── Detect OS ────────────────────────────────────────────────────────────────
detect_os() {
  if [ -f /etc/debian_version ]; then
    OS="debian"
    PKG="apt"
  elif [ -f /etc/redhat-release ]; then
    OS="rhel"
    if command -v dnf &>/dev/null; then PKG="dnf"; else PKG="yum"; fi
  elif [ "$(uname -s)" = "Darwin" ]; then
    OS="macos"
    PKG="brew"
  elif [ -f /etc/arch-release ]; then
    OS="arch"
    PKG="pacman"
  else
    OS="unknown"
    PKG="unknown"
  fi
  info "Detected OS: ${OS} (package manager: ${PKG})"
}

# ─── Check for root / sudo ────────────────────────────────────────────────────
SUDO=""
if [ "$(id -u)" -eq 0 ]; then
  SUDO=""
else
  if command -v sudo &>/dev/null; then
    SUDO="sudo"
  else
    warn "Not running as root and 'sudo' not found."
    warn "Some steps may fail. Run as root or install sudo first."
  fi
fi

# ─── Uninstall ────────────────────────────────────────────────────────────────
if [ "$OPT_UNINSTALL" -eq 1 ]; then
  step "Uninstalling Absolute DB"

  if command -v systemctl &>/dev/null; then
    $SUDO systemctl stop    "${SERVICE_NAME}" 2>/dev/null || true
    $SUDO systemctl disable "${SERVICE_NAME}" 2>/dev/null || true
    $SUDO rm -f "/etc/systemd/system/${SERVICE_NAME}.service"
    $SUDO systemctl daemon-reload 2>/dev/null || true
    ok "Stopped and removed systemd service"
  fi

  $SUDO rm -f "${BIN_DIR}/absdb"
  $SUDO rm -f "${BIN_DIR}/absdb-server"
  $SUDO rm -f "${BIN_DIR}/absdb-bench"
  $SUDO rm -rf "/usr/local/include/absdb"
  $SUDO rm -rf "/usr/local/share/doc/absdb"

  ok "Removed binaries and documentation"
  warn "Data directory ${DATA_DIR} was NOT removed (to preserve your data)."
  warn "To remove data: sudo rm -rf ${DATA_DIR}"
  echo ""
  ok "Absolute DB uninstalled successfully."
  exit 0
fi

# ─── Step 1: Install prerequisites ───────────────────────────────────────────
step "Step 1/5 — Installing prerequisites"

detect_os

# Ensure package lists are up to date (Debian/Ubuntu only)
if [ "$PKG" = "apt" ]; then
  info "Updating package lists..."
  $SUDO apt-get update -qq
fi

# Install build tools + curl
if [ "$OS" = "debian" ]; then
  info "Installing git, gcc, make, build-essential, curl..."
  $SUDO apt-get install -y -qq git gcc make build-essential curl
elif [ "$OS" = "rhel" ]; then
  if ! command -v gcc &>/dev/null; then
    info "Installing Development Tools group..."
    $SUDO "$PKG" groupinstall -y "Development Tools"
  fi
  info "Installing git and curl..."
  $SUDO "$PKG" install -y git curl
elif [ "$OS" = "arch" ]; then
  $SUDO pacman -S --noconfirm --needed base-devel git curl
elif [ "$OS" = "macos" ]; then
  if ! command -v gcc &>/dev/null; then
    info "Installing Xcode command-line tools..."
    xcode-select --install 2>/dev/null || true
    warn "If a dialog appeared, click Install and wait for it to finish."
    warn "Then re-run this installer."
    exit 0
  fi
  command -v git &>/dev/null || brew install git
  command -v curl &>/dev/null || brew install curl
fi

# Verify required tools are present
for req in git gcc make curl; do
  if command -v "$req" &>/dev/null; then
    ok "$req: $(command -v "$req")"
  else
    die "$req is required but could not be installed. Install it manually and retry."
  fi
done

# ─── Step 2: Download / update source ────────────────────────────────────────
step "Step 2/5 — Getting Absolute DB source"

if [ -d "${INSTALL_DIR}/.git" ]; then
  info "Existing installation found at ${INSTALL_DIR} — updating..."
  cd "${INSTALL_DIR}"
  git fetch origin main --quiet
  git reset --hard origin/main --quiet
  ok "Updated to latest version"
else
  if [ -d "${INSTALL_DIR}" ]; then
    warn "Directory ${INSTALL_DIR} exists but is not a git repo. Removing it..."
    rm -rf "${INSTALL_DIR}"
  fi
  info "Cloning from GitHub (this takes 30-60 seconds)..."
  git clone --depth=1 "${REPO}" "${INSTALL_DIR}" --quiet
  ok "Cloned to ${INSTALL_DIR}"
fi

cd "${INSTALL_DIR}"

# ─── Step 3: Build ────────────────────────────────────────────────────────────
step "Step 3/5 — Building Absolute DB"
info "Compiling source code and running 644 automated tests (~7 seconds)..."
echo ""

make clean --quiet 2>/dev/null || true
make all

# Verify binaries were created
if [ ! -x "build/absdb-server" ]; then
  die "Build failed — build/absdb-server not found. Check output above for errors."
fi

echo ""
ok "Build complete — binaries ready in ./build/"

# ─── Step 4: Install binaries ─────────────────────────────────────────────────
if [ "$OPT_NO_INSTALL" -eq 0 ]; then
  step "Step 4/5 — Installing binaries to ${BIN_DIR}"

  $SUDO install -m 755 build/absdb         "${BIN_DIR}/absdb"
  $SUDO install -m 755 build/absdb-server  "${BIN_DIR}/absdb-server"
  $SUDO install -m 755 build/absdb-bench   "${BIN_DIR}/absdb-bench"

  # Headers
  $SUDO mkdir -p /usr/local/include/absdb
  $SUDO cp include/absolute.h  /usr/local/include/absdb/ 2>/dev/null || true
  $SUDO cp include/adb_types.h /usr/local/include/absdb/ 2>/dev/null || true
  $SUDO cp include/adb_sql.h   /usr/local/include/absdb/ 2>/dev/null || true

  # Docs
  $SUDO mkdir -p /usr/local/share/doc/absdb
  $SUDO cp README.md LICENSE dist/docs/*.md /usr/local/share/doc/absdb/ 2>/dev/null || true

  ok "Installed: absdb  absdb-server  absdb-bench → ${BIN_DIR}/"
else
  step "Step 4/5 — Skipped (--no-install)"
fi

# ─── Step 5: Systemd service ──────────────────────────────────────────────────
if [ "$OPT_NO_SERVICE" -eq 0 ] && command -v systemctl &>/dev/null && [ "$OS" != "macos" ]; then
  step "Step 5/5 — Setting up systemd service"

  # Create dedicated system user (never run a database as root)
  if ! id "${SERVICE_USER}" &>/dev/null; then
    $SUDO useradd --system --no-create-home \
      --shell /usr/sbin/nologin 2>/dev/null \
      --shell /sbin/nologin "${SERVICE_USER}" 2>/dev/null || \
      $SUDO useradd --system --no-create-home "${SERVICE_USER}"
    ok "Created system user '${SERVICE_USER}'"
  else
    ok "System user '${SERVICE_USER}' already exists"
  fi

  # Create and secure data directory
  $SUDO mkdir -p "${DATA_DIR}"
  $SUDO chown "${SERVICE_USER}:${SERVICE_USER}" "${DATA_DIR}" 2>/dev/null || \
    $SUDO chown "${SERVICE_USER}" "${DATA_DIR}" 2>/dev/null || true
  $SUDO chmod 750 "${DATA_DIR}"
  ok "Data directory: ${DATA_DIR} (owned by ${SERVICE_USER})"

  # Write service file with explicit ports
  $SUDO tee /etc/systemd/system/${SERVICE_NAME}.service > /dev/null <<EOF
[Unit]
Description=Absolute DB v${VERSION} Database Server
Documentation=https://absolutedb.com/docs
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=${SERVICE_USER}
Group=${SERVICE_USER}
ExecStart=${BIN_DIR}/absdb-server -p ${PG_PORT} -r ${REST_PORT} -d ${DATA_DIR}/data.db
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
# Activate a licence key for Professional/Enterprise:
# Environment="ADB_LICENSE_KEY=PRO-XXXX-XXXX-XXXX-XXXX"

[Install]
WantedBy=multi-user.target
EOF

  ok "Service file written: /etc/systemd/system/${SERVICE_NAME}.service"

  # Open firewall ports (ufw — Ubuntu/Debian)
  if command -v ufw &>/dev/null && $SUDO ufw status 2>/dev/null | grep -q "Status: active"; then
    $SUDO ufw allow ${PG_PORT}/tcp --quiet 2>/dev/null || true
    $SUDO ufw allow ${REST_PORT}/tcp --quiet 2>/dev/null || true
    ok "Firewall (ufw): opened ports ${PG_PORT}/tcp and ${REST_PORT}/tcp"
  fi

  # Open firewall ports (firewalld — RHEL/Fedora)
  if command -v firewall-cmd &>/dev/null && $SUDO firewall-cmd --state -q 2>/dev/null; then
    $SUDO firewall-cmd --add-port=${PG_PORT}/tcp --permanent -q 2>/dev/null || true
    $SUDO firewall-cmd --add-port=${REST_PORT}/tcp --permanent -q 2>/dev/null || true
    $SUDO firewall-cmd --reload -q 2>/dev/null || true
    ok "Firewall (firewalld): opened ports ${PG_PORT}/tcp and ${REST_PORT}/tcp"
  fi

  # Enable and start
  $SUDO systemctl daemon-reload
  $SUDO systemctl enable "${SERVICE_NAME}" --quiet
  $SUDO systemctl restart "${SERVICE_NAME}"

  # Wait up to 10 seconds for service to start
  info "Waiting for server to start..."
  STARTED=0
  for i in 1 2 3 4 5 6 7 8 9 10; do
    sleep 1
    if $SUDO systemctl is-active "${SERVICE_NAME}" --quiet 2>/dev/null; then
      ok "Service '${SERVICE_NAME}' is running (PID: $(systemctl show -p MainPID --value absdb 2>/dev/null || echo '?'))"
      STARTED=1
      break
    fi
  done

  if [ "$STARTED" -eq 0 ]; then
    err "Service '${SERVICE_NAME}' did not start within 10 seconds."
    err "Check logs with: sudo journalctl -u ${SERVICE_NAME} --no-pager -n 30"
    warn "Continuing — you may need to start manually: sudo systemctl start ${SERVICE_NAME}"
  fi

elif [ "$OPT_NO_SERVICE" -eq 1 ]; then
  step "Step 5/5 — Skipped (--no-service)"
  info "To start manually:"
  info "  ${BIN_DIR}/absdb-server -p ${PG_PORT} -r ${REST_PORT} -d ${DATA_DIR}/data.db"
fi

# ─── macOS LaunchAgent ────────────────────────────────────────────────────────
if [ "$OPT_NO_SERVICE" -eq 0 ] && [ "$OS" = "macos" ] && [ "$OPT_NO_INSTALL" -eq 0 ]; then
  step "Setting up macOS LaunchAgent"
  PLIST="/Library/LaunchDaemons/com.absdb.server.plist"
  $SUDO mkdir -p "${DATA_DIR}"
  $SUDO tee "${PLIST}" > /dev/null <<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.absdb.server</string>
  <key>ProgramArguments</key>
  <array>
    <string>${BIN_DIR}/absdb-server</string>
    <string>-p</string><string>${PG_PORT}</string>
    <string>-r</string><string>${REST_PORT}</string>
    <string>-d</string><string>${DATA_DIR}/data.db</string>
  </array>
  <key>RunAtLoad</key><true/>
  <key>KeepAlive</key><true/>
  <key>StandardOutPath</key><string>/var/log/absdb.log</string>
  <key>StandardErrorPath</key><string>/var/log/absdb.log</string>
</dict>
</plist>
EOF
  $SUDO launchctl unload "${PLIST}" 2>/dev/null || true
  $SUDO launchctl load   "${PLIST}"
  ok "LaunchAgent installed and started"
fi

# ─── Verify REST API is responding ────────────────────────────────────────────
step "Verifying installation"

if command -v absdb &>/dev/null; then
  ok "absdb CLI:    $(absdb --version 2>/dev/null || echo "v${VERSION}")"
fi
if command -v absdb-server &>/dev/null; then
  ok "absdb-server: $(absdb-server --version 2>/dev/null || echo "v${VERSION}")"
fi

# Wait for REST API to respond (up to 15 seconds total)
info "Testing REST API at http://localhost:${REST_PORT}/health ..."
REST_OK=0
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
  sleep 1
  HEALTH=$(curl -sf --connect-timeout 2 "http://localhost:${REST_PORT}/health" 2>/dev/null || true)
  if echo "${HEALTH}" | grep -q '"healthy":true'; then
    ok "REST API is responding: ${HEALTH}"
    REST_OK=1
    break
  fi
done

if [ "$REST_OK" -eq 0 ]; then
  err "REST API on port ${REST_PORT} did not respond within 15 seconds."
  echo ""
  warn "Troubleshooting steps:"
  warn "  1. Check server is running:   sudo systemctl status absdb"
  warn "  2. View logs:                 sudo journalctl -u absdb --no-pager -n 30"
  warn "  3. Check port is open:        sudo ss -tlnp | grep ${REST_PORT}"
  warn "     or:                        sudo netstat -tlnp | grep ${REST_PORT}"
  warn "  4. Test manually:             curl http://localhost:${REST_PORT}/health"
  warn "  5. If on a VPS/cloud: open port ${REST_PORT} in your cloud security group"
  warn "     (AWS: EC2 → Security Groups → Inbound Rules → Add ${REST_PORT}/tcp)"
  warn "     (GCP: VPC → Firewall → Allow ${REST_PORT}/tcp)"
  warn "     (DigitalOcean: Networking → Firewalls → Add ${REST_PORT}/tcp)"
fi

# Test psql if available
if command -v psql &>/dev/null; then
  PSQL_RESULT=$(psql -h localhost -p ${PG_PORT} -U absdb -t -c "SELECT 1+1;" 2>/dev/null | tr -d ' \n' || true)
  if [ "${PSQL_RESULT}" = "2" ]; then
    ok "PostgreSQL wire protocol: psql connected successfully on port ${PG_PORT}"
  else
    warn "psql test inconclusive (server may still be initializing)"
  fi
else
  info "psql not installed — to test wire protocol:"
  info "  Ubuntu/Debian: sudo apt install -y postgresql-client"
  info "  RHEL/Fedora:   sudo dnf install -y postgresql"
  info "  Then:          psql -h localhost -p ${PG_PORT} -U absdb"
fi

# ─── Done ─────────────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}${GRN}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}${GRN}║   Absolute DB v${VERSION} installed successfully!               ║${NC}"
echo -e "${BOLD}${GRN}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "  ${BOLD}REST API:${NC}"
echo -e "    curl http://localhost:${REST_PORT}/health"
echo -e "    curl -X POST http://localhost:${REST_PORT}/sql \\"
echo -e "      -H 'Content-Type: application/json' \\"
echo -e "      -d '{\"sql\":\"SELECT 1+1 AS result\"}'"
echo ""
echo -e "  ${BOLD}PostgreSQL wire protocol:${NC}"
echo -e "    psql -h localhost -p ${PG_PORT} -U \$(whoami)"
echo -e "    (Install psql: sudo apt install -y postgresql-client)"
echo ""
echo -e "  ${BOLD}Service management:${NC}"
echo -e "    sudo systemctl status absdb       # check status"
echo -e "    sudo systemctl restart absdb      # restart"
echo -e "    sudo journalctl -u absdb -f       # live logs"
echo ""
echo -e "  ${BOLD}If on a VPS/cloud server:${NC}"
echo -e "    Open ports ${PG_PORT}/tcp and ${REST_PORT}/tcp in your cloud firewall"
echo -e "    Then connect from your machine using the server's public IP:"
echo -e "    curl http://YOUR_SERVER_IP:${REST_PORT}/health"
echo -e "    psql -h YOUR_SERVER_IP -p ${PG_PORT} -U absdb"
echo ""
echo -e "  ${BOLD}Documentation:${NC}"
echo -e "    https://absolutedb.com/docs"
echo ""
