#!/usr/bin/env bash
# =============================================================================
# Maree-CareFlow - Bare Metal Installer (Ubuntu 22.04 / 24.04)
# =============================================================================
# Usage: sudo bash stack-baremetal/install.sh
# =============================================================================
set -euo pipefail

LOG=/tmp/careflow-baremetal-install.log
exec > >(tee -a "$LOG") 2>&1

# ── Colour helpers ────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'

ok()   { echo -e "${GREEN}  ✔  $*${NC}"; }
info() { echo -e "${CYAN}  ℹ  $*${NC}"; }
warn() { echo -e "${YELLOW}  ⚠  $*${NC}"; }
err()  { echo -e "${RED}  ✘  $*${NC}" >&2; exit 1; }
step() { echo -e "\n${BOLD}${CYAN}━━━  $*  ━━━${NC}"; }

# ── Runtime mode + secret-preservation helpers ────────────────────────────────
# CRITICAL DATA-SAFETY: PHI_ENCRYPTION_KEY decrypts every patient record already
# stored on this server. Rotating it on a re-run or upgrade would make all
# existing encrypted PHI permanently unreadable - a silent, catastrophic data
# loss. So this installer NEVER regenerates an encryption key that already
# exists: it reads the current value out of backend.env and reuses it verbatim
# (the same guarantee the JWT keypair already has), minting a fresh key only
# when none is present. Re-running the installer is therefore always safe.
ENV_FILE=/etc/maree-careflow/backend.env
UPGRADE_MODE=0

# Print the value of KEY=... from the existing env file (empty if absent). Only
# the leading "KEY=" is stripped, so base64 values containing =,+,/ survive.
cf_env() { [[ -f "$ENV_FILE" ]] && sed -n "s/^$1=//p" "$ENV_FILE" | head -n1 || true; }

# Extract the DB password embedded in the existing DATABASE_URL (empty if absent).
cf_db_pass() {
  [[ -f "$ENV_FILE" ]] || return 0
  sed -n 's#^DATABASE_URL=postgresql+asyncpg://careflow:\(.*\)@localhost.*#\1#p' "$ENV_FILE" | head -n1
}

for arg in "$@"; do
  case "$arg" in
    --upgrade) UPGRADE_MODE=1 ;;
    -h|--help)
      echo "Usage: sudo bash $0 [--upgrade]"
      echo ""
      echo "  (no flag)   Fresh install, or a safe re-run. Existing encryption keys,"
      echo "              secrets, database and data are always preserved when present."
      echo "  --upgrade   Update an existing install in place: refresh code, Python"
      echo "              dependencies, run database migrations and restart services,"
      echo "              reusing the existing configuration and keys unchanged."
      exit 0 ;;
    *) echo "Unknown argument: $arg (try --help)" >&2; exit 1 ;;
  esac
done

# ── Banner ────────────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}${CYAN}"
echo "  ╔════════════════════════════════════════════════════╗"
echo "  ║        Maree-CareFlow Installer                    ║"
echo "  ║        Ubuntu 22.04 / 24.04 - Bare Metal          ║"
echo "  ╚════════════════════════════════════════════════════╝"
echo -e "${NC}"

# ── 1. Check root ──────────────────────────────────────────────────────────────
if [[ $EUID -ne 0 ]]; then
  err "This script must be run as root. Try: sudo bash $0"
fi

# ── 2. apt update + base packages ─────────────────────────────────────────────
step "1/28 - Updating apt and installing base packages"
apt-get update -y
apt-get install -y \
  curl \
  git \
  jq \
  gcc \
  build-essential \
  libssl-dev \
  libffi-dev \
  python3.12 \
  python3.12-venv \
  python3.12-dev \
  nginx \
  gnupg \
  lsb-release \
  ca-certificates \
  apt-transport-https \
  software-properties-common \
  rsync
ok "Base packages installed"

