#!/usr/bin/env bash
# =============================================================================
# GoodGo Platform — One-Command Bootstrap
# =============================================================================
# Sets up a complete local development environment from a clean clone.
#
# Usage:
#   ./scripts/bootstrap.sh          # Full setup
#   ./scripts/bootstrap.sh --skip-seed  # Skip database seeding
#   ./scripts/bootstrap.sh --no-docker  # Skip Docker services (BYO database)
#
# Idempotent — safe to run multiple times.
# Works on macOS and Linux.
# =============================================================================

set -euo pipefail

# ── Colours & Helpers ────────────────────────────────────────────────────────

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
BOLD='\033[1m'
NC='\033[0m' # No Color

info()    { printf "${BLUE}ℹ${NC}  %s\n" "$1"; }
success() { printf "${GREEN}✔${NC}  %s\n" "$1"; }
warn()    { printf "${YELLOW}⚠${NC}  %s\n" "$1"; }
fail()    { printf "${RED}✖${NC}  %s\n" "$1" >&2; exit 1; }
step()    { printf "\n${BOLD}── %s ──${NC}\n" "$1"; }

# ── Parse Arguments ──────────────────────────────────────────────────────────

SKIP_SEED=false
NO_DOCKER=false

for arg in "$@"; do
  case "$arg" in
    --skip-seed)  SKIP_SEED=true ;;
    --no-docker)  NO_DOCKER=true ;;
    --help|-h)
      echo "Usage: ./scripts/bootstrap.sh [--skip-seed] [--no-docker]"
      echo ""
      echo "Options:"
      echo "  --skip-seed   Skip database seeding (pnpm db:seed)"
      echo "  --no-docker   Skip Docker Compose services (bring your own DB)"
      echo "  --help, -h    Show this help message"
      exit 0
      ;;
    *)
      warn "Unknown argument: $arg (ignored)"
      ;;
  esac
done

# ── Navigate to Project Root ─────────────────────────────────────────────────

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$PROJECT_ROOT"

echo ""
printf "${BOLD}╔══════════════════════════════════════════════════╗${NC}\n"
printf "${BOLD}║       GoodGo Platform — Developer Bootstrap     ║${NC}\n"
printf "${BOLD}╚══════════════════════════════════════════════════╝${NC}\n"
echo ""
info "Project root: $PROJECT_ROOT"

# ── Step 1: Check Prerequisites ──────────────────────────────────────────────

step "Checking prerequisites"

MISSING=()

# Node.js >= 22
if command -v node &>/dev/null; then
  NODE_VERSION=$(node -v | sed 's/v//')
  NODE_MAJOR=$(echo "$NODE_VERSION" | cut -d. -f1)
  if [ "$NODE_MAJOR" -ge 22 ]; then
    success "Node.js $NODE_VERSION (>= 22 required)"
  else
    fail "Node.js $NODE_VERSION found but >= 22 is required. Install via nvm: nvm install 22"
  fi
else
  MISSING+=("Node.js >= 22 — https://nodejs.org or 'nvm install 22'")
fi

# pnpm
if command -v pnpm &>/dev/null; then
  PNPM_VERSION=$(pnpm -v)
  success "pnpm $PNPM_VERSION"
else
  MISSING+=("pnpm — install with 'corepack enable' or 'npm install -g pnpm'")
fi

