#!/usr/bin/env bash
# Automated CSF migration to GPL open-source edition (v15.00)
# Based on guide: https://github.com/centminmod/configserver-scripts/blob/main/README-gpl-csf.md#-migration-guide
# Compatible with RHEL/AlmaLinux/CentOS 7/8/9+ (and generic Debian/Ubuntu)
# Execution: bash migrate_csf.sh [options]

###############################################################################
# ====================== USER-ADJUSTABLE OPTIONS =============================
# Enable or disable CSF/OSS auto-updates. Default is OFF ("0").
# Change here or override with --auto-updates=0|1
AUTO_UPDATES="0"
###############################################################################

set -euo pipefail

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
LIGHT_BLUE='\033[1;36m'
NC='\033[0m' # No Color

### ===== Internal defaults =====
CSF_SOURCE_URL_DEFAULT="https://raw.githubusercontent.com/waytotheweb/scripts/refs/heads/main/csf.tgz"
BACKUP_BASE_DEFAULT="/root/csf-migration-backups"
LOG_FILE="/var/log/csf_migration_$(date +%Y%m%d_%H%M%S).log"

### ===== Flags/params =====
DRY_RUN=0
NO_RESTORE=0
CSF_SOURCE_URL="$CSF_SOURCE_URL_DEFAULT"
BACKUP_BASE="$BACKUP_BASE_DEFAULT"

usage() {
  cat <<EOF
Usage: $0 [options]

Options:
  --dry-run               Show what would be done without making changes
  --no-restore            Do NOT restore configs from backup (clean install)
  --source-url URL        URL of csf.tgz (default: $CSF_SOURCE_URL_DEFAULT)
  --backup-dir DIR        Base backup directory (default: $BACKUP_BASE_DEFAULT)
  --auto-updates=0|1      Override AUTO_UPDATES variable defined at the top
  -h, --help              This help message

Examples:
  $0
  $0 --source-url "https://my-mirror.local/csf.tgz"
  $0 --no-restore
  $0 --dry-run
  $0 --auto-updates=1
EOF
}

log()      { echo -e "[$(date +%F\ %T)] $*" | tee -a "$LOG_FILE"; }
log_info() { echo -e "${LIGHT_BLUE}[INFO]${NC} [$(date +%F\ %T)] $*" | tee -a "$LOG_FILE"; }
log_ok()   { echo -e "${GREEN}[OK]${NC} [$(date +%F\ %T)] $*" | tee -a "$LOG_FILE"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} [$(date +%F\ %T)] $*" | tee -a "$LOG_FILE"; }
log_err()  { echo -e "${RED}[ERROR]${NC} [$(date +%F\ %T)] $*" | tee -a "$LOG_FILE"; }
run()      { if [[ "$DRY_RUN" -eq 1 ]]; then log_info "[DRY-RUN] $*"; else log_info "[RUN] $*"; eval "$@" 2>&1 | tee -a "$LOG_FILE"; fi }
exists()   { command -v "$1" >/dev/null 2>&1; }

# Parse arguments
while [[ $# -gt 0 ]]; do
  case "$1" in
    --dry-run) DRY_RUN=1; shift ;;
    --no-restore) NO_RESTORE=1; shift ;;
    --source-url) CSF_SOURCE_URL="${2:-$CSF_SOURCE_URL_DEFAULT}"; shift 2 ;;
    --backup-dir) BACKUP_BASE="${2:-$BACKUP_BASE_DEFAULT}"; shift 2 ;;
    --auto-updates=*)
      AUTO_UPDATES="${1#*=}"
      if [[ "$AUTO_UPDATES" != "0" && "$AUTO_UPDATES" != "1" ]]; then
        echo "Invalid value for --auto-updates (use 0 or 1)"; exit 2
      fi
      shift
      ;;
    -h|--help) usage; exit 0 ;;
    *) shift ;;
  esac
done

if [[ $EUID -ne 0 ]]; then
  log_err "This script must be run as root."
  exit 1
fi

echo -e "${GREEN}═══════════════════════════════════════════════════════════${NC}"
echo -e "${GREEN}           CSF MIGRATION TO GPL EDITION (v15.00)           ${NC}"
echo -e "${GREEN}═══════════════════════════════════════════════════════════${NC}"
echo -e "${LIGHT_BLUE}           Provided by UnderHost.com${NC}"
echo -e "${LIGHT_BLUE}      Reliable Hosting Solutions Since 2007${NC}"
echo -e "${GREEN}═══════════════════════════════════════════════════════════${NC}"
log_info "Log file: $LOG_FILE"
log_info "CSF source URL: $CSF_SOURCE_URL"
log_info "Backup base: $BACKUP_BASE"
log_info "Desired AUTO_UPDATES: \"$AUTO_UPDATES\""
[[ "$DRY_RUN" -eq 1 ]] && log_warn "DRY-RUN Mode Enabled"

