#!/usr/bin/env bash
set -euo pipefail

# ── Deploy to shared cPanel hosting (CloudLinux Python Selector + Passenger) ──
#
# Target layout on the server (business122.web-hosting.com, SSH alias "jnc"):
#   ~/quill.nx.kg/                  ← addon docroot = PassengerAppRoot = code lives here
#   ~/quill.nx.kg/passenger_wsgi.py ← startup file (imports app.py:app as `application`)
#   ~/quill.nx.kg/f/.htaccess       ← selector-managed: routes URI /f to Passenger (DO NOT sync over)
#   ~/virtualenv/quill.nx.kg/3.13/  ← selector-managed virtualenv
#
# The app is reachable at https://quill.nx.kg/f (once DNS points at 192.64.117.115).
#
# Runtime config is loaded from the MySQL config_vars table. The only env vars
# that must be set in the cPanel Python Selector UI are MYSQL_* and
# FLASK_SECRET_KEY. This script seeds the rest from your local .env.
#
# Usage:
#   ./deploy.sh                    # sync code, no restart
#   ./deploy.sh -r                 # sync code and restart via CloudLinux selector
#   ./deploy.sh --start            # start the selector app (no code sync)
#   ./deploy.sh --stop             # stop the selector app (no code sync)
#   ./deploy.sh --restart          # same as -r

LOCAL_DIR="${LOCAL_DIR:-.}"
REMOTE_HOST="${REMOTE_HOST:-jnc}"
REMOTE_DIR="${REMOTE_DIR:-quill.nx.kg}"           # relative to remote $HOME
CPANEL_USER="${CPANEL_USER:-}"
SELECTOR_APP_ROOT="${SELECTOR_APP_ROOT:-}"
VENV="${VENV:-virtualenv/quill.nx.kg/3.13}"
SITE_IP="${SITE_IP:-192.64.117.115}"
SITE_URL="${SITE_URL:-https://quill.nx.kg/f}"

RSYNC_OPTS=(-avz --delete
  # never touch server-side state / selector-managed files
  --exclude='.env' --exclude='.htaccess' --exclude='f/' --exclude='tmp/' --exclude='logs/'
  --exclude='public/' --exclude='cgi-bin/' --exclude='.well-known/' --exclude='.ftpquota'
  --exclude='app.js' --exclude='package.json'
  # never upload local-only / sensitive / bulky files
  --exclude='.git' --exclude='__pycache__' --exclude='*.pyc' --exclude='.DS_Store'
  --exclude='venv' --exclude='.pb_data' --exclude='.pocketbase'
  --exclude='.code-review-graph' --exclude='.qwen' --exclude='signals_raw_180d.json'
  # runtime dialog cache is server-side state — never delete it on deploy
  --exclude='.dialogs_cache*.json'
)

log()  { echo "[$(date +'%H:%M:%S')] $*"; }
info() { log "ℹ  $*"; }
ok()   { log "✓  $*"; }
warn() { log "⚠  $*" >&2; }
err()  { log "✗ $*" >&2; exit 1; }

# Discover the cPanel user name if not provided.
_discover_cpanel_user() {
  if [[ -n "$CPANEL_USER" ]]; then
    echo "$CPANEL_USER"
    return
  fi
  local user
  user=$(ssh -q -o BatchMode=yes -o ConnectTimeout=8 "$REMOTE_HOST" 'whoami' 2>/dev/null) || true
  if [[ -n "$user" ]]; then
    echo "$user"
  else
    echo ""
  fi
}

# Discover the CloudLinux Python Selector app-root if not overridden.
_discover_selector_app_root() {
  if [[ -n "$SELECTOR_APP_ROOT" ]]; then
    echo "$SELECTOR_APP_ROOT"
    return
  fi
  local cpanel_user app_json homedir app_name
  cpanel_user=$(_discover_cpanel_user)
  [[ -n "$cpanel_user" ]] || { echo ""; return; }

  app_json=$(ssh -q "$REMOTE_HOST" "cloudlinux-selector get --json --interpreter python --user '$cpanel_user'" 2>/dev/null) || true
  [[ -n "$app_json" ]] || { echo ""; return; }

  # Parse the selector JSON: users.<user>.applications.<app>.
  app_root=$(python3 - "$cpanel_user" "$REMOTE_DIR" <<'PY' 2>/dev/null
import sys, json
try:
    user, remote_dir = sys.argv[1], sys.argv[2]
    data = json.load(sys.stdin)
    for ver in data.get("available_versions", {}).values():
        u = ver.get("users", {}).get(user, {})
        for app_name, app in u.get("applications", {}).items():
            if app_name == remote_dir or app.get("domain") == remote_dir or remote_dir in app_name:
                homedir = u.get("homedir", f"/home/{user}")
                print(f"{homedir}/{app_name}")
                sys.exit(0)
except Exception:
    pass
PY
<<< "$app_json")

  if [[ -n "$app_root" ]]; then
    echo "$app_root"
  else
    echo "/home/${cpanel_user}/${REMOTE_DIR}"
  fi
}