# ── 3. PostgreSQL 16 ──────────────────────────────────────────────────────────
step "2/28 - Installing PostgreSQL 16"
if ! command -v psql &>/dev/null; then
  curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc \
    | gpg --dearmor -o /usr/share/keyrings/postgresql-archive-keyring.gpg
  echo "deb [signed-by=/usr/share/keyrings/postgresql-archive-keyring.gpg] \
https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" \
    > /etc/apt/sources.list.d/pgdg.list
  apt-get update -y
  # postgresql-16-pgvector supplies the "vector" extension the schema REQUIRES
  # (AI semantic search embeddings). Without it, CREATE EXTENSION vector - and
  # therefore the database migrations - fail on a fresh server.
  apt-get install -y postgresql-16 postgresql-contrib-16 postgresql-16-pgvector
  ok "PostgreSQL 16 installed (incl. contrib + pgvector)"
else
  ok "PostgreSQL already installed: $(psql --version)"
  # Belt-and-braces: a pre-existing PostgreSQL may lack the pgvector package.
  # Best-effort install for the detected major version; the per-extension
  # check further below is the real gate and prints exact fix instructions.
  PG_MAJOR=$(psql --version | grep -oE '[0-9]+' | head -1)
  apt-get install -y "postgresql-${PG_MAJOR}-pgvector" "postgresql-contrib-${PG_MAJOR}" 2>/dev/null \
    || warn "Could not auto-install postgresql-${PG_MAJOR}-pgvector - availability is verified below"
fi

# ── 4. Redis 7 ────────────────────────────────────────────────────────────────
step "3/28 - Installing Redis 7"
if ! command -v redis-server &>/dev/null; then
  curl -fsSL https://packages.redis.io/gpg \
    | gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
  echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] \
https://packages.redis.io/deb $(lsb_release -cs) main" \
    > /etc/apt/sources.list.d/redis.list
  apt-get update -y
  apt-get install -y redis
  ok "Redis installed"
else
  ok "Redis already installed"
fi

# ── 5. Node.js 24 ─────────────────────────────────────────────────────────────
step "4/28 - Installing Node.js 24"
if ! command -v node &>/dev/null || [[ "$(node --version | cut -d. -f1 | tr -d 'v')" -lt 24 ]]; then
  curl -fsSL https://deb.nodesource.com/setup_24.x | bash -
  apt-get install -y nodejs
  ok "Node.js $(node --version) installed"
else
  ok "Node.js $(node --version) already installed"
fi

# ── 6. System users ───────────────────────────────────────────────────────────
step "5/28 - Creating system users"
for sysuser in careflow ollama minio; do
  if ! id "$sysuser" &>/dev/null; then
    useradd -r -s /sbin/nologin "$sysuser"
    ok "Created user: $sysuser"
  else
    ok "User already exists: $sysuser"
  fi
done

# ── 7. Directories ────────────────────────────────────────────────────────────
step "6/28 - Creating directories"
mkdir -p \
  /opt/maree-careflow \
  /etc/maree-careflow \
  /var/lib/minio/data \
  /var/lib/ollama/models \
  /var/www/maree-careflow/dist
ok "Directories created"

# ── 8. Clone / copy repo ──────────────────────────────────────────────────────
step "7/28 - Installing application source"
if [[ -n "${CAREFLOW_SOURCE_DIR:-}" && -d "${CAREFLOW_SOURCE_DIR}" ]]; then
  info "Copying from CAREFLOW_SOURCE_DIR=${CAREFLOW_SOURCE_DIR}"
  rsync -a --exclude='.git' "${CAREFLOW_SOURCE_DIR}/" /opt/maree-careflow/
elif [[ -d "$(dirname "$(realpath "$0")")/../backend" ]]; then
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
  REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
  info "Copying from repo at: ${REPO_ROOT}"
  rsync -a --exclude='.git' --exclude='node_modules' --exclude='__pycache__' \
    --exclude='*.pyc' --exclude='.env' --exclude='venv' \
    "${REPO_ROOT}/" /opt/maree-careflow/
  ok "Files copied from local repo"
else
  if [[ -d /opt/maree-careflow/.git ]]; then
    info "Repo already exists - pulling latest..."
    git -C /opt/maree-careflow pull origin main
  else
    info "Cloning from GitHub..."
    git clone https://github.com/supportcall/Maree-CareFlow-2026.git /opt/maree-careflow
  fi
fi
ok "Application source installed"