### ===== Detect panel and init system =====
PANEL="generic"
[[ -e "/usr/local/cpanel/version" ]] && PANEL="cpanel"
[[ -e "/usr/local/directadmin/directadmin" ]] && PANEL="directadmin"
[[ -e "/usr/local/interworx" ]] && PANEL="interworx"
[[ -e "/usr/local/cwpsrv" ]] && PANEL="cwp"
[[ -e "/usr/local/vesta" ]] && PANEL="vesta"
[[ -e "/usr/local/CyberCP" ]] && PANEL="cyberpanel"
log_info "Panel detected: ${LIGHT_BLUE}$PANEL${NC}"

if pidof systemd >/dev/null 2>&1; then INIT="systemd"; else INIT="sysv"; fi
log_info "Init system detected: ${LIGHT_BLUE}$INIT${NC}"

### ===== Backup =====
TS="$(date +%Y%m%d_%H%M%S)"
BACKUP_DIR="$BACKUP_BASE/backup_$TS"
mkdir -p "$BACKUP_DIR"

backup_path_if_exists() {
  local src="$1"
  if [[ -e "$src" ]]; then
    # Ensure destination directory exists before creating tar
    local dst="$BACKUP_DIR$(echo "$src" | sed 's#/$##').tgz"
    run "mkdir -p '$(dirname "$dst")'"
    run "tar -C / -czf '$dst' '${src#/}'"
  else
    log_warn "$src does not exist, skipping backup."
  fi
}

log_info "Backing up current CSF configuration..."
backup_path_if_exists "/etc/csf"
backup_path_if_exists "/usr/local/csf"
log_ok "Backups saved to: ${LIGHT_BLUE}$BACKUP_DIR${NC}"

### ===== Safe stop of CSF/LFD =====
if exists csf; then
  run "csf -x || true"   # disable firewall rules
fi
if [[ "$INIT" == "systemd" ]]; then
  run "systemctl stop lfd || true"
else
  run "service lfd stop || true"
fi

### ===== Download/installation =====
WORKDIR="/usr/src"
CSF_TGZ="$WORKDIR/csf.tgz"
INSTALL_DIR="$WORKDIR/csf"

run "mkdir -p '$WORKDIR'"
run "rm -f '$CSF_TGZ'"
run "rm -rf '$INSTALL_DIR'"

# Basic prerequisites
if ! exists wget; then run "yum -y install wget || dnf -y install wget || apt -y install wget"; fi
if ! exists tar; then  run "yum -y install tar  || dnf -y install tar  || apt -y install tar"; fi
if ! exists perl; then run "yum -y install perl || dnf -y install perl || apt -y install perl"; fi

log_info "Downloading CSF GPL v15.00 from: ${LIGHT_BLUE}$CSF_SOURCE_URL${NC}..."
if run "wget -O '$CSF_TGZ' '$CSF_SOURCE_URL'"; then
  log_ok "Download completed successfully"
else
  log_err "Failed to download CSF. Please check the URL and connectivity."
  exit 1
fi

log_info "Extracting csf.tgz file..."
if run "tar -C '$WORKDIR' -xzf '$CSF_TGZ'"; then
  log_ok "Extraction completed successfully"
else
  log_err "Failed to extract CSF archive."
  exit 1
fi

log_info "Running CSF installer..."
case "$PANEL" in
  cpanel)      INSTALL_SH="install.cpanel.sh" ;;
  directadmin) INSTALL_SH="install.directadmin.sh" ;;
  interworx)   INSTALL_SH="install.interworx.sh" ;;
  cwp)         INSTALL_SH="install.cwp.sh" ;;
  vesta)       INSTALL_SH="install.vesta.sh" ;;
  cyberpanel)  INSTALL_SH="install.cyberpanel.sh" ;;
  *)           INSTALL_SH="install.sh" ;;
esac

if [[ "$DRY_RUN" -eq 1 ]]; then
  log_info "[DRY-RUN] sh '$INSTALL_DIR/$INSTALL_SH'"
else
  if ( cd "$INSTALL_DIR" && sh "$INSTALL_SH" 2>&1 | tee -a "$LOG_FILE" ); then
    log_ok "CSF installation completed successfully"
  else
    log_err "CSF installation failed. Check the log for details."
    exit 1
  fi
fi

