#!/bin/bash
#
# CloudFigma / CloudWatch Pro — one-command install / fix / uninstall / verify.
#
# Every command is a single line (run as root on a cPanel/WHM server):
#
#   INSTALL collector (control plane + console + agent + tripwire + shield + portal):
#     bash <(curl -fsSL https://cwp.cloudfigma.com/bootstrap.sh) collector
#
#   INSTALL agent (reports to the collector):
#     bash <(curl -fsSL https://cwp.cloudfigma.com/bootstrap.sh) agent \
#          --collector https://cwp.host.example.com [--secret <hex>] [--id <fqdn>]
#
#   FIX (re-apply everything idempotently, restart services, then verify):
#     bash <(curl -fsSL https://cwp.cloudfigma.com/bootstrap.sh) fix
#
#   UNINSTALL (remove services/crons/plugins; add --purge to also drop data/config):
#     bash <(curl -fsSL https://cwp.cloudfigma.com/bootstrap.sh) uninstall [--purge]
#
#   VERIFY (read-only health check — DB, services, crons, live sync):
#     bash <(curl -fsSL https://cwp.cloudfigma.com/bootstrap.sh) verify
#
# Downloads a prebuilt release (no Go needed on the target), runs every installer
# in the right order, wires the configs, and leaves everything in DRY-RUN.
set -euo pipefail

BASE_URL="${CWP_BASE_URL:-https://cwp.cloudfigma.com}"
RELEASE="${CWP_RELEASE:-cwp-release.tar.gz}"
ALERT_EMAIL="${CWP_ALERT_EMAIL:-alerts@cloudfigma.com}"
SRC="/opt/cwp/src"

die(){ printf '\nERROR: %s\n' "$*" >&2; exit 1; }
info(){ printf '==> %s\n' "$*"; }

# ---- verify: read-only health check (no download, no changes) ----
do_verify(){
  info "CloudFigma verify — health check"
  local ok=1
  if [[ -d /home/cwp/cwp-config ]]; then
    if [[ -f /home/cwp/cwp-data/findings.sqlite ]]; then
      local n="?"; command -v sqlite3 >/dev/null && \
        n="$(sqlite3 /home/cwp/cwp-data/findings.sqlite 'SELECT COUNT(*) FROM findings' 2>/dev/null || echo '?')"
      info "  collector DB: present ($n findings)"
    else
      info "  collector DB: MISSING — run: bootstrap.sh fix"; ok=0
    fi
  fi
  local svc
  for svc in cwp-agent cwp-tripwire; do
    if systemctl is-active --quiet "$svc" 2>/dev/null; then info "  service $svc: active"
    elif systemctl list-unit-files 2>/dev/null | grep -q "^${svc}\.service"; then info "  service $svc: installed but NOT running"; ok=0
    else info "  service $svc: not installed"; fi
  done
  local ncron; ncron="$(find /etc/cron.d -name 'cwp-*' 2>/dev/null | wc -l | tr -d ' ')"
  info "  cron jobs: ${ncron} in /etc/cron.d"
  if [[ -x /opt/cwp/agent/sync/cwp-sync ]]; then
    if /opt/cwp/agent/sync/cwp-sync --verbose 2>&1 | grep -qE 'status=200|complete: success|local ingest ok'; then
      info "  sync/ingest: OK"
    else
      info "  sync/ingest: FAILED — run: /opt/cwp/agent/sync/cwp-sync --verbose"; ok=0
    fi
  fi
  [[ "$ok" -eq 1 ]] && info "verify: HEALTHY" || info "verify: issues above — try: bootstrap.sh fix"
}

# ---- uninstall: remove everything (data kept unless --purge) ----
do_uninstall(){
  info "CloudFigma uninstall"
  [[ -f installer/install-agent.sh ]]                        && bash installer/install-agent.sh --uninstall 2>/dev/null || true
  [[ -x /opt/cwp/bin/deploy-shield.sh ]]                     && /opt/cwp/bin/deploy-shield.sh --remove 2>/dev/null || true
  [[ -f control-plane/whm-plugin/install-whm-plugin.sh ]]    && bash control-plane/whm-plugin/install-whm-plugin.sh --uninstall 2>/dev/null || true
  [[ -f control-plane/whm-plugin/install-client-portal.sh ]] && bash control-plane/whm-plugin/install-client-portal.sh --uninstall 2>/dev/null || true
  rm -f /etc/cron.d/cwp-* 2>/dev/null || true
  if [[ "${PURGE:-0}" -eq 1 ]]; then
    info "  --purge: removing /var/cwp /etc/cwp /opt/cwp"
    rm -rf /var/cwp /etc/cwp /opt/cwp 2>/dev/null || true
    info "  NOTE: collector data (/home/cwp/cwp-data) and the 'cwp' cPanel account are kept — remove the account in WHM to fully purge."
  else
    info "  kept data + configs. Re-run with 'uninstall --purge' to also remove /var/cwp /etc/cwp /opt/cwp."
  fi
  info "uninstall complete"
}

