#!/usr/bin/env bash
# B-connex — Linux self-host installer (Debian/Ubuntu primary, RHEL/Alma/Rocky secondary).
# Idempotent. Run as root or with sudo. Re-runnable.
#
# Usage:
#   sudo bash scripts/install.sh                       # interactive
#   sudo BCX_DOMAIN=app.example.com BCX_NONINTERACTIVE=1 bash scripts/install.sh
#
# Env overrides:
#   BCX_DOMAIN           public hostname (default: localhost)
#   BCX_APP_DIR          install dir (default: current repo path)
#   BCX_DB_NAME          database name (default: bconnex)
#   BCX_DB_USER          database user (default: bconnex)
#   BCX_DB_PASS          database password (default: random 32 chars)
#   BCX_HTTP_PORT        nginx listen port (default: 80)
#   BCX_NO_NGINX=1       skip nginx vhost
#   BCX_NO_DB=1          skip MariaDB install + DB provisioning
#   BCX_NO_SYSTEMD=1     skip systemd unit (built-in server fallback)
#   BCX_NONINTERACTIVE=1 do not prompt; use defaults / env vars
#
# What it does:
#   1. Verifies/installs PHP 8.2+ with required extensions (pdo_mysql, mbstring, openssl, json, fileinfo, curl, intl).
#   2. Verifies/installs MariaDB (>= 10.5) and provisions DB + scoped user.
#   3. Renders .env from .env.example, generates APP_KEY, populates DB_*.
#   4. Runs scripts/migrate.php + scripts/seed.php.
#   5. Drops nginx vhost (php-fpm) at /etc/nginx/sites-available/bconnex.conf and enables it.
#   6. Optionally installs a systemd unit (bconnex.service) wrapping the built-in PHP server
#      for hosts without nginx (set BCX_NO_NGINX=1).
#   7. Prints next-steps + demo credentials.

set -euo pipefail

#---------------------------------------------------------------------- helpers
log()  { printf '\033[1;36m›\033[0m %s\n' "$*"; }
ok()   { printf '\033[1;32m✔\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m⚠\033[0m %s\n' "$*"; }
die()  { printf '\033[1;31m✖\033[0m %s\n' "$*" >&2; exit 1; }

require_root() {
  if [[ $EUID -ne 0 ]]; then
    die "Please run as root (sudo bash scripts/install.sh)"
  fi
}

detect_pkg() {
  if   command -v apt-get >/dev/null 2>&1; then echo apt
  elif command -v dnf     >/dev/null 2>&1; then echo dnf
  elif command -v yum     >/dev/null 2>&1; then echo yum
  else echo unknown; fi
}

rand_pw() {
  # 32-char URL-safe random (no shell-meta chars).
  tr -dc 'A-Za-z0-9' </dev/urandom | head -c 32
}

#---------------------------------------------------------------------- inputs
require_root

BCX_APP_DIR="${BCX_APP_DIR:-$(pwd)}"
BCX_DOMAIN="${BCX_DOMAIN:-localhost}"
BCX_DB_NAME="${BCX_DB_NAME:-bconnex}"
BCX_DB_USER="${BCX_DB_USER:-bconnex}"
BCX_DB_PASS="${BCX_DB_PASS:-$(rand_pw)}"
BCX_HTTP_PORT="${BCX_HTTP_PORT:-80}"
BCX_NO_NGINX="${BCX_NO_NGINX:-0}"
BCX_NO_DB="${BCX_NO_DB:-0}"
BCX_NO_SYSTEMD="${BCX_NO_SYSTEMD:-0}"
BCX_NONINTERACTIVE="${BCX_NONINTERACTIVE:-0}"

if [[ ! -f "$BCX_APP_DIR/public/index.php" ]]; then
  die "BCX_APP_DIR='$BCX_APP_DIR' does not look like a B-connex repo (missing public/index.php)."
fi

if [[ "$BCX_NONINTERACTIVE" != "1" ]]; then
  read -r -p "Public hostname [$BCX_DOMAIN]: " _x && [[ -n "$_x" ]] && BCX_DOMAIN="$_x" || true
  read -r -p "Database name [$BCX_DB_NAME]: " _x && [[ -n "$_x" ]] && BCX_DB_NAME="$_x" || true
  read -r -p "Database user [$BCX_DB_USER]: " _x && [[ -n "$_x" ]] && BCX_DB_USER="$_x" || true
  read -r -p "Database password [random]: " _x && [[ -n "$_x" ]] && BCX_DB_PASS="$_x" || true
fi

PKG="$(detect_pkg)"
[[ "$PKG" == "unknown" ]] && die "Unsupported distro (need apt, dnf or yum)."

#---------------------------------------------------------------------- packages
log "Installing system packages via $PKG…"

PHP_EXTS_APT="php8.2-cli php8.2-fpm php8.2-mysql php8.2-mbstring php8.2-curl php8.2-xml php8.2-intl php8.2-zip"
PHP_EXTS_DNF="php-cli php-fpm php-mysqlnd php-mbstring php-json php-xml php-intl php-pdo php-fileinfo"