# ── 9. Python virtualenv ──────────────────────────────────────────────────────
step "8/28 - Setting up Python virtualenv"
python3.12 -m venv /opt/maree-careflow/venv
/opt/maree-careflow/venv/bin/pip install --upgrade pip wheel setuptools --quiet
info "Installing Python packages (this takes 2-5 minutes)..."
/opt/maree-careflow/venv/bin/pip install -r /opt/maree-careflow/backend/requirements.txt --quiet
ok "Python packages installed"

# ── 10. Ollama ────────────────────────────────────────────────────────────────
step "9/28 - Installing Ollama"
if ! command -v ollama &>/dev/null; then
  export OLLAMA_HOME=/var/lib/ollama
  curl -fsSL https://ollama.ai/install.sh | OLLAMA_HOME=/var/lib/ollama sh
  ok "Ollama installed"
else
  ok "Ollama already installed"
fi

# ── 11. MinIO ─────────────────────────────────────────────────────────────────
step "10/28 - Installing MinIO server"
if [[ ! -f /usr/local/bin/minio ]]; then
  curl -fsSL https://dl.min.io/server/minio/release/linux-amd64/minio \
    -o /usr/local/bin/minio
  chmod +x /usr/local/bin/minio
  ok "MinIO server installed"
else
  ok "MinIO already installed"
fi

if [[ ! -f /usr/local/bin/mc ]]; then
  curl -fsSL https://dl.min.io/client/mc/release/linux-amd64/mc \
    -o /usr/local/bin/mc
  chmod +x /usr/local/bin/mc
  ok "MinIO client (mc) installed"
else
  ok "MinIO client already installed"
fi

# ── 12. Caddy 2 ───────────────────────────────────────────────────────────────
step "11/28 - Installing Caddy 2"
if ! command -v caddy &>/dev/null; then
  curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
    | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
  curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
    > /etc/apt/sources.list.d/caddy-stable.list
  apt-get update -y
  apt-get install -y caddy
  ok "Caddy installed"
else
  ok "Caddy already installed"
fi

# ── 13. Interactive prompts (or reuse existing config in --upgrade) ────────────
if [[ "$UPGRADE_MODE" -eq 1 ]]; then
  [[ -f "$ENV_FILE" ]] || err "--upgrade needs an existing install, but ${ENV_FILE} was not found.
     Run the installer without --upgrade to perform a fresh install first."
  step "Upgrade mode - reusing existing configuration (no prompts; nothing regenerated)"
  DOMAIN="$(cf_env ALLOWED_HOSTS | cut -d, -f1)"; DOMAIN="${DOMAIN:-maree-careflow.com.au}"
  DB_PASSWORD="$(cf_db_pass)"
  [[ -n "$DB_PASSWORD" ]] || err "Could not read the existing database password from ${ENV_FILE}."
  ADMIN_EMAIL="$(cf_env ADMIN_EMAIL)"
  SMTP_HOST="$(cf_env SMTP_HOST)"
  SMTP_PORT="$(cf_env SMTP_PORT)"; SMTP_PORT="${SMTP_PORT:-587}"
  SMTP_USER="$(cf_env SMTP_USER)"; SMTP_USER="${SMTP_USER:-${ADMIN_EMAIL}}"
  SMTP_PASSWORD="$(cf_env SMTP_PASSWORD)"; SMTP_PASSWORD="${SMTP_PASSWORD:-CHANGE_ME}"
  INSTALL_MODELS=n
  ok "Domain: ${DOMAIN}   Admin: ${ADMIN_EMAIL}   (existing config + keys preserved)"
