#!/usr/bin/env bash
#
# Update a Foodifly server to the code in this folder.
#
#   bash scripts/deploy.sh            # code already uploaded / pulled
#   bash scripts/deploy.sh --pull     # git pull the current branch first
#
# Safe to run again: every step is idempotent. Never seeds data — run the
# ProductionSeeder yourself once, on a fresh install (see "After installing" in the documentation).

set -euo pipefail

cd "$(dirname "$0")/.."
ROOT="$(pwd)"

PULL=0
for arg in "$@"; do
  case "$arg" in
    --pull) PULL=1 ;;
    -h|--help) sed -n '2,10p' "$0"; exit 0 ;;
    *) echo "Unknown option: $arg" >&2; exit 2 ;;
  esac
done

step() { printf '\n\033[1;34m==> %s\033[0m\n' "$1"; }
warn() { printf '\033[1;33m  ! %s\033[0m\n' "$1"; }
ok()   { printf '\033[0;32m  ✓ %s\033[0m\n' "$1"; }
fail() { printf '\033[1;31m  ✗ %s\033[0m\n' "$1" >&2; exit 1; }

env_value() { grep -E "^$1=" .env | tail -1 | cut -d= -f2- | sed -e 's/^"//' -e 's/"$//'; }

# ── Preflight ────────────────────────────────────────────────────────────────
step "Checking the server"

[ -f .env ] || fail ".env is missing. Copy .env.example to .env and fill it in first."
[ -n "$(env_value APP_KEY)" ] || fail "APP_KEY is empty. Run: php artisan key:generate"

php -r 'exit(version_compare(PHP_VERSION, "8.4.0", ">=") ? 0 : 1);' \
  || fail "PHP 8.4 or newer is required (found $(php -r 'echo PHP_VERSION;'))."
ok "PHP $(php -r 'echo PHP_VERSION;')"

APP_ENV="$(env_value APP_ENV)"
if [ "$APP_ENV" = "production" ]; then
  [ "$(env_value APP_DEBUG)" = "false" ] || warn "APP_DEBUG is not false: error pages will show code and secrets to visitors."
fi
[ "$(env_value QUEUE_CONNECTION)" = "sync" ] && warn "QUEUE_CONNECTION=sync: pushes are sent inside each request (slow). Use database and run a worker."

for dir in storage bootstrap/cache; do
  [ -w "$dir" ] || fail "$dir is not writable by $(whoami). Fix ownership/permissions, then rerun."
done
ok "storage and bootstrap/cache are writable"

if [ "$PULL" = 1 ]; then
  step "Pulling the latest code"
  git pull --ff-only
fi

# ── Dependencies ─────────────────────────────────────────────────────────────
step "Installing PHP packages"
if [ "$APP_ENV" = "production" ]; then
  composer install --no-dev --optimize-autoloader --no-interaction --no-progress
else
  composer install --optimize-autoloader --no-interaction --no-progress
fi

step "Building admin panel assets"
if command -v npm >/dev/null 2>&1; then
  npm ci --no-audit --no-fund
  npm run build
elif [ -f public/build/manifest.json ]; then
  warn "npm not found; keeping the existing public/build. Build on another machine and upload public/build if the admin's CSS/JS changed."
else
  fail "npm not found and public/build is missing: the admin panel would have no styles. Install Node 20+ or upload a built public/build."
fi

# ── Database and app ─────────────────────────────────────────────────────────
# Maintenance only while the schema changes, so the API is never served
# against a half-migrated database. `trap` brings the site back even if a
# step fails.
step "Migrating the database"
php artisan down --retry=30 || true
trap 'php artisan up >/dev/null 2>&1 || true' EXIT
php artisan migrate --force
php artisan up
trap - EXIT

step "Linking public storage"
[ -L public/storage ] && ok "already linked" || php artisan storage:link

step "Caching config, routes, views and events"
php artisan optimize:clear >/dev/null
php artisan optimize

# Workers keep the old code in memory until restarted; Supervisor starts
# fresh ones as soon as these exit.
step "Restarting queue workers"
php artisan queue:restart

# ── After-deploy checks ──────────────────────────────────────────────────────
step "Checking background services"
php artisan tinker --execute='
  $q = \App\Support\BackgroundWorkers::queue();
  $s = \App\Support\BackgroundWorkers::scheduler();
  echo ($q["needs_worker"] ? ($q["running"] ? "  ✓ queue worker running" : "  ! queue worker NOT running — set up Supervisor (see the documentation)") : "  ✓ queue runs inline (sync)"), PHP_EOL;
  echo ($s["running"] ? "  ✓ scheduler running" : "  ! scheduler NOT running — add the cron line (see the documentation)"), PHP_EOL;
  echo (app(\App\Services\FirebaseCredentials::class)->status()["configured"] ? "  ✓ Firebase key uploaded" : "  ! no Firebase key — upload it in Admin → Settings → Firebase & Push"), PHP_EOL;
  $cur = \App\Models\PlatformSetting::get("currency_code");
  echo (strtoupper((string) $cur) === "BDT" ? "  ✓ currency BDT" : "  ! currency_code is \"" . ($cur ?: "unset (Stripe defaults to USD)") . "\" — set BDT in Admin → Settings"), PHP_EOL;
'

# Mark the site installed so the web installer at /install stays locked.
[ -f storage/installed.lock ] || date -u +%FT%TZ > storage/installed.lock

printf '\n\033[1;32mDeploy finished.\033[0m Worker/scheduler warnings right after a first deploy are expected until Supervisor and cron are set up.\n'
