#!/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/downloads/install-macos.sh
#
# Tested on: macOS 12 Monterey, 13 Ventura, 14 Sonoma, 15 Sequoia (Intel + Apple Silicon)
# Starts from a completely fresh macOS install — no prior tools required.
#
# Usage:
#   bash install-macos.sh
#   bash install-macos.sh --no-service          # skip LaunchAgent setup
#   bash install-macos.sh --no-test             # skip post-build test suite
#   bash install-macos.sh --uninstall           # remove Absolute DB
#   bash install-macos.sh --prefix=/opt/absdb   # custom install prefix
#   bash install-macos.sh --branch=main         # checkout specific branch
#
# Copyright 2024-2026 SupportCALL AU & D.H.Maree
# SPDX-License-Identifier: BSL-1.1

set -euo pipefail

# ── Constants ─────────────────────────────────────────────────────────────────
VERSION="7.5.2"
REPO="https://github.com/supportcall/AbsoluteDB.git"
INSTALL_DIR="${HOME}/AbsoluteDB"
DATA_DIR="${HOME}/.absdb"
PG_PORT=5432
REST_PORT=8080
GRPC_PORT=9090
PLIST="${HOME}/Library/LaunchAgents/com.absdb.server.plist"
LOG_FILE="${DATA_DIR}/install.log"
MIN_MACOS_MAJOR=12

# ── Colour helpers ────────────────────────────────────────────────────────────
GRN='\033[0;32m'; BLU='\033[0;34m'; YLW='\033[0;33m'
RED='\033[0;31m'; 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}  $*"; }
step() { echo -e "\n${BOLD}${CYN}$*${NC}"; }
die()  {
    echo -e "\n${RED}${BOLD}[FAIL]${NC}  $*" >&2
    echo -e "${YLW}${BOLD}Troubleshooting guide:${NC}" >&2
    echo -e "  1. Full install log: ${LOG_FILE}" >&2
    echo -e "  2. Re-run with verbose output: bash -x install-macos.sh" >&2
    echo -e "  3. Xcode tools missing?  Run: xcode-select --install" >&2
    echo -e "  4. Homebrew install failed? Visit: https://brew.sh" >&2
    echo -e "  5. Apple Silicon path issue? Ensure /opt/homebrew/bin is in PATH" >&2
    echo -e "  6. SIP/Gatekeeper blocking binary? Run:" >&2
    echo -e "       xattr -d com.apple.quarantine ${BIN_DIR}/absdb" >&2
    echo -e "  7. Port ${PG_PORT} in use? Check: lsof -i :${PG_PORT}" >&2
    echo -e "  8. LaunchAgent not loading? Check: launchctl error log" >&2
    echo -e "       log show --predicate 'subsystem == \"com.apple.xpc.launchd\"' --last 1m" >&2
    echo -e "  9. See full docs: https://absolutedb.com/docs/install-macos" >&2
    exit 1
}

# Redirect all output to log file while keeping terminal output
mkdir -p "${HOME}/.absdb" 2>/dev/null || true
exec > >(tee -a "${LOG_FILE}") 2>&1

# ── Argument parsing ──────────────────────────────────────────────────────────
OPT_NO_SERVICE=0
OPT_NO_TEST=0
OPT_UNINSTALL=0
BRANCH="main"

for a in "$@"; do
    case "$a" in
        --no-service)     OPT_NO_SERVICE=1 ;;
        --no-test)        OPT_NO_TEST=1 ;;
        --uninstall)      OPT_UNINSTALL=1 ;;
        --prefix=*)       BIN_PREFIX="${a#--prefix=}" ;;
        --branch=*)       BRANCH="${a#--branch=}" ;;
        --help|-h)
            echo "Usage: bash install-macos.sh [OPTIONS]"
            echo "  --no-service       Skip LaunchAgent setup"
            echo "  --no-test          Skip post-build test suite"
            echo "  --uninstall        Remove Absolute DB"
            echo "  --prefix=<path>    Install binaries to <path>/bin (default: auto-detect)"
            echo "  --branch=<name>    Git branch to install (default: main)"
            exit 0
            ;;
        *) warn "Unknown option: $a (ignored)" ;;
    esac
done