# Docker (only if not --no-docker)
if [ "$NO_DOCKER" = false ]; then
  if command -v docker &>/dev/null; then
    DOCKER_VERSION=$(docker --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
    success "Docker $DOCKER_VERSION"
  else
    MISSING+=("Docker — https://docs.docker.com/get-docker/")
  fi

  # Docker Compose (v2 plugin or standalone)
  if docker compose version &>/dev/null 2>&1; then
    COMPOSE_VERSION=$(docker compose version --short 2>/dev/null || docker compose version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
    success "Docker Compose $COMPOSE_VERSION"
  elif command -v docker-compose &>/dev/null; then
    COMPOSE_VERSION=$(docker-compose --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
    success "Docker Compose $COMPOSE_VERSION (standalone)"
  else
    MISSING+=("Docker Compose — https://docs.docker.com/compose/install/")
  fi

  # Check Docker daemon is running
  if ! docker info &>/dev/null 2>&1; then
    fail "Docker daemon is not running. Please start Docker Desktop or the Docker service."
  fi
fi

if [ ${#MISSING[@]} -gt 0 ]; then
  echo ""
  printf "${RED}Missing prerequisites:${NC}\n"
  for dep in "${MISSING[@]}"; do
    echo "  • $dep"
  done
  echo ""
  fail "Install the missing tools above and re-run this script."
fi

success "All prerequisites met"

# ── Step 2: Environment File ─────────────────────────────────────────────────

step "Setting up environment"

if [ -f .env ]; then
  success ".env already exists (skipping copy)"
else
  if [ -f .env.example ]; then
    cp .env.example .env

    # Generate secure defaults for development
    if command -v openssl &>/dev/null; then
      JWT_SECRET_VAL=$(openssl rand -base64 48)
      JWT_REFRESH_VAL=$(openssl rand -base64 48)
      KYC_KEY_VAL=$(openssl rand -hex 32)

      # Platform-safe sed in-place (macOS vs Linux)
      if [[ "$OSTYPE" == "darwin"* ]]; then
        SED_INPLACE=(sed -i '')
      else
        SED_INPLACE=(sed -i)
      fi

      "${SED_INPLACE[@]}" "s|DB_PASSWORD=CHANGE_ME|DB_PASSWORD=goodgo_secret|" .env
      "${SED_INPLACE[@]}" "s|TYPESENSE_API_KEY=CHANGE_ME|TYPESENSE_API_KEY=ts_dev_key_change_me|" .env
      "${SED_INPLACE[@]}" "s|MINIO_ACCESS_KEY=CHANGE_ME|MINIO_ACCESS_KEY=minioadmin|" .env
      "${SED_INPLACE[@]}" "s|MINIO_SECRET_KEY=CHANGE_ME|MINIO_SECRET_KEY=minioadmin|" .env
      "${SED_INPLACE[@]}" "s|PGBOUNCER_ADMIN_PASSWORD=CHANGE_ME|PGBOUNCER_ADMIN_PASSWORD=pgbouncer_admin|" .env
      "${SED_INPLACE[@]}" "s|PGBOUNCER_STATS_PASSWORD=CHANGE_ME|PGBOUNCER_STATS_PASSWORD=pgbouncer_stats|" .env
      "${SED_INPLACE[@]}" "s|JWT_SECRET=.*|JWT_SECRET=$JWT_SECRET_VAL|" .env
      "${SED_INPLACE[@]}" "s|JWT_REFRESH_SECRET=.*|JWT_REFRESH_SECRET=$JWT_REFRESH_VAL|" .env
      "${SED_INPLACE[@]}" "s|KYC_ENCRYPTION_KEY=.*|KYC_ENCRYPTION_KEY=$KYC_KEY_VAL|" .env
    else
      warn "openssl not found — .env copied but secrets are placeholders. Update them manually."
    fi

    success ".env created from .env.example with generated dev secrets"
  else
    fail ".env.example not found. Is this the project root?"
  fi
fi

# ── Step 3: Install Dependencies ─────────────────────────────────────────────

step "Installing dependencies"

pnpm install --frozen-lockfile 2>/dev/null || pnpm install
success "Dependencies installed"

# ── Step 4: Start Docker Services ────────────────────────────────────────────

if [ "$NO_DOCKER" = false ]; then
  step "Starting Docker services"

  # Start only core dev services (not monitoring/backup stack)
  CORE_SERVICES=(postgres redis typesense minio)

  info "Starting: ${CORE_SERVICES[*]}"
  docker compose up -d "${CORE_SERVICES[@]}"

  # Wait for services to be healthy
  info "Waiting for services to be healthy..."

  MAX_WAIT=120
  ELAPSED=0
  INTERVAL=5

  wait_for_service() {
    local service="$1"
    local container="goodgo-$service"

    while [ "$ELAPSED" -lt "$MAX_WAIT" ]; do
      local health
      health=$(docker inspect --format='{{.State.Health.Status}}' "$container" 2>/dev/null || echo "not_found")

      case "$health" in
        healthy)
          success "$service is healthy"
          return 0
          ;;
        unhealthy)
          fail "$service is unhealthy. Check logs: docker compose logs $service"
          ;;
        not_found)
          fail "Container $container not found. Check: docker compose ps"
          ;;
        *)
          # starting or no status yet
          ;;
      esac

      sleep "$INTERVAL"
      ELAPSED=$((ELAPSED + INTERVAL))
    done

    fail "$service did not become healthy within ${MAX_WAIT}s. Check logs: docker compose logs $service"
  }

  for svc in "${CORE_SERVICES[@]}"; do
    ELAPSED=0
    wait_for_service "$svc"
  done

  success "All Docker services are healthy"
else
  warn "Skipping Docker services (--no-docker). Ensure PostgreSQL, Redis, Typesense, and MinIO are available."
fi

# ── Step 5: Generate Prisma Client ───────────────────────────────────────────

step "Setting up database"

info "Generating Prisma client..."
pnpm db:generate
success "Prisma client generated"

# ── Step 6: Run Migrations ───────────────────────────────────────────────────

info "Running database migrations..."
pnpm db:migrate:dev --name init 2>/dev/null || pnpm db:migrate:dev 2>/dev/null || {
  # If migrate dev fails (e.g., migrations already applied), try deploy instead
  warn "migrate dev had issues, trying migrate deploy..."
  pnpm db:migrate:deploy
}
success "Database migrations applied"

# ── Step 7: Seed Database ────────────────────────────────────────────────────

if [ "$SKIP_SEED" = false ]; then
  info "Seeding database..."
  pnpm db:seed || {
    warn "Seed command returned non-zero (data may already exist). Continuing..."
  }
  success "Database seeded"
else
  info "Skipping database seed (--skip-seed)"
fi

# ── Done! ────────────────────────────────────────────────────────────────────

echo ""
printf "${BOLD}${GREEN}╔══════════════════════════════════════════════════╗${NC}\n"
printf "${BOLD}${GREEN}║         Setup Complete!                          ║${NC}\n"
printf "${BOLD}${GREEN}╚══════════════════════════════════════════════════╝${NC}\n"
echo ""
echo "Next steps:"
echo ""
echo "  ${BOLD}pnpm dev${NC}           Start all apps (API :3001, Web :3000)"
echo "  ${BOLD}pnpm db:studio${NC}     Open Prisma Studio to browse data"
echo "  ${BOLD}pnpm test${NC}          Run unit tests"
echo "  ${BOLD}pnpm lint${NC}          Run ESLint"
echo ""
echo "Optional services (monitoring stack):"
echo ""
echo "  ${BOLD}docker compose up -d loki promtail prometheus grafana${NC}"
echo "  Grafana: http://localhost:3002 (admin/admin)"
echo ""
echo "Documentation:"
echo ""
echo "  README.md             Project overview"
echo "  CONTRIBUTING.md       Contribution guidelines"
echo "  CLAUDE.md             AI assistant instructions"
echo ""