### ===== Restore configs (optional) =====
if [[ "$NO_RESTORE" -eq 0 ]]; then
  log_info "Restoring configuration files from backup..."
  declare -a CFGS=(
    "etc/csf/csf.conf"
    "etc/csf/csf.allow"
    "etc/csf/csf.deny"
    "etc/csf/csf.ignore"
    "etc/csf/csf.pignore"
    "etc/csf/regex.custom.pm"
    "etc/csf/ui/ui.allow"
    "etc/csf/ui/ui.ignore"
    "etc/csf/ui/ui.minipass"
    "etc/csf/lfd.ignore"
    "etc/csf/lfd.logignore"
    "etc/csf/lfd.conf"
  )
  for item in "${CFGS[@]}"; do
    B_TAR="$BACKUP_DIR/$(dirname "/$item").tgz"
    if [[ -f "$B_TAR" ]] && tar -tzf "$B_TAR" "$item" >/dev/null 2>&1; then
      run "tar -xzf '$B_TAR' -C / '$item'"
    fi
  done
  log_ok "Configuration restored from backup"
else
  log_warn "NO_RESTORE=1 - not restoring configs from backup (clean install)."
fi

### ===== Set AUTO_UPDATES in /etc/csf/csf.conf (at the top) =====
CSF_CONF="/etc/csf/csf.conf"
if [[ -f "$CSF_CONF" ]]; then
  log_info "Setting AUTO_UPDATES = \"$AUTO_UPDATES\" in csf.conf..."
  if [[ "$DRY_RUN" -eq 1 ]]; then
    log_info "[DRY-RUN] (insert/replace) AUTO_UPDATES = \"$AUTO_UPDATES\" in $CSF_CONF"
  else
    if grep -q '^AUTO_UPDATES' "$CSF_CONF"; then
      sed -i "s/^AUTO_UPDATES *=.*$/AUTO_UPDATES = \"$AUTO_UPDATES\"/" "$CSF_CONF"
      log_ok "AUTO_UPDATES updated to \"$AUTO_UPDATES\" (disabling automatic updates)"
    else
      sed -i "1iAUTO_UPDATES = \"$AUTO_UPDATES\"" "$CSF_CONF"
      log_ok "AUTO_UPDATES set to \"$AUTO_UPDATES\" (disabling automatic updates)"
    fi
  fi
else
  log_err "$CSF_CONF not found after installation!"
  exit 1
fi

### ===== Restart CSF/LFD =====
log_info "Restarting CSF and LFD..."
if exists csf; then
  if run "csf -r || csf -e"; then
    log_ok "CSF restarted successfully"
  else
    log_err "Failed to restart CSF"
  fi
fi

if [[ "$INIT" == "systemd" ]]; then
  if run "systemctl restart lfd || systemctl start lfd"; then
    log_ok "LFD service restarted successfully"
  else
    log_err "Failed to restart LFD service"
  fi
else
  if run "service lfd restart || service lfd start"; then
    log_ok "LFD service restarted successfully"
  else
    log_err "Failed to restart LFD service"
  fi
fi

### ===== Final validation =====
echo -e "\n${LIGHT_BLUE}═══════════════════════════════════════════════════════════${NC}"
echo -e "${LIGHT_BLUE}                    FINAL VALIDATION                        ${NC}"
echo -e "${LIGHT_BLUE}═══════════════════════════════════════════════════════════${NC}"

ERRORS_FOUND=0