# ── Detect architecture and set prefix ───────────────────────────────────────
ARCH=$(uname -m)
if [ "${ARCH}" = "arm64" ]; then
    PLATFORM="Apple Silicon (arm64)"
    DEFAULT_PREFIX="/opt/homebrew"
    HOMEBREW_PREFIX="/opt/homebrew"
else
    PLATFORM="Intel (x86_64)"
    DEFAULT_PREFIX="/usr/local"
    HOMEBREW_PREFIX="/usr/local"
fi
BIN_PREFIX="${BIN_PREFIX:-${DEFAULT_PREFIX}}"
BIN_DIR="${BIN_PREFIX}/bin"

# ── Banner ────────────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}${GRN}╔══════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}${GRN}║   Absolute DB v${VERSION} — macOS Installer         ║${NC}"
echo -e "${BOLD}${GRN}╚══════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "  Platform : ${BOLD}${PLATFORM}${NC}"
echo -e "  Install  : ${BOLD}${INSTALL_DIR}${NC}"
echo -e "  Binaries : ${BOLD}${BIN_DIR}${NC}"
echo -e "  Data     : ${BOLD}${DATA_DIR}${NC}"
echo -e "  Branch   : ${BOLD}${BRANCH}${NC}"
echo -e "  Log      : ${BOLD}${LOG_FILE}${NC}"
echo ""

# ── Uninstall ─────────────────────────────────────────────────────────────────
if [ "${OPT_UNINSTALL}" -eq 1 ]; then
    step "Uninstalling Absolute DB v${VERSION}..."
    launchctl unload "${PLIST}" 2>/dev/null || true
    rm -f "${PLIST}"
    rm -f "${BIN_DIR}/absdb" "${BIN_DIR}/absdb-server" "${BIN_DIR}/absdb-bench"
    rm -rf "${BIN_PREFIX}/include/absdb" "${BIN_PREFIX}/share/doc/absdb"
    rm -rf "${INSTALL_DIR}"
    ok "Absolute DB removed."
    warn "Data directory ${DATA_DIR} was NOT removed (remove manually if desired)."
    exit 0
fi

# ── Step 1/5: Check macOS version ─────────────────────────────────────────────
step "Step 1/5: Checking system requirements"

MACOS_VER=$(sw_vers -productVersion 2>/dev/null || echo "0.0")
MACOS_MAJOR=$(echo "${MACOS_VER}" | cut -d. -f1)
info "macOS version: ${MACOS_VER}"

if [ "${MACOS_MAJOR}" -lt "${MIN_MACOS_MAJOR}" ] 2>/dev/null; then
    warn "macOS ${MACOS_VER} is below the minimum supported version (${MIN_MACOS_MAJOR}.x)."
    warn "Absolute DB v${VERSION} is tested on macOS 12 and later."
    warn "Proceeding anyway — some features may not work correctly."
else
    ok "macOS ${MACOS_VER} — supported"
fi

# Check available disk space (need at least 500 MB)
AVAIL_KB=$(df -k "${HOME}" | awk 'NR==2 {print $4}')
if [ "${AVAIL_KB:-0}" -lt 512000 ]; then
    warn "Less than 500 MB disk space available (${AVAIL_KB} KB). Build may fail."
else
    ok "Disk space: $(( ${AVAIL_KB:-0} / 1024 )) MB available"
fi

# Check available RAM
RAM_MB=$(( $(sysctl -n hw.memsize 2>/dev/null || echo 0) / 1048576 ))
if [ "${RAM_MB}" -lt 512 ]; then
    warn "Only ${RAM_MB} MB RAM detected. Recommend at least 512 MB."
else
    ok "RAM: ${RAM_MB} MB"
fi

# ── Step 2/5: Xcode Command Line Tools ────────────────────────────────────────
step "Step 2/5: Checking Xcode Command Line Tools"

XCODE_OK=0
if xcode-select -p &>/dev/null && command -v gcc &>/dev/null && command -v make &>/dev/null; then
    XCODE_OK=1
fi

if [ "${XCODE_OK}" -eq 0 ]; then
    warn "Xcode Command Line Tools are not installed."
    echo ""
    echo -e "${BOLD}  How to install:${NC}"
    echo "  1. A system dialog will appear after this script runs:"
    echo "       xcode-select --install"
    echo "  2. Click 'Install' (NOT 'Get Xcode') in the dialog."
    echo "  3. Accept the license agreement."
    echo "  4. Wait 5-10 minutes for the download to complete."
    echo "  5. Run this installer again:"
    echo "       bash install-macos.sh"
    echo ""
    info "Launching Xcode tools installer dialog now..."
    xcode-select --install 2>/dev/null || true
    echo ""
    warn "IMPORTANT: After the dialog install completes, re-run: bash install-macos.sh"
    exit 0