case "$PKG" in
  apt)
    export DEBIAN_FRONTEND=noninteractive
    apt-get update -y
    apt-get install -y software-properties-common ca-certificates curl gnupg lsb-release
    if ! apt-cache show php8.2-cli >/dev/null 2>&1; then
      log "Adding ondrej/php PPA for PHP 8.2…"
      add-apt-repository -y ppa:ondrej/php || warn "ppa add failed; relying on distro PHP"
      apt-get update -y
    fi
    apt-get install -y $PHP_EXTS_APT
    [[ "$BCX_NO_NGINX" == "1" ]] || apt-get install -y nginx
    [[ "$BCX_NO_DB"    == "1" ]] || apt-get install -y mariadb-server
    ;;
  dnf|yum)
    $PKG install -y epel-release || true
    $PKG install -y $PHP_EXTS_DNF
    [[ "$BCX_NO_NGINX" == "1" ]] || $PKG install -y nginx
    [[ "$BCX_NO_DB"    == "1" ]] || $PKG install -y mariadb-server
    ;;
esac

# Verify PHP version
PHP_BIN="$(command -v php || true)"
[[ -z "$PHP_BIN" ]] && die "PHP not found after install."
PHP_VER="$($PHP_BIN -r 'echo PHP_VERSION;')"
PHP_MAJ="$($PHP_BIN -r 'echo PHP_MAJOR_VERSION;')"
PHP_MIN="$($PHP_BIN -r 'echo PHP_MINOR_VERSION;')"
if (( PHP_MAJ < 8 || (PHP_MAJ == 8 && PHP_MIN < 2) )); then
  die "PHP 8.2+ required (found $PHP_VER)."
fi
ok "PHP $PHP_VER"

# Verify required extensions
MISSING=()
for ext in pdo_mysql mbstring openssl json fileinfo curl intl; do
  $PHP_BIN -m | grep -qiE "^$ext$" || MISSING+=("$ext")