else
  echo ""
  step "Configuration - answer each question (press Enter for default)"
  echo ""

  # On a re-run, default the domain and DB password to the values already in
  # backend.env so pressing Enter keeps the working credential instead of
  # minting a new one that would not match the existing PostgreSQL role.
  DEFAULT_DOMAIN="$(cf_env ALLOWED_HOSTS | cut -d, -f1)"; DEFAULT_DOMAIN="${DEFAULT_DOMAIN:-maree-careflow.com.au}"
  DEFAULT_DB_PASS="$(cf_db_pass)"
  DEFAULT_DB_PASS="${DEFAULT_DB_PASS:-$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c24)}"

  read -r -p "  Domain name [${DEFAULT_DOMAIN}]: " DOMAIN_INPUT
  DOMAIN="${DOMAIN_INPUT:-${DEFAULT_DOMAIN}}"
  ok "Domain: ${DOMAIN}"

  read -r -p "  Database password [${DEFAULT_DB_PASS}]: " DB_PASSWORD_INPUT
  DB_PASSWORD="${DB_PASSWORD_INPUT:-${DEFAULT_DB_PASS}}"

  read -r -p "  Admin email: " ADMIN_EMAIL
  [[ -n "$ADMIN_EMAIL" ]] || err "Admin email cannot be empty"
  ok "Admin email: ${ADMIN_EMAIL}"

  read -r -p "  SMTP host [skip - configure later]: " SMTP_HOST
  SMTP_HOST="${SMTP_HOST:-}"

  read -r -p "  SMTP port [587]: " SMTP_PORT_INPUT
  SMTP_PORT="${SMTP_PORT_INPUT:-587}"

  read -r -p "  SMTP username [${ADMIN_EMAIL}]: " SMTP_USER_INPUT
  SMTP_USER="${SMTP_USER_INPUT:-${ADMIN_EMAIL}}"

  if [[ -n "$SMTP_HOST" ]]; then
    read -r -p "  SMTP password: " SMTP_PASSWORD
  else
    SMTP_PASSWORD="CHANGE_ME"
  fi

  echo ""
  echo -e "  ${YELLOW}Ollama AI models enable clinical note summarisation.${NC}"
  echo -e "  ${YELLOW}Models are 4-8 GB each - download takes 5-20 minutes on a fast connection.${NC}"
  read -r -p "  Pull Ollama AI models now? [n - skip, download later]: " INSTALL_MODELS_INPUT
  INSTALL_MODELS="${INSTALL_MODELS_INPUT:-n}"
fi

echo ""
info "Proceeding with installation..."
echo ""

# ── 14. Generate JWT RSA keypair ──────────────────────────────────────────────
step "12/28 - Generating JWT RSA keypair"
if [[ ! -f /etc/maree-careflow/jwt_private.pem ]]; then
  openssl genrsa -out /etc/maree-careflow/jwt_private.pem 2048 2>/dev/null
  openssl rsa \
    -in /etc/maree-careflow/jwt_private.pem \
    -pubout \
    -out /etc/maree-careflow/jwt_public.pem 2>/dev/null
  chmod 600 /etc/maree-careflow/jwt_private.pem
  chmod 644 /etc/maree-careflow/jwt_public.pem
  ok "JWT RS256 key pair generated"
else
  ok "JWT keys already exist - reusing"
fi

# ── 15. Generate (or REUSE) secret keys ───────────────────────────────────────
# See the data-safety note at the top of this script: any encryption key that is
# already present in backend.env is REUSED verbatim, never rotated, so PHI (and
# TOTP/OAuth secrets) already stored on this server stay decryptable across every
# re-run and --upgrade. Fresh keys are minted only for values not yet present.
step "13/28 - Generating (or reusing) secret keys"
TOTP_KEY="$(cf_env TOTP_ENCRYPTION_KEY)";    TOTP_KEY="${TOTP_KEY:-$(openssl rand -base64 32)}"
PHI_KEY="$(cf_env PHI_ENCRYPTION_KEY)";       PHI_KEY="${PHI_KEY:-$(openssl rand -base64 32)}"
OAUTH_KEY="$(cf_env OAUTH_ENCRYPTION_KEY)";   OAUTH_KEY="${OAUTH_KEY:-$(openssl rand -base64 32)}"
SECRET_KEY="$(cf_env SECRET_KEY)";            SECRET_KEY="${SECRET_KEY:-$(openssl rand -base64 48)}"
MINIO_ROOT_USER="$(cf_env MINIO_ROOT_USER)";  MINIO_ROOT_USER="${MINIO_ROOT_USER:-careflow_minio}"
MINIO_ROOT_PASSWORD="$(cf_env MINIO_ROOT_PASSWORD)"
MINIO_ROOT_PASSWORD="${MINIO_ROOT_PASSWORD:-$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c32)}"
if [[ -f "$ENV_FILE" ]]; then
  ok "Existing secret keys reused - PHI/TOTP/OAuth encryption keys NOT rotated (stored data stays readable)"