fi

GCC_VER=$(gcc --version 2>/dev/null | head -1 || echo "unknown")
ok "Compiler: ${GCC_VER}"
ok "make: $(make --version 2>/dev/null | head -1)"
ok "Xcode tools path: $(xcode-select -p)"

# ── Step 3/5: Install Homebrew + git ──────────────────────────────────────────
step "Step 3/5: Checking package manager and git"

# Check for git (comes with Xcode tools, but verify)
if ! command -v git &>/dev/null; then
    info "git not found — attempting to install via Homebrew..."
    if ! command -v brew &>/dev/null; then
        info "Installing Homebrew (this requires your password for sudo)..."
        if command -v curl &>/dev/null; then
            /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || {
                echo ""
                echo -e "${RED}Homebrew installation failed.${NC}"
                echo "  Manual install: https://brew.sh"
                echo "  Then run: brew install git"
                die "Homebrew install failed — cannot continue without git"
            }
            # Add Homebrew to PATH for this session
            if [ "${ARCH}" = "arm64" ]; then
                eval "$(/opt/homebrew/bin/brew shellenv)"
            else
                eval "$(/usr/local/bin/brew shellenv)"
            fi
            ok "Homebrew installed: $(brew --version | head -1)"
        else
            die "curl not found. Install curl first or install Xcode Command Line Tools."
        fi
    fi
    brew install git -q
fi

ok "git: $(git --version)"

# Verify curl is available (macOS ships with it)
if command -v curl &>/dev/null; then
    ok "curl: $(curl --version 2>/dev/null | head -1)"
else
    die "curl not found — macOS should include curl. Check your PATH."
fi

# Install Homebrew if not present (useful for future installs)
if ! command -v brew &>/dev/null; then
    info "Homebrew not found — it is optional but recommended for managing psql and other tools."
    warn "To install Homebrew later: /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
fi

# ── Step 4/5: Clone and build ──────────────────────────────────────────────────
step "Step 4/5: Downloading and building Absolute DB"

if [ -d "${INSTALL_DIR}/.git" ]; then
    info "Existing installation found — updating to v${VERSION}..."
    cd "${INSTALL_DIR}"
    git fetch origin "${BRANCH}" -q || die "git fetch failed — check your internet connection"
    git checkout "${BRANCH}" -q
    git reset --hard "origin/${BRANCH}" -q
    ok "Source updated to latest ${BRANCH}"
else
    [ -d "${INSTALL_DIR}" ] && rm -rf "${INSTALL_DIR}"
    info "Cloning Absolute DB from GitHub (30-90 seconds on first install)..."
    git clone --depth=1 --branch="${BRANCH}" "${REPO}" "${INSTALL_DIR}" || \
        die "git clone failed. Check: internet connection, firewall, VPN settings."
    ok "Source cloned to ${INSTALL_DIR}"
fi

cd "${INSTALL_DIR}"
info "Compiling (using $(sysctl -n hw.logicalcpu 2>/dev/null || echo 4) CPU cores)..."
make clean -s 2>/dev/null || true
make all -j"$(sysctl -n hw.logicalcpu 2>/dev/null || echo 4)" || \
    die "Build failed. Check output above. Common cause: Xcode tools update required."

# Verify build artifacts exist
[ -x "build/absdb" ]        || die "build/absdb not found after build"
[ -x "build/absdb-server" ] || die "build/absdb-server not found after build"
ok "Build complete"

# Run test suite (unless --no-test)
if [ "${OPT_NO_TEST}" -eq 0 ]; then
    info "Running test suite..."
    make test 2>&1 | tail -5 || warn "Some tests reported failures — check output above"
    ok "Test suite complete"
else
    info "Test suite skipped (--no-test)"
fi

# Install binaries
info "Installing binaries to ${BIN_DIR}..."
mkdir -p "${BIN_DIR}" 2>/dev/null || true