# ---- fix: re-apply the install idempotently, restart services, verify ----
do_fix(){
  info "CloudFigma fix — repairing this install"
  if [[ -d /home/cwp/cwp-config ]]; then
    info "  collector detected — repairing control plane + console + portal"
    bash control-plane/install-primary.sh                   || info "  (install-primary reported an issue)"
    bash control-plane/whm-plugin/install-whm-plugin.sh     || info "  (whm-plugin reported an issue)"
    bash control-plane/whm-plugin/install-client-portal.sh  || info "  (client-portal reported an issue)"
  fi
  bash installer/install-agent.sh || info "  (install-agent reported an issue)"
  systemctl daemon-reload 2>/dev/null || true
  local svc
  for svc in cwp-agent cwp-tripwire; do
    systemctl list-unit-files 2>/dev/null | grep -q "^${svc}\.service" && systemctl restart "$svc" 2>/dev/null || true
  done
  systemctl reload crond 2>/dev/null || systemctl reload cron 2>/dev/null || true
  info "fix complete — verifying"
  do_verify
}

CMD="${1:-}"; shift 2>/dev/null || true
COLLECTOR=""; SERVER_ID="$(hostname -f 2>/dev/null || hostname)"; SECRET=""; PURGE=0
while [[ $# -gt 0 ]]; do case "$1" in
  --collector) COLLECTOR="${2%/}"; shift 2;;
  --secret)    SECRET="$2"; shift 2;;
  --id)        SERVER_ID="$2"; shift 2;;
  --base)      BASE_URL="${2%/}"; shift 2;;
  --purge)     PURGE=1; shift;;
  *) die "unknown flag: $1";;
esac; done

[[ "$(id -u)" -eq 0 ]] || die "run as root"
[[ -d /usr/local/cpanel ]] || die "this is not a cPanel/WHM server"
command -v curl >/dev/null || die "curl required"
case "$CMD" in
  collector|agent|fix|uninstall|verify) : ;;
  *) die "usage: bootstrap.sh {collector|agent|fix|uninstall|verify} [--collector URL --secret HEX --id FQDN --purge]";;
esac

# verify is read-only and needs nothing downloaded.
[[ "$CMD" == verify ]] && { do_verify; exit 0; }

# ---- 1. download + unpack the release (prebuilt binaries inside) ----
info "downloading CloudFigma release from $BASE_URL/$RELEASE"
tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' EXIT
curl -fsSL "$BASE_URL/$RELEASE" -o "$tmp/rel.tgz" || die "could not download $BASE_URL/$RELEASE"
install -d -m 0755 /opt/cwp
rm -rf "$SRC"; mkdir -p "$SRC"
tar xzf "$tmp/rel.tgz" -C "$SRC" --strip-components=1 || die "bad release archive"
cd "$SRC"

# fix + uninstall operate on the freshly-downloaded release, then exit.
[[ "$CMD" == uninstall ]] && { do_uninstall; exit 0; }
[[ "$CMD" == fix ]]       && { do_fix; exit 0; }

# ---- 2. collector role: control plane + console ----
if [[ "$CMD" == collector ]]; then
  HOST="$(hostname -f 2>/dev/null || hostname)"; CWPDOM="cwp.${HOST}"
  # whmapi1 always exits 0, so detect the account by its userdata file, not exit code.
  if [[ ! -e /var/cpanel/users/cwp ]]; then
    info "creating the 'cwp' cPanel account ($CWPDOM)"
    cwppw="$(openssl rand -base64 18)"
    ca_out="$(/usr/local/cpanel/bin/whmapi1 createacct username=cwp domain="$CWPDOM" \
              password="$cwppw" contactemail="$ALERT_EMAIL" 2>&1 || true)"
    if [[ ! -e /var/cpanel/users/cwp ]] && ! printf '%s\n' "$ca_out" | grep -qE 'result:[[:space:]]*1'; then
      die "could not auto-create the 'cwp' account. Create it in WHM → Create a New Account (user 'cwp', domain '$CWPDOM', any small plan), wait for AutoSSL, then re-run this same command. Detail: $(printf '%s\n' "$ca_out" | grep -iE 'reason|statusmsg' | head -1)"
    fi
    info "account created; triggering AutoSSL (cert may take a few minutes — the console works once it's live)"
    /usr/local/cpanel/bin/whmapi1 start_autossl_check username=cwp >/dev/null 2>&1 || true
  else
    info "'cwp' cPanel account already exists"
  fi
  info "installing control plane"
  bash control-plane/install-primary.sh
  COLLECTOR="https://${CWPDOM}"
  # reuse the starter secret install-primary generated for this server's identity
  SECRET="$(grep -oE "[a-f0-9]{64}" /home/cwp/cwp-config/primary.conf | head -1)"
  [[ -n "$SECRET" ]] || die "could not read the generated HMAC secret from primary.conf"
  info "installing WHM console plugin"
  bash control-plane/whm-plugin/install-whm-plugin.sh
