#!/usr/bin/env bash
# CareBill — first install on a fresh Ubuntu server.
#
#   sudo DB_PASS='choose-a-strong-one' APP_URL='https://billing.caresoft.co.in' bash deploy/install.sh
#
# It sets up a NEW installation only. Pointed at a database that already holds
# CareBill data, it stops — existing installs are upgraded with the migrations
# listed in INSTALL.md, never by reloading the schema over live invoices.
set -euo pipefail

APP_DIR="${APP_DIR:-$(cd "$(dirname "$0")/.." && pwd)}"
DB_HOST="${DB_HOST:-127.0.0.1}"
DB_NAME="${DB_NAME:-carebill}"
DB_USER="${DB_USER:-carebill}"
DB_PASS="${DB_PASS:-}"
APP_URL="${APP_URL:-}"
WEB_USER="${WEB_USER:-www-data}"
MYSQL="${MYSQL:-mysql}"                      # how to reach the server as an admin (root via socket by default)

say()  { printf '\n\033[1m%s\033[0m\n' "$*"; }
ok()   { printf '  ok    %s\n' "$*"; }
stop() { printf '\n  STOP  %s\n\n' "$*" >&2; exit 1; }

[ -n "$DB_PASS" ] || stop "Set DB_PASS — the password CareBill will use for its own database user."
[ -n "$APP_URL" ] || stop "Set APP_URL — the https:// address the site will live at."
case "$APP_URL" in https://*) ;; *) stop "APP_URL must start with https://. Payment links and the client portal need it." ;; esac
[ "${#DB_PASS}" -ge 12 ] || stop "DB_PASS should be at least 12 characters."

say "Checking the server"
command -v php >/dev/null || stop "PHP is not installed:  apt install php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-zip php8.3-xml php8.3-curl"
php -r 'exit(version_compare(PHP_VERSION,"8.1.0",">=")?0:1);' || stop "PHP 8.1 or later is needed; this is $(php -r 'echo PHP_VERSION;')."
ok "PHP $(php -r 'echo PHP_VERSION;')"
# asked of PHP directly: piping php -m into grep -q fails under pipefail, because
# grep exits on the first match and php is killed mid-write
for ext in pdo_mysql mbstring zip simplexml curl openssl; do
  php -r 'exit(extension_loaded($argv[1]) ? 0 : 1);' "$ext" || stop "PHP extension $ext is missing:  apt install php8.3-${ext/pdo_mysql/mysql}"
done
ok "PHP extensions"
command -v "$MYSQL" >/dev/null || stop "The mysql client is not installed."
$MYSQL -e "SELECT 1" >/dev/null 2>&1 || stop "Cannot reach the database server as an admin. Set MYSQL='mysql -uroot -p' if root needs a password."
ok "database server reachable"
if command -v wkhtmltopdf >/dev/null; then ok "wkhtmltopdf present — invoices will be real PDFs"
else printf '  note  wkhtmltopdf is not installed; invoices will attach as HTML until it is:  apt install wkhtmltopdf\n'; fi

say "Database"
if $MYSQL -N -e "SHOW DATABASES LIKE '$DB_NAME'" | grep -q .; then
  if $MYSQL -N -e "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='$DB_NAME' AND TABLE_NAME='invoices'" | grep -qv '^0$'; then
    stop "Database $DB_NAME already contains CareBill. This installer only sets up new installations — use the upgrade steps in INSTALL.md."
  fi
fi
$MYSQL -e "CREATE DATABASE IF NOT EXISTS \`$DB_NAME\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
$MYSQL -e "CREATE USER IF NOT EXISTS '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
$MYSQL -e "CREATE USER IF NOT EXISTS '$DB_USER'@'127.0.0.1' IDENTIFIED BY '$DB_PASS';"
$MYSQL -e "ALTER USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS'; ALTER USER '$DB_USER'@'127.0.0.1' IDENTIFIED BY '$DB_PASS';"
$MYSQL -e "GRANT ALL PRIVILEGES ON \`$DB_NAME\`.* TO '$DB_USER'@'localhost'; GRANT ALL PRIVILEGES ON \`$DB_NAME\`.* TO '$DB_USER'@'127.0.0.1'; FLUSH PRIVILEGES;"
ok "database $DB_NAME and user $DB_USER"
$MYSQL "$DB_NAME" < "$APP_DIR/sql/schema.sql"
$MYSQL "$DB_NAME" < "$APP_DIR/sql/seed.sql"
$MYSQL "$DB_NAME" -e "UPDATE settings SET v='$APP_URL' WHERE k='app_url'; UPDATE settings SET v='log' WHERE k='mail_driver';"
ok "schema and starting data loaded (mail set to log-only until you switch it)"

say "Configuration"
CFG="$APP_DIR/config/config.php"
if [ -f "$CFG" ]; then
  ok "config/config.php already exists — left as it is"
else
  cp "$APP_DIR/config/config.sample.php" "$CFG"
  php -r '
    $f=$argv[1]; $s=file_get_contents($f);
    $s=preg_replace("/(.host.\s*=>\s*).[^,]*/", "\${1}".var_export($argv[2],true), $s, 1);
    $s=preg_replace("/(.name.\s*=>\s*).[^,]*/", "\${1}".var_export($argv[3],true), $s, 1);
    $s=preg_replace("/(.user.\s*=>\s*).[^,]*/", "\${1}".var_export($argv[4],true), $s, 1);
    $s=preg_replace("/(.pass.\s*=>\s*).[^,]*/", "\${1}".var_export($argv[5],true), $s, 1);
    $s=preg_replace("/(.env.\s*=>\s*).[^,]*/", "\${1}\x27production\x27", $s, 1);
    file_put_contents($f,$s);' "$CFG" "$DB_HOST" "$DB_NAME" "$DB_USER" "$DB_PASS"
  ok "config/config.php written, environment set to production"
fi

say "Permissions"
mkdir -p "$APP_DIR"/storage/{logs,imports,statements,advices,backups}
if id "$WEB_USER" >/dev/null 2>&1; then
  chown -R "$WEB_USER":"$WEB_USER" "$APP_DIR/storage"
  chown root:"$WEB_USER" "$CFG"
fi
chmod 750 "$APP_DIR/storage" "$APP_DIR"/storage/*
chmod 640 "$CFG"
ok "storage writable by $WEB_USER, config readable by nobody else"

say "Checking the result"
cd "$APP_DIR"
# run it as the web server user, since that is who has to read and write here
if id "$WEB_USER" >/dev/null 2>&1 && command -v runuser >/dev/null; then
  runuser -u "$WEB_USER" -- php tools/smoke_test.php || true
elif id "$WEB_USER" >/dev/null 2>&1 && command -v sudo >/dev/null; then
  sudo -u "$WEB_USER" php tools/smoke_test.php || true
else
  php tools/smoke_test.php || true
fi

cat <<NEXT

Next, in this order:
  1. nginx:  cp deploy/nginx.conf /etc/nginx/sites-available/carebill   (edit the three marked lines)
             ln -s ../sites-available/carebill /etc/nginx/sites-enabled/ && nginx -t && systemctl reload nginx
             certbot --nginx -d ${APP_URL#https://}
  2. cron:   crontab -u $WEB_USER deploy/crontab.txt
  3. Sign in as admin@caresoft.co.in / Caresoft@123 — you will be made to change it.
  4. Add a second admin, and turn on two-factor sign-in for both.
  5. Work through deploy/GOLIVE.md.
  6. php tools/smoke_test.php --web   to prove nothing private is public.
NEXT