# Try without sudo first (Homebrew-managed /opt/homebrew is user-writable on Apple Silicon)
if [ -w "${BIN_DIR}" ]; then
    install -m 755 build/absdb        "${BIN_DIR}/absdb"
    install -m 755 build/absdb-server "${BIN_DIR}/absdb-server"
    install -m 755 build/absdb-bench  "${BIN_DIR}/absdb-bench" 2>/dev/null || true
else
    info "Directory ${BIN_DIR} requires sudo..."
    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" 2>/dev/null || true
fi

# Strip Gatekeeper quarantine attribute if present
xattr -d com.apple.quarantine "${BIN_DIR}/absdb"        2>/dev/null || true
xattr -d com.apple.quarantine "${BIN_DIR}/absdb-server" 2>/dev/null || true
xattr -d com.apple.quarantine "${BIN_DIR}/absdb-bench"  2>/dev/null || true

# Install headers and docs
if [ -w "${BIN_PREFIX}/include" ] 2>/dev/null || mkdir -p "${BIN_PREFIX}/include/absdb" 2>/dev/null; then
    mkdir -p "${BIN_PREFIX}/include/absdb" "${BIN_PREFIX}/share/doc/absdb" 2>/dev/null || true
    cp include/absolute.h include/adb_types.h "${BIN_PREFIX}/include/absdb/" 2>/dev/null || true
    cp README.md LICENSE "${BIN_PREFIX}/share/doc/absdb/" 2>/dev/null || true
fi

# Verify installed binaries actually run
"${BIN_DIR}/absdb" --version &>/dev/null        || warn "absdb --version failed — binary may need PATH update"
"${BIN_DIR}/absdb-server" --version &>/dev/null || warn "absdb-server --version failed — check ${BIN_DIR} is in PATH"
ok "Binaries installed and verified: ${BIN_DIR}/absdb, ${BIN_DIR}/absdb-server"

# Ensure BIN_DIR is in PATH
if ! echo ":${PATH}:" | grep -q ":${BIN_DIR}:"; then
    warn "${BIN_DIR} is not in your PATH."
    SHELL_NAME=$(basename "${SHELL:-bash}")
    if [ "${SHELL_NAME}" = "zsh" ]; then
        RCFILE="${HOME}/.zshrc"
    else
        RCFILE="${HOME}/.bash_profile"
    fi
    warn "Add to ${RCFILE}:"
    warn "  export PATH=\"${BIN_DIR}:\$PATH\""
    warn "Then run: source ${RCFILE}"
fi

# ── Step 5/5: LaunchAgent setup ───────────────────────────────────────────────
step "Step 5/5: Service setup"

mkdir -p "${DATA_DIR}"

if [ "${OPT_NO_SERVICE}" -eq 0 ]; then
    info "Creating LaunchAgent for auto-start on login..."
    mkdir -p "${HOME}/Library/LaunchAgents"

    cat > "${PLIST}" <<PLIST_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>--grpc-port</string>
    <string>${GRPC_PORT}</string>
    <string>-d</string>
    <string>${DATA_DIR}/data.db</string>
  </array>

  <key>RunAtLoad</key>
  <true/>

  <key>KeepAlive</key>
  <dict>
    <key>SuccessfulExit</key>
    <false/>
  </dict>

  <key>ThrottleInterval</key>
  <integer>10</integer>

  <key>StandardOutPath</key>
  <string>${DATA_DIR}/absdb.log</string>

  <key>StandardErrorPath</key>
  <string>${DATA_DIR}/absdb-error.log</string>

  <key>WorkingDirectory</key>
  <string>${DATA_DIR}</string>
</dict>
</plist>
PLIST_EOF

    # Unload any previous version, then load the new one
    launchctl unload "${PLIST}" 2>/dev/null || true
    launchctl load   "${PLIST}" || die "launchctl load failed. Check: log show --predicate 'subsystem == \"com.apple.xpc.launchd\"' --last 1m"
    ok "LaunchAgent loaded: ${PLIST}"

    # Wait for server to start (up to 15 seconds)
    info "Waiting for server to start..."
    STARTED=0
    for i in $(seq 1 15); do
        sleep 1
        if lsof -iTCP:"${PG_PORT}" -sTCP:LISTEN &>/dev/null 2>&1; then
            ok "Server is listening on port ${PG_PORT}"
            STARTED=1
            break
        fi
    done

    if [ "${STARTED}" -eq 0 ]; then
        warn "Server did not start within 15 seconds."
        warn "  Check LaunchAgent log: tail -f ${DATA_DIR}/absdb-error.log"
        warn "  Check system log: log show --predicate 'subsystem == \"com.apple.xpc.launchd\"' --last 2m"
        warn "  Port ${PG_PORT} in use? Run: lsof -i :${PG_PORT}"
    fi