fi

# ---- 3. agent role identity ----
[[ -n "$COLLECTOR" ]] || die "agent role requires --collector https://cwp.host.example.com"
if [[ -z "$SECRET" ]]; then
  SECRET="$(openssl rand -hex 32)"
  info "generated this server's secret. Enroll it ON THE COLLECTOR (one command), then this agent is trusted:"
  printf "      sudo bash control-plane/cwp-enroll.sh '%s' '%s'\n" "$SERVER_ID" "$SECRET"
fi

# ---- 4. telemetry agent (detectors + sync that ships findings) ----
info "installing telemetry agent + sync"
bash installer/install-agent.sh --no-resident
if [[ "$CMD" == collector ]]; then
  # The collector ingests its OWN findings straight into the local DB — no DNS,
  # no cert, no HMAC. So a totally fresh box shows real data the moment the
  # detectors run, with zero post-install steps.
  cat > /etc/cwp/sync.conf <<EOF
SERVER_ID="${SERVER_ID}"
LOCAL_INGEST="/home/cwp/cwp-config/ingest-local.php"
LOCAL_INGEST_PHP="/usr/local/cpanel/3rdparty/bin/php"
LOCAL_INGEST_USER="cwp"
FALLBACK_ALERT_EMAIL="${ALERT_EMAIL}"
EOF
else
  # A remote agent POSTs to the collector over HTTPS, authenticated by its secret.
  cat > /etc/cwp/sync.conf <<EOF
PRIMARY_URL="${COLLECTOR}/ingest.php"
SERVER_ID="${SERVER_ID}"
HMAC_SECRET="${SECRET}"
FALLBACK_ALERT_EMAIL="${ALERT_EMAIL}"
EOF
fi
chmod 0640 /etc/cwp/sync.conf

# ---- 5. resident Go agent (governor + mail/backdoor + tripwire) ----
# Non-fatal: if this fails, the 7 detectors + local ingest still work, so the box
# is useful. We never abort the whole install over one optional component.
info "installing resident agent + tripwire (dry-run)"
if ( cd agent && bash install-cwp-agent.sh ); then
  cat >> /etc/cwp/agent.conf <<EOF

# --- bootstrap overrides (last-wins) ---
SERVER_NAME=${SERVER_ID}
DRY_RUN=true
CONTROL_URL=${COLLECTOR}/commands.php
SERVER_ID=${SERVER_ID}
HMAC_SECRET=${SECRET}
EOF
  systemctl restart cwp-agent 2>/dev/null || true
else
  info "resident agent install failed — detectors + local ingest still work; re-run 'agent/install-cwp-agent.sh' later to add mail-shield/backdoor/tripwire"
fi

# ---- 6. customer portal ----
info "installing customer Security Center"
bash control-plane/whm-plugin/install-client-portal.sh || info "portal install needs a manual cPanel plugin-registration step (see its output)"

cat <<EOF

============================================================
 CloudFigma is installed on $(hostname -f) — running in DRY-RUN.
 Role: $CMD   Collector: $COLLECTOR

 Verify:
   systemctl status cwp-agent
   journalctl -u cwp-agent -f
   /opt/cwp/agent/sync/cwp-sync --verbose      # expect status=200
   WHM -> Plugins -> CloudWatch Pro
$( [[ "$CMD" == agent ]] && echo "
 REMEMBER: run the cwp-enroll.sh command (printed above) ON THE COLLECTOR,
 or sync will 401 and this server never appears." )

 It detects only. To enforce later, see docs/CANARY-RUNBOOK.md steps 9-10.
$( [[ "$CMD" == collector ]] && echo "
 This collector shows its OWN data immediately — it ingests locally, no DNS
 needed. Run a detector or wait for cron, then check the console.
 DNS + cert are only needed to add OTHER servers to the fleet:
     1) add a DNS A record:  cwp.$(hostname -f)  ->  this server's public IP
     2) issue the cert:      whmapi1 start_autossl_check username=cwp
 Then other servers POST to ${COLLECTOR}." )
============================================================
EOF
