#!/usr/bin/env bash

# SnapReels One-Click VPS Installer
# Target OS: Ubuntu 22.04 / 24.04
# App path expected: /var/www/snapreels

set -Eeuo pipefail

APP_NAME="snapreels"
APP_DIR="/var/www/snapreels"
APP_PORT="3000"

DOMAIN=""
EMAIL=""
ENABLE_SSL="yes"

MONGO_DB="snapreels"
MONGO_USER="snapreels"
MONGO_PASS="snapreels123456"

LOG_FILE="/root/snapreels-install.log"

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

log() {
  echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] $*${NC}" | tee -a "$LOG_FILE"
}

warn() {
  echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] $*${NC}" | tee -a "$LOG_FILE"
}

err() {
  echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] $*${NC}" | tee -a "$LOG_FILE"
}

on_error() {
  err "Installer failed on line $1. Check: $LOG_FILE"
}
trap 'on_error $LINENO' ERR

require_root() {
  if [ "$(id -u)" -ne 0 ]; then
    err "Please run this installer as root."
    exit 1
  fi
}

ask_inputs() {
  read -rp "Enter your domain (example.com): " DOMAIN
  while [ -z "${DOMAIN// }" ]; do
    read -rp "Domain cannot be empty. Enter your domain: " DOMAIN
  done

  read -rp "Enable SSL with Let's Encrypt? (yes/no) [yes]: " SSL_INPUT || true
  SSL_INPUT="${SSL_INPUT:-yes}"
  case "$SSL_INPUT" in
    yes|y|Y) ENABLE_SSL="yes" ;;
    no|n|N) ENABLE_SSL="no" ;;
    *) ENABLE_SSL="yes" ;;
  esac

  EMAIL="support@$DOMAIN"
}

check_app_files() {
  if [ ! -d "$APP_DIR" ]; then
    err "App directory not found: $APP_DIR"
    err "Upload/extract the SnapReels project there first."
    exit 1
  fi

  if [ ! -f "$APP_DIR/package.json" ]; then
    err "package.json not found in $APP_DIR"
    exit 1
  fi
}

install_base_packages() {
  log "Updating system packages..."
  export DEBIAN_FRONTEND=noninteractive
  apt-get update -y
  apt-get install -y ca-certificates curl wget gnupg unzip git nginx software-properties-common ufw
}

install_node() {
  if command -v node >/dev/null 2>&1; then
    log "Node already installed: $(node -v)"
  else
    log "Installing Node.js 20..."
    curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
    apt-get install -y nodejs
  fi

  log "Node version: $(node -v)"
  log "NPM version: $(npm -v)"

  if command -v pm2 >/dev/null 2>&1; then
    log "PM2 already installed: $(pm2 -v)"
  else
    log "Installing PM2..."
    npm install -g pm2
    hash -r
    log "PM2 version: $(pm2 -v)"
  fi
}

install_mongodb() {
  log "Installing MongoDB 7.0..."

  if [ ! -f /usr/share/keyrings/mongodb-server-7.0.gpg ]; then
    curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | \
      gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor
  fi

  cat >/etc/apt/sources.list.d/mongodb-org-7.0.list <<EOF
deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse
EOF

  apt-get update -y
  apt-get install -y mongodb-org

  systemctl enable mongod
  systemctl restart mongod
  sleep 5

  if ! systemctl is-active --quiet mongod; then
    err "MongoDB did not start."
    systemctl status mongod --no-pager || true
    journalctl -u mongod --no-pager -n 50 || true
    exit 1
  fi

  log "MongoDB is running."
}

configure_mongodb_user() {
  log "Waiting for MongoDB to accept connections..."
  for i in {1..15}; do
    if mongosh --quiet --eval "db.adminCommand('ping')" >/dev/null 2>&1; then
      break
    fi
    sleep 2
  done

  if ! mongosh --quiet --eval "db.adminCommand('ping')" >/dev/null 2>&1; then
    err "MongoDB is running but not accepting connections."
    journalctl -u mongod --no-pager -n 50 || true
    exit 1
  fi

  log "Creating MongoDB user if missing..."

  mongosh --quiet --eval "
    db = db.getSiblingDB('admin');
    if (db.getUser('$MONGO_USER') == null) {
      db.createUser({
        user: '$MONGO_USER',
        pwd: '$MONGO_PASS',
        roles: [
          { role: 'userAdminAnyDatabase', db: 'admin' },
          { role: 'readWriteAnyDatabase', db: 'admin' }
        ]
      });
      print('Mongo user created');
    } else {
      print('Mongo user already exists');
    }
  "

  if ! grep -q '^security:' /etc/mongod.conf; then
    printf '\nsecurity:\n  authorization: enabled\n' >> /etc/mongod.conf
  elif ! grep -q 'authorization: enabled' /etc/mongod.conf; then
    awk '
      BEGIN{done=0}
      /^security:/ {print; print "  authorization: enabled"; done=1; next}
      {print}
      END{if(done==0) print "security:\n  authorization: enabled"}
    ' /etc/mongod.conf > /etc/mongod.conf.tmp
    mv /etc/mongod.conf.tmp /etc/mongod.conf
  fi

  systemctl restart mongod
  sleep 5

  if ! systemctl is-active --quiet mongod; then
    err "MongoDB failed after enabling authorization."
    systemctl status mongod --no-pager || true
    journalctl -u mongod --no-pager -n 50 || true
    exit 1
  fi

  for i in {1..15}; do
    if mongosh "mongodb://$MONGO_USER:$MONGO_PASS@127.0.0.1:27017/admin?authSource=admin" \
      --quiet --eval "db.adminCommand('ping')" >/dev/null 2>&1; then
      log "MongoDB authentication verified."
      return 0
    fi
    sleep 2
  done

  err "MongoDB auth check failed."
  exit 1
}