else
    info "LaunchAgent setup skipped (--no-service)"
    info "To start manually:"
    info "  ${BIN_DIR}/absdb-server -p ${PG_PORT} -r ${REST_PORT} -d ${DATA_DIR}/data.db"
fi

# ── Health check ─────────────────────────────────────────────────────────────
if [ "${OPT_NO_SERVICE}" -eq 0 ]; then
    echo ""
    info "Testing REST API health endpoint..."
    REST_OK=0
    for i in $(seq 1 10); do
        sleep 1
        HEALTH=$(curl -sf --connect-timeout 2 "http://localhost:${REST_PORT}/health" 2>/dev/null || true)
        if echo "${HEALTH}" | grep -q '"status"'; then
            ok "REST API healthy: ${HEALTH}"
            REST_OK=1
            break
        fi
    done
    if [ "${REST_OK}" -eq 0 ]; then
        warn "REST API on port ${REST_PORT} did not respond within 10 seconds."
        warn "  Check logs: tail -f ${DATA_DIR}/absdb.log"
    fi
fi

# ── Final summary ─────────────────────────────────────────────────────────────
SHELL_NAME=$(basename "${SHELL:-bash}")
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}  Quick start:${NC}"
echo ""
echo -e "  ${CYN}REST API:${NC}"
echo "    curl http://localhost:${REST_PORT}/health"
echo "    curl -X POST http://localhost:${REST_PORT}/sql \\"
echo "      -H 'Content-Type: application/json' \\"
echo "      -d '{\"sql\":\"SELECT 1+1 AS result\"}'"
echo ""
echo -e "  ${CYN}PostgreSQL wire (psql):${NC}"
if command -v psql &>/dev/null; then
    echo "    psql -h localhost -p ${PG_PORT}"
else
    echo "    # Install psql first:"
    echo "    brew install libpq && brew link --force libpq"
    echo "    psql -h localhost -p ${PG_PORT}"
fi
echo ""
echo -e "  ${CYN}gRPC (port ${GRPC_PORT}):${NC}"
echo "    grpcurl -plaintext localhost:${GRPC_PORT} list"
echo ""
echo -e "  ${CYN}CLI:${NC}"
echo "    absdb                           # interactive shell"
echo "    absdb -c \"SELECT version()\"    # single query"
echo ""
echo -e "  ${CYN}Service management:${NC}"
echo "    launchctl list | grep absdb                       # check status"
echo "    launchctl unload  ${PLIST}   # stop"
echo "    launchctl load    ${PLIST}   # start"
echo "    tail -f ${DATA_DIR}/absdb.log                # view logs"
echo ""
echo -e "${BOLD}  Next steps:${NC}"
echo ""
echo -e "  ${YLW}1. macOS firewall:${NC} If you have the Application Firewall enabled"
echo -e "     (System Settings → Network → Firewall), allow absdb-server when prompted,"
echo -e "     or add it manually under Firewall Options."
echo ""
echo -e "  ${YLW}2. Default ports:${NC}"
echo -e "     ${DIM}PostgreSQL wire:${NC}  ${PG_PORT}    ${DIM}REST API + Web console:${NC}  ${REST_PORT}"
echo -e "     ${DIM}gRPC / HTTP/2:${NC}    ${GRPC_PORT}    ${DIM}Redis RESP3:${NC}             6379"
echo ""
echo -e "  ${YLW}3. Open the web management console:${NC}"
echo -e "     ${CYN}open http://localhost:${REST_PORT}/console${NC}"
echo ""
echo -e "  ${YLW}4. Enable TLS for production:${NC}"
echo -e "     See ${DIM}https://absolutedb.com/docs/tls${NC}"
echo ""
echo -e "  ${CYN}Uninstall:${NC}"
echo "    bash install-macos.sh --uninstall"
echo ""
echo -e "  ${CYN}Docs:${NC}  https://absolutedb.com/docs"
echo -e "  ${CYN}Support:${NC} https://absolutedb.com/support"
echo ""