done
[[ ${#MISSING[@]} -gt 0 ]] && die "Missing PHP extensions: ${MISSING[*]}"
ok "PHP extensions present"

#---------------------------------------------------------------------- database
if [[ "$BCX_NO_DB" != "1" ]]; then
  log "Starting MariaDB…"
  systemctl enable --now mariadb || systemctl enable --now mysql || true

  log "Provisioning database '$BCX_DB_NAME' and user '$BCX_DB_USER'…"
  mysql --protocol=socket -uroot <<SQL
CREATE DATABASE IF NOT EXISTS \`$BCX_DB_NAME\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS '$BCX_DB_USER'@'localhost' IDENTIFIED BY '$BCX_DB_PASS';
ALTER USER '$BCX_DB_USER'@'localhost' IDENTIFIED BY '$BCX_DB_PASS';
GRANT ALL PRIVILEGES ON \`$BCX_DB_NAME\`.* TO '$BCX_DB_USER'@'localhost';
FLUSH PRIVILEGES;
SQL
  ok "Database ready"
fi

#---------------------------------------------------------------------- .env
ENV_FILE="$BCX_APP_DIR/.env"
if [[ -f "$ENV_FILE" ]]; then
  warn ".env exists — leaving in place (backup at .env.bak.$(date +%s))"
  cp "$ENV_FILE" "$ENV_FILE.bak.$(date +%s)"
else
  cp "$BCX_APP_DIR/.env.example" "$ENV_FILE"
fi

APP_KEY="$($PHP_BIN -r 'echo base64_encode(random_bytes(32));')"
APP_URL="http://${BCX_DOMAIN}"
[[ "$BCX_HTTP_PORT" != "80" ]] && APP_URL="${APP_URL}:${BCX_HTTP_PORT}"

# Inline edits — replace if present, otherwise append
set_env() {
  local key="$1" val="$2"
  if grep -qE "^${key}=" "$ENV_FILE"; then
    # escape forward slashes and ampersands for sed
    local esc; esc="$(printf '%s' "$val" | sed -e 's/[\/&]/\\&/g')"
    sed -i "s|^${key}=.*|${key}=${esc}|" "$ENV_FILE"
  else
    printf '%s=%s\n' "$key" "$val" >> "$ENV_FILE"
  fi
}

set_env APP_ENV       "production"
set_env APP_DEBUG     "false"
set_env APP_URL       "$APP_URL"
set_env APP_KEY       "$APP_KEY"
set_env DB_HOST       "127.0.0.1"
set_env DB_PORT       "3306"
set_env DB_NAME       "$BCX_DB_NAME"
set_env DB_USER       "$BCX_DB_USER"
set_env DB_PASS       "$BCX_DB_PASS"
set_env COOKIE_SECURE "auto"
set_env TRUSTED_PROXIES "127.0.0.1"

ok ".env written ($ENV_FILE)"

#---------------------------------------------------------------------- migrate + seed
log "Running migrations…"
( cd "$BCX_APP_DIR" && "$PHP_BIN" scripts/migrate.php )

log "Seeding demo data (idempotent)…"
( cd "$BCX_APP_DIR" && "$PHP_BIN" scripts/seed.php ) || warn "Seed step reported issues — usually safe to ignore on re-run."

#---------------------------------------------------------------------- ownership
WEBUSER="www-data"
id -u www-data >/dev/null 2>&1 || WEBUSER="nginx"
log "Setting ownership for $WEBUSER on storage/…"
mkdir -p "$BCX_APP_DIR/storage/logs" "$BCX_APP_DIR/storage/cache" "$BCX_APP_DIR/storage/kyc"
chown -R "$WEBUSER":"$WEBUSER" "$BCX_APP_DIR/storage" || warn "chown failed (non-fatal)"
chmod -R u+rwX,g+rX,o-rwx       "$BCX_APP_DIR/storage" || true

#---------------------------------------------------------------------- nginx
if [[ "$BCX_NO_NGINX" != "1" ]]; then
  log "Writing nginx vhost…"
  PHP_FPM_SOCK="$(ls /run/php/php8.2-fpm.sock /run/php-fpm/www.sock 2>/dev/null | head -n1 || true)"
  [[ -z "$PHP_FPM_SOCK" ]] && PHP_FPM_SOCK="/run/php/php8.2-fpm.sock"

  VHOST_DIR="/etc/nginx/sites-available"
  [[ -d /etc/nginx/conf.d && ! -d "$VHOST_DIR" ]] && VHOST_DIR="/etc/nginx/conf.d"
  mkdir -p "$VHOST_DIR"
  CONF="$VHOST_DIR/bconnex.conf"

  cat > "$CONF" <<NGINX
# B-connex vhost — generated by scripts/install.sh
server {
    listen ${BCX_HTTP_PORT};
    listen [::]:${BCX_HTTP_PORT};
    server_name ${BCX_DOMAIN};
    root ${BCX_APP_DIR}/public;
    index index.php;

    client_max_body_size 8m;

    location / {
        try_files \$uri \$uri/ /index.php?\$query_string;
    }

    location ~ \.php\$ {
        include fastcgi_params;
        fastcgi_pass unix:${PHP_FPM_SOCK};
        fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
        fastcgi_param HTTPS \$https if_not_empty;
        fastcgi_read_timeout 60;
    }

    location ~* /\.(?!well-known) { deny all; }
    location ~* \.(env|sql|md|lock|json)\$ { deny all; }

    access_log /var/log/nginx/bconnex.access.log;
    error_log  /var/log/nginx/bconnex.error.log;
}
NGINX

  if [[ -d /etc/nginx/sites-enabled ]]; then
    ln -sf "$CONF" /etc/nginx/sites-enabled/bconnex.conf
    [[ -e /etc/nginx/sites-enabled/default ]] && rm -f /etc/nginx/sites-enabled/default || true
  fi

  systemctl enable --now php8.2-fpm 2>/dev/null || systemctl enable --now php-fpm 2>/dev/null || true
  nginx -t
  systemctl reload nginx || systemctl restart nginx
  ok "nginx vhost active on :${BCX_HTTP_PORT}"
fi

#---------------------------------------------------------------------- systemd (no-nginx fallback)
if [[ "$BCX_NO_NGINX" == "1" && "$BCX_NO_SYSTEMD" != "1" ]]; then
  log "Installing bconnex.service (built-in PHP server) on :${BCX_HTTP_PORT}…"
  cat > /etc/systemd/system/bconnex.service <<UNIT
[Unit]
Description=B-connex (PHP built-in server)
After=network.target mariadb.service

[Service]
Type=simple
WorkingDirectory=${BCX_APP_DIR}
ExecStart=${PHP_BIN} -S 0.0.0.0:${BCX_HTTP_PORT} -t ${BCX_APP_DIR}/public
Restart=on-failure
User=${WEBUSER}
Group=${WEBUSER}
Environment=APP_ENV=production

[Install]
WantedBy=multi-user.target
UNIT
  systemctl daemon-reload
  systemctl enable --now bconnex.service
  ok "bconnex.service running on :${BCX_HTTP_PORT}"
fi

#---------------------------------------------------------------------- summary
cat <<DONE

────────────────────────────────────────────────────────────────────────
✔ B-connex installed.

  URL          : ${APP_URL}
  App dir      : ${BCX_APP_DIR}
  Database     : ${BCX_DB_NAME} (user ${BCX_DB_USER})
  DB password  : ${BCX_DB_PASS}
  .env         : ${ENV_FILE}

  Demo logins (delete in production!):
    owner@b-connex.local / ChangeMe!2025
    admin@b-connex.local / AdminPass!2026

  Next steps:
    1. Point DNS for ${BCX_DOMAIN} at this host.
    2. Add TLS (recommended): sudo apt install certbot python3-certbot-nginx
       sudo certbot --nginx -d ${BCX_DOMAIN}
    3. Review docs/needs-attention.md for items that require your input
       (Stripe keys, OAuth client IDs, SMTP credentials, etc.).
    4. Edit ${ENV_FILE} and rotate APP_KEY / passwords before going live.
────────────────────────────────────────────────────────────────────────
DONE