write_env_file() {
  log "Writing .env file..."

  cat >"$APP_DIR/.env" <<EOF
MONGODB_URI="mongodb://$MONGO_USER:$MONGO_PASS@127.0.0.1:27017/$MONGO_DB?authSource=admin"
NEXT_PUBLIC_DEMO_MODE="false"
EOF
}

build_app() {
  cd "$APP_DIR"

  log "Installing app dependencies..."
  npm install

  log "Building app..."
  npm run build
}

start_app_pm2() {
  cd "$APP_DIR"

  if pm2 describe "$APP_NAME" >/dev/null 2>&1; then
    log "Restarting existing PM2 app..."
    pm2 restart "$APP_NAME"
  else
    log "Starting app with PM2..."
    pm2 start npm --name "$APP_NAME" -- start -- -p "$APP_PORT"
  fi

  pm2 save
  pm2 startup systemd >/tmp/pm2-startup.txt 2>/dev/null || true

  if grep -q "sudo" /tmp/pm2-startup.txt; then
    bash -c "$(grep 'sudo' /tmp/pm2-startup.txt | sed 's/^.*sudo/sudo/' | head -n 1)" || true
  fi

  sleep 5

  if ! pm2 describe "$APP_NAME" >/dev/null 2>&1; then
    err "PM2 app failed to start."
    pm2 logs "$APP_NAME" --lines 50 || true
    exit 1
  fi

  log "PM2 app started."
}

configure_nginx() {
  log "Configuring Nginx..."

  cat >/etc/nginx/sites-available/"$DOMAIN" <<EOF
server {
    listen 80;
    listen [::]:80;
    server_name $DOMAIN www.$DOMAIN;

    client_max_body_size 500M;

    location / {
        proxy_pass http://127.0.0.1:$APP_PORT;
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
        proxy_cache_bypass \$http_upgrade;

        proxy_connect_timeout 60s;
        proxy_send_timeout 600s;
        proxy_read_timeout 600s;
        send_timeout 600s;
    }
}
EOF

  ln -sf /etc/nginx/sites-available/"$DOMAIN" /etc/nginx/sites-enabled/"$DOMAIN"
  rm -f /etc/nginx/sites-enabled/default

  nginx -t
  systemctl enable nginx
  systemctl restart nginx

  log "Nginx configured."
}

configure_firewall() {
  log "Configuring firewall..."
  ufw allow OpenSSH >/dev/null 2>&1 || true
  ufw allow 'Nginx Full' >/dev/null 2>&1 || true
  ufw --force enable >/dev/null 2>&1 || true
}

install_ssl() {
  if [ "$ENABLE_SSL" != "yes" ]; then
    warn "SSL skipped by choice."
    return 0
  fi

  log "Installing Certbot packages..."
  apt-get install -y certbot python3-certbot-nginx

  log "Requesting SSL certificate..."
  if certbot --nginx -d "$DOMAIN" -d "www.$DOMAIN" --non-interactive --agree-tos -m "$EMAIL" --redirect; then
    log "SSL installed successfully."
  else
    warn "SSL step failed. The app is still installed."
    warn "Most common reason: domain DNS is not pointed to this server yet."
  fi
}

final_checks() {
  log "Running final checks..."

  systemctl is-active --quiet mongod && log "MongoDB: OK" || warn "MongoDB: NOT RUNNING"
  systemctl is-active --quiet nginx && log "Nginx: OK" || warn "Nginx: NOT RUNNING"

  if pm2 describe "$APP_NAME" >/dev/null 2>&1; then
    log "PM2 app: OK"
  else
    warn "PM2 app: NOT RUNNING"
  fi
}

show_summary() {
  echo
  echo "------------------------------------------------"
  echo " SnapReels installation completed"
  echo "------------------------------------------------"
  echo " Domain        : $DOMAIN"
  echo " App path      : $APP_DIR"
  echo " App port      : $APP_PORT"
  echo " Setup page    : http://$DOMAIN/install"
  if [ "$ENABLE_SSL" = "yes" ]; then
    echo " HTTPS URL     : https://$DOMAIN/install"
  fi
  echo " Log file      : $LOG_FILE"
  echo "------------------------------------------------"
  echo " Useful commands:"
  echo "   pm2 status"
  echo "   pm2 logs $APP_NAME --lines 100"
  echo "   systemctl status mongod"
  echo "   systemctl status nginx"
  echo "------------------------------------------------"
}

main() {
  require_root
  ask_inputs
  check_app_files
  install_base_packages
  install_node
  install_mongodb
  configure_mongodb_user
  write_env_file
  build_app
  start_app_pm2
  configure_nginx
  configure_firewall
  install_ssl
  final_checks
  show_summary
}

main "$@"