else
  ok "Secret keys generated"
fi

# ── 16. Configure PostgreSQL ──────────────────────────────────────────────────
step "14/28 - Configuring PostgreSQL"
systemctl start postgresql

sudo -u postgres psql -tc "SELECT 1 FROM pg_roles WHERE rolname='careflow'" | grep -q 1 || \
  sudo -u postgres psql -c "CREATE USER careflow WITH PASSWORD '${DB_PASSWORD}';"

sudo -u postgres psql -tc "SELECT 1 FROM pg_database WHERE datname='maree_careflow'" | grep -q 1 || \
  sudo -u postgres psql -c "CREATE DATABASE maree_careflow OWNER careflow;"

sudo -u postgres psql -d maree_careflow -c "GRANT ALL PRIVILEGES ON DATABASE maree_careflow TO careflow;"

# Create each required extension in its OWN psql call. A single multi-statement
# psql -c runs as ONE transaction, so one unavailable extension would silently
# roll back ALL of them and the install would die later, mid-migration, with a
# confusing error. Per-statement creation isolates failures, and the explicit
# "vector" gate below fails fast with the exact fix if pgvector is missing.
# Enabling an extension applies ONLY to this database - it cannot affect any
# other database, cPanel account, or hosted domain on the server.
for ext in "uuid-ossp" "pgcrypto" "pg_trgm"; do
  sudo -u postgres psql -d maree_careflow -c "CREATE EXTENSION IF NOT EXISTS \"${ext}\";"
done
if ! sudo -u postgres psql -d maree_careflow -c 'CREATE EXTENSION IF NOT EXISTS "vector";'; then
  err "The pgvector (\"vector\") PostgreSQL extension is not available on this server.
     The Maree-CareFlow schema requires it. Fix (as root), matching your PostgreSQL major version:
         apt-get install -y postgresql-16-pgvector
     Then re-run this installer - it is safe to re-run."
fi
ok "PostgreSQL configured (uuid-ossp, pgcrypto, pg_trgm, vector enabled on maree_careflow only)"

# ── 17. Write backend.env ─────────────────────────────────────────────────────
step "15/28 - Writing /etc/maree-careflow/backend.env"
cat > /etc/maree-careflow/backend.env <<ENVFILE
# Maree-CareFlow Backend Environment
# Generated by install.sh on $(date -u +"%Y-%m-%d %H:%M:%S UTC")
# WARNING: Keep this file secret - do not commit to version control.

DATABASE_URL=postgresql+asyncpg://careflow:${DB_PASSWORD}@localhost:5432/maree_careflow
REDIS_URL=redis://localhost:6379/0

SECRET_KEY=${SECRET_KEY}
JWT_PRIVATE_KEY_FILE=/etc/maree-careflow/jwt_private.pem
JWT_PUBLIC_KEY_FILE=/etc/maree-careflow/jwt_public.pem
JWT_ALGORITHM=RS256
ACCESS_TOKEN_EXPIRE_MINUTES=15
REFRESH_TOKEN_EXPIRE_DAYS=30

TOTP_ENCRYPTION_KEY=${TOTP_KEY}
PHI_ENCRYPTION_KEY=${PHI_KEY}
OAUTH_ENCRYPTION_KEY=${OAUTH_KEY}

ADMIN_EMAIL=${ADMIN_EMAIL}

SMTP_HOST=${SMTP_HOST}
SMTP_PORT=${SMTP_PORT}
SMTP_USER=${SMTP_USER}
SMTP_PASSWORD=${SMTP_PASSWORD}
SMTP_FROM_EMAIL=${ADMIN_EMAIL}
SMTP_TLS=true