if exists csf; then
  log_info "Checking installed CSF version..."
  if [[ "$DRY_RUN" -eq 1 ]]; then
    # In DRY-RUN mode, simulate that version 15.x would be installed
    CSF_VERSION="csf: v15.00 (GPL Edition)"
    echo -e "${GREEN}✓ CSF Version: $CSF_VERSION (simulated)${NC}"
    log_ok "CSF version 15.x would be installed successfully"
  else
    CSF_VERSION=$(csf -v 2>/dev/null | head -n1 || echo "Version not found")
    if [[ "$CSF_VERSION" == *"15."* ]]; then
      echo -e "${GREEN}✓ CSF Version: $CSF_VERSION${NC}"
      log_ok "CSF version 15.x installed successfully"
    else
      echo -e "${RED}✗ CSF Version: $CSF_VERSION${NC}"
      log_err "CSF version is not 15.x - possible installation issue"
      ERRORS_FOUND=1
    fi
  fi
  
  log_info "Checking firewall rules..."
  if [[ "$DRY_RUN" -eq 1 ]]; then
    echo -e "${GREEN}✓ Firewall rules: OK (simulated)${NC}"
    log_ok "Firewall rules would be loaded correctly"
  else
    if csf -l >/dev/null 2>&1; then
      echo -e "${GREEN}✓ Firewall rules: OK${NC}"
      log_ok "Firewall rules loaded correctly"
    else
      echo -e "${RED}✗ Firewall rules: ERROR${NC}"
      log_err "Problem loading firewall rules"
      ERRORS_FOUND=1
    fi
  fi
  
  log_info "Checking LFD status..."
  if [[ "$DRY_RUN" -eq 1 ]]; then
    echo -e "${GREEN}✓ LFD Service: Active (simulated)${NC}"
    log_ok "LFD service would be running"
  else
    if [[ "$INIT" == "systemd" ]]; then
      if systemctl is-active lfd >/dev/null 2>&1; then
        echo -e "${GREEN}✓ LFD Service: Active${NC}"
        log_ok "LFD service is running"
      else
        echo -e "${RED}✗ LFD Service: Inactive${NC}"
        log_err "LFD service is not running"
        ERRORS_FOUND=1
      fi
    else
      if service lfd status >/dev/null 2>&1; then
        echo -e "${GREEN}✓ LFD Service: Active${NC}"
        log_ok "LFD service is running"
      else
        echo -e "${RED}✗ LFD Service: Inactive${NC}"
        log_err "LFD service is not running"
        ERRORS_FOUND=1
      fi
    fi
  fi
  
  log_info "Running Perl modules test..."
  if [[ "$DRY_RUN" -eq 1 ]]; then
    echo -e "${GREEN}✓ Perl Modules: OK (simulated)${NC}"
    log_ok "All required Perl modules would be available"
  else
    if perl /usr/local/csf/bin/csftest.pl >/dev/null 2>&1; then
      echo -e "${GREEN}✓ Perl Modules: OK${NC}"
      log_ok "All required Perl modules are available"
    else
      echo -e "${YELLOW}⚠ Perl Modules: Some modules may be missing${NC}"
      log_warn "Run 'perl /usr/local/csf/bin/csftest.pl' for details"
    fi
  fi
else
  echo -e "${RED}✗ CSF not found after installation!${NC}"
  log_err "CSF not found on system - installation failed"
  ERRORS_FOUND=1
fi

echo -e "\n${GREEN}═══════════════════════════════════════════════════════════${NC}"
if [[ $ERRORS_FOUND -eq 0 ]]; then
  if [[ "$DRY_RUN" -eq 1 ]]; then
    echo -e "${GREEN}              ✅ SIMULATION COMPLETED SUCCESSFULLY! ✅        ${NC}"
    echo -e "${GREEN}═══════════════════════════════════════════════════════════${NC}"
    log_ok "CSF GPL v15.00 migration simulation completed successfully!"
    echo -e "${GREEN}\n🔥 CSF GPL v15.00 would be installed and working perfectly!${NC}"
    echo -e "${LIGHT_BLUE}📁 Backups would be saved to: $BACKUP_DIR${NC}"
    echo -e "${LIGHT_BLUE}📋 Log would be detailed at: $LOG_FILE${NC}"
    echo -e "${YELLOW}\n💡 Run without --dry-run to perform the actual migration.${NC}\n"
  else
    echo -e "${GREEN}              ✅ MIGRATION COMPLETED SUCCESSFULLY! ✅          ${NC}"
    echo -e "${GREEN}═══════════════════════════════════════════════════════════${NC}"
    log_ok "CSF GPL v15.00 migration completed successfully!"
    echo -e "${GREEN}\n🔥 CSF GPL v15.00 is installed and working!${NC}"
    echo -e "${LIGHT_BLUE}📁 Backups saved to: $BACKUP_DIR${NC}"
    echo -e "${LIGHT_BLUE}📋 Detailed log at: $LOG_FILE${NC}"
    echo -e "${LIGHT_BLUE}🌐 For professional hosting services, visit UnderHost.com${NC}\n"
  fi
else
  if [[ "$DRY_RUN" -eq 1 ]]; then
    echo -e "${RED}              ⚠️  SIMULATION WITH ISSUES! ⚠️             ${NC}"
    echo -e "${RED}═══════════════════════════════════════════════════════════${NC}"
    log_err "Simulation detected $ERRORS_FOUND possible issue(s)"
    echo -e "${RED}\n❌ Please check the issues identified above.${NC}"
    echo -e "${YELLOW}💡 Resolve the issues before running the actual migration.${NC}\n"
  else
    echo -e "${RED}              ⚠️  MIGRATION WITH ISSUES! ⚠️               ${NC}"
    echo -e "${RED}═══════════════════════════════════════════════════════════${NC}"
    log_err "Migration completed but with $ERRORS_FOUND error(s) found"
    echo -e "${RED}\n❌ Check the errors above and consult the log for more details.${NC}"
    echo -e "${LIGHT_BLUE}📁 Backups available at: $BACKUP_DIR${NC}"
    echo -e "${LIGHT_BLUE}📋 Detailed log at: $LOG_FILE${NC}"
    echo -e "${LIGHT_BLUE}🌐 Need help? Contact support@underhost.com${NC}\n"
    exit 1
  fi
fi