# Push MySQL/Flask env vars into the CloudLinux Python Selector.
_set_selector_env() {
  local env_file json cpanel_user app_root
  env_file="$LOCAL_DIR/.env"
  [[ -f "$env_file" ]] || { warn "No local .env found — cannot set selector env vars"; return; }

  cpanel_user=$(_discover_cpanel_user)
  [[ -n "$cpanel_user" ]] || { warn "Could not determine cPanel user — set CPANEL_USER"; return; }

  json=$(python3 "$LOCAL_DIR/scripts/selector_env.py" --env "$env_file") || {
    warn "Could not build selector env JSON (missing MYSQL_* / FLASK_SECRET_KEY?)"
    return
  }
  [[ -n "$json" ]] || { warn "Empty selector env JSON"; return; }

  app_root=$(_discover_selector_app_root)
  [[ -n "$app_root" ]] || { warn "Could not determine selector app-root"; return; }

  info "Setting CloudLinux Python Selector env vars (app-root: $app_root)…"
  if ssh -q "$REMOTE_HOST" "cloudlinux-selector set --json --interpreter python --user '$cpanel_user' --app-root '$app_root' --env-vars '$json'"; then
    ok "Selector env vars updated"
  else
    warn "Failed to update selector env vars"
  fi
}

START=false
STOP=false
RESTART=false
DRY_RUN=false
for arg in "$@"; do
  case "$arg" in
    --start)      START=true ;;
    --stop)       STOP=true ;;
    -r|--restart) RESTART=true ;;
    --dry-run)    DRY_RUN=true ;;
    -h|--help)    grep '^#' "$0" | head -25; exit 0 ;;
    *)            err "Unknown option: $arg (use --start, --stop, -r, --dry-run)" ;;
  esac
done

_selector_app_action() {
  local action=$1
  local cpanel_user app_root
  cpanel_user=$(_discover_cpanel_user)
  [[ -n "$cpanel_user" ]] || err "Could not determine cPanel user"
  app_root=$(_discover_selector_app_root)
  [[ -n "$app_root" ]] || err "Could not determine selector app-root"
  info "Running selector '${action}' for Passenger app…"
  if ssh -q "$REMOTE_HOST" "cloudlinux-selector ${action} --json --interpreter python --user '${cpanel_user}' --app-root '${app_root}'"; then
    ok "Selector ${action} complete"
  else
    warn "Selector ${action} command failed"
  fi
}

_health_check() {
  info "Health check:"
  curl -sk --resolve "quill.nx.kg:443:${SITE_IP}" "${SITE_URL}/api/health" && echo \
    || curl -sk "${SITE_URL}/api/health" && echo \
    || warn "Health check failed — is DNS pointing at ${SITE_IP}?"
}

[[ -f "$LOCAL_DIR/app.py" ]] || err "app.py not found in $LOCAL_DIR — run from the workspace root"

ssh -q -o BatchMode=yes -o ConnectTimeout=8 "$REMOTE_HOST" true 2>/dev/null \
  || err "Cannot SSH to $REMOTE_HOST (check ~/.ssh/config)"

if $STOP; then
  _selector_app_action stop
  exit 0
fi

if $START; then
  _selector_app_action start
  sleep 3
  _health_check
  exit 0
fi

info "Syncing → ${REMOTE_HOST}:~/${REMOTE_DIR}"
$DRY_RUN && RSYNC_OPTS+=("--dry-run") && info "DRY RUN"
rsync "${RSYNC_OPTS[@]}" -e ssh "$LOCAL_DIR/" "${REMOTE_HOST}:${REMOTE_DIR}/"
$DRY_RUN && exit 0
ok "Upload complete"

info "Installing dependencies in selector venv…"
ssh "$REMOTE_HOST" "${VENV}/bin/pip install --no-cache-dir -q -r ${REMOTE_DIR}/requirements.txt"
ok "Dependencies ready"

info "Applying database schema/migrations…"
python3 "$LOCAL_DIR/scripts/apply_schema.py" \
  --env "$LOCAL_DIR/.env" \
  --ssh-host "$REMOTE_HOST" \
  || warn "Schema apply failed — check MYSQL_* credentials and SSH access"

info "Seeding config_vars from local .env into remote database…"
python3 "$LOCAL_DIR/scripts/seed_config.py" \
  --env "$LOCAL_DIR/.env" \
  --ssh-host "$REMOTE_HOST" \
  --remote-dir "~/${REMOTE_DIR}" \
  --remote-python "${VENV}/bin/python" \
  || warn "Config seed failed — is the local .env present and are the MYSQL_* credentials correct?"

_set_selector_env

if $RESTART; then
  _selector_app_action restart
  sleep 3
  _health_check
fi

ok "Deploy complete"