MINIO_ENDPOINT=localhost:9000
MINIO_ROOT_USER=${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
MINIO_BUCKET_NAME=maree-careflow
MINIO_SECURE=false

OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=qwen2.5:7b
OLLAMA_EMBED_MODEL=nomic-embed-text

ENVIRONMENT=production
DEBUG=false
LOG_LEVEL=info
CORS_ORIGINS=https://${DOMAIN}
ALLOWED_HOSTS=${DOMAIN},localhost

CAREFLOW_AI_ENABLED=false

CELERY_BROKER_URL=redis://localhost:6379/1
CELERY_RESULT_BACKEND=redis://localhost:6379/2
ENVFILE

chmod 640 /etc/maree-careflow/backend.env
ok "backend.env written"

# ── 18. Write MinIO env ───────────────────────────────────────────────────────
step "16/28 - Writing /etc/minio/minio.env"
mkdir -p /etc/minio
cat > /etc/minio/minio.env <<MINIOENV
MINIO_ROOT_USER=${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
MINIO_VOLUMES=/var/lib/minio/data
MINIO_OPTS="--console-address :9001"
MINIOENV
chmod 640 /etc/minio/minio.env
chown minio:minio /etc/minio/minio.env 2>/dev/null || true
ok "MinIO env written"

# ── 19. Write Caddyfile ───────────────────────────────────────────────────────
step "17/28 - Writing Caddyfile"
CADDYFILE_TPL=/opt/maree-careflow/stack-baremetal/Caddyfile.template
if [[ -f "$CADDYFILE_TPL" ]]; then
  sed "s/__DOMAIN__/${DOMAIN}/g" "$CADDYFILE_TPL" > /etc/caddy/Caddyfile
  ok "Caddyfile written from template"
else
  cat > /etc/caddy/Caddyfile <<CADDYFILE
${DOMAIN} {
  encode gzip

  header {
    Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    X-Content-Type-Options nosniff
    X-Frame-Options DENY
    X-XSS-Protection "1; mode=block"
    Referrer-Policy strict-origin-when-cross-origin
    Permissions-Policy "camera=(), microphone=(), geolocation=()"
    -Server
  }

  handle /api/* {
    reverse_proxy localhost:8000
  }

  handle /ws/* {
    reverse_proxy localhost:8000 {
      header_up Upgrade {>Upgrade}
      header_up Connection {>Connection}
    }
  }

  handle {
    root * /var/www/maree-careflow/dist
    try_files {path} /index.html
    file_server
  }
}
CADDYFILE
  ok "Caddyfile written"
fi

# ── 20. Systemd unit files ────────────────────────────────────────────────────
step "18/28 - Installing systemd unit files"
SYSTEMD_SRC=/opt/maree-careflow/stack-baremetal/systemd
if [[ -d "$SYSTEMD_SRC" ]]; then
  cp "$SYSTEMD_SRC"/*.service /etc/systemd/system/
  ok "Systemd unit files installed"
else
  warn "Systemd unit files not found at $SYSTEMD_SRC - skipping"
fi

# ── 21. systemctl daemon-reload ───────────────────────────────────────────────
step "19/28 - Reloading systemd"
systemctl daemon-reload
ok "systemd reloaded"

# ── 22. Enable services ───────────────────────────────────────────────────────
step "20/28 - Enabling services"
systemctl enable postgresql redis-server minio ollama \
  careflow-api careflow-worker careflow-beat caddy 2>/dev/null || true
ok "Services enabled"

step "21/28 - Starting base services"
systemctl start postgresql redis-server
systemctl start minio   || warn "minio failed to start - check: journalctl -u minio -n 20"
systemctl start ollama  || warn "ollama failed to start - check: journalctl -u ollama -n 20"
systemctl start caddy   || warn "caddy failed to start - check: journalctl -u caddy -n 20"
ok "Base services started"

# ── 23. Run database migrations ───────────────────────────────────────────────
step "22/28 - Running database migrations"
sleep 3
cd /opt/maree-careflow/backend
/opt/maree-careflow/venv/bin/alembic upgrade head
ok "Migrations complete"

# ── 24. Build frontend ────────────────────────────────────────────────────────
step "23/28 - Building frontend"
cd /opt/maree-careflow/frontend
npm install --prefer-offline --quiet
npm run build
rsync -a dist/ /var/www/maree-careflow/dist/
ok "Frontend built and deployed"

# ── 25. Start application services ───────────────────────────────────────────
step "24/28 - Starting application services"
systemctl start careflow-api
sleep 5
systemctl start careflow-worker careflow-beat
ok "Application services started"

# ── 26. Wait for backend ──────────────────────────────────────────────────────
step "25/28 - Waiting for backend to be ready"
RETRY=0
MAX_RETRIES=30
until curl -sf http://localhost:8000/api/v1/health &>/dev/null; do
  RETRY=$((RETRY + 1))
  if [[ $RETRY -ge $MAX_RETRIES ]]; then
    warn "Backend did not respond after ${MAX_RETRIES} attempts."
    warn "Check logs: journalctl -u careflow-api -n 50"
    break
  fi
  printf "  ${CYAN}  [%2d/%d] waiting...${NC}\r" "$RETRY" "$MAX_RETRIES"
  sleep 3
done
echo ""

# ── 27. Pull Ollama models ────────────────────────────────────────────────────
step "26/28 - Ollama AI models"
if [[ "${INSTALL_MODELS,,}" == "y" || "${INSTALL_MODELS,,}" == "yes" ]]; then
  info "Pulling qwen2.5:7b (~4.7 GB)..."
  /usr/bin/ollama pull qwen2.5:7b     || warn "Failed to pull qwen2.5:7b - retry: ollama pull qwen2.5:7b"
  info "Pulling nomic-embed-text (~274 MB)..."
  /usr/bin/ollama pull nomic-embed-text || warn "Failed to pull nomic-embed-text"
  info "Pulling llava:7b (~4.1 GB)..."
  /usr/bin/ollama pull llava:7b        || warn "Failed to pull llava:7b"
  ok "AI models downloaded"
else
  info "Skipping AI model download."
  info "Pull later with: ollama pull qwen2.5:7b && ollama pull nomic-embed-text"
fi

# ── 28. Set file permissions ──────────────────────────────────────────────────
step "27/28 - Setting file permissions"
chown -R careflow:careflow /opt/maree-careflow /etc/maree-careflow
chown -R minio:minio /var/lib/minio 2>/dev/null || true
chown -R ollama:ollama /var/lib/ollama 2>/dev/null || true
chown -R www-data:www-data /var/www/maree-careflow 2>/dev/null || true
chmod 640 /etc/maree-careflow/backend.env
chmod 600 /etc/maree-careflow/jwt_private.pem
ok "Permissions set"

# ── Configure MinIO bucket ────────────────────────────────────────────────────
step "28/28 - Configuring MinIO buckets"
sleep 2
/usr/local/bin/mc alias set local \
  http://localhost:9000 \
  "${MINIO_ROOT_USER}" \
  "${MINIO_ROOT_PASSWORD}" 2>/dev/null || true
/usr/local/bin/mc mb local/maree-careflow          2>/dev/null || true
/usr/local/bin/mc mb local/maree-careflow-backups  2>/dev/null || true
ok "MinIO buckets configured"

# ── Done ──────────────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}${GREEN}"
echo "  ╔════════════════════════════════════════════════════════════════════╗"
echo "  ║        Maree-CareFlow installed successfully!                      ║"
echo "  ╚════════════════════════════════════════════════════════════════════╝"
echo -e "${NC}"
echo -e "  ${BOLD}Application URL:${NC}  https://${DOMAIN}"
echo -e "  ${BOLD}Admin email:${NC}      ${ADMIN_EMAIL}"
echo ""
echo -e "  ${CYAN}First-time setup:${NC}"
echo "    Visit https://${DOMAIN}/admin to complete onboarding."
echo ""
echo -e "  ${CYAN}Service status:${NC}"
for svc in postgresql redis-server minio ollama careflow-api careflow-worker careflow-beat caddy; do
  STATUS=$(systemctl is-active "$svc" 2>/dev/null || echo "unknown")
  if [[ "$STATUS" == "active" ]]; then
    echo -e "    ${GREEN}${svc}: ${STATUS}${NC}"
  else
    echo -e "    ${YELLOW}${svc}: ${STATUS}${NC}"
  fi
done
echo ""
echo -e "  ${CYAN}Useful commands:${NC}"
echo "    journalctl -u careflow-api    -f   # API logs"
echo "    journalctl -u careflow-worker -f   # worker logs"
echo "    systemctl restart careflow-api     # restart API"
echo ""
echo -e "  ${CYAN}Install log:${NC}  ${LOG}"
echo ""
