#!/usr/bin/env bash
set -Eeuo pipefail

APP_NAME="Clip24"
APP_VERSION="v1.0.1"
DEFAULT_DOMAIN="clip24.ainab.info"
DEFAULT_PROJECT_ROOT="/home/clip/public_html"
PACKAGE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="${CLIP24_PROJECT_ROOT:-$DEFAULT_PROJECT_ROOT}"
DOMAIN="${CLIP24_DOMAIN:-$DEFAULT_DOMAIN}"
BACKUP_ROOT="${CLIP24_BACKUP_ROOT:-$PROJECT_ROOT/clip24-backups}"
PROJECT_BACKUP_DIR="$BACKUP_ROOT/project"
DB_BACKUP_DIR="$BACKUP_ROOT/database"
LOG_DIR="$BACKUP_ROOT/logs"
ZIP_BACKUP_DIR="$BACKUP_ROOT/zips"
TMP_DIR="$BACKUP_ROOT/tmp"
LOG_FILE="$LOG_DIR/clip24-installer.log"
DEFAULT_ADMIN_EMAIL="admin@clip24.ainab.info"
DEFAULT_ADMIN_PASSWORD="ChangeMe!123"

CLR_RESET="\033[0m"; CLR_GREEN="\033[32m"; CLR_RED="\033[31m"; CLR_YELLOW="\033[33m"; CLR_BLUE="\033[34m"; CLR_BOLD="\033[1m"

log(){ echo -e "${CLR_GREEN}[Clip24]${CLR_RESET} $*" | tee -a "${LOG_FILE:-/dev/null}" 2>/dev/null || true; }
warn(){ echo -e "${CLR_YELLOW}[WARN]${CLR_RESET} $*" | tee -a "${LOG_FILE:-/dev/null}" 2>/dev/null || true; }
err(){ echo -e "${CLR_RED}[ERROR]${CLR_RESET} $*" | tee -a "${LOG_FILE:-/dev/null}" 2>/dev/null || true; }
step(){ echo -e "\n${CLR_BLUE}${CLR_BOLD}==> $*${CLR_RESET}" | tee -a "${LOG_FILE:-/dev/null}" 2>/dev/null || true; }

confirm(){ local msg="$1"; read -r -p "$msg [y/N]: " ans || true; case "$ans" in y|Y|yes|YES) return 0;; *) return 1;; esac; }

safe_realpath(){
  if command -v realpath >/dev/null 2>&1; then realpath -m "$1"; else echo "$1"; fi
}

protect_path(){
  local path
  path="$(safe_realpath "$PROJECT_ROOT")"
  case "$path" in
    "/"|"/home"|"/home/"|"/root"|"/tmp"|"/var"|"/usr"|"/etc"|"/opt")
      err "Unsafe PROJECT_ROOT detected: $path"; exit 1;;
  esac
  if [[ "$path" != */public_html ]]; then
    warn "Project root does not end with public_html: $path"
    confirm "Continue with this project root?" || exit 1
  fi
  PROJECT_ROOT="$path"
  BACKUP_ROOT="${CLIP24_BACKUP_ROOT:-$PROJECT_ROOT/clip24-backups}"
  PROJECT_BACKUP_DIR="$BACKUP_ROOT/project"; DB_BACKUP_DIR="$BACKUP_ROOT/database"; LOG_DIR="$BACKUP_ROOT/logs"; ZIP_BACKUP_DIR="$BACKUP_ROOT/zips"; TMP_DIR="$BACKUP_ROOT/tmp"; LOG_FILE="$LOG_DIR/clip24-installer.log"
}

ensure_backup_dirs(){
  mkdir -p "$PROJECT_ROOT" "$PROJECT_BACKUP_DIR" "$DB_BACKUP_DIR" "$LOG_DIR" "$ZIP_BACKUP_DIR" "$TMP_DIR"
  cat > "$BACKUP_ROOT/.htaccess" <<'HTACCESS'
Require all denied
Deny from all
HTACCESS
  echo "Clip24 backup folder. Do not delete." > "$BACKUP_ROOT/README.txt"
  touch "$LOG_FILE"
}

assert_direct_root_package(){
  if [ "$(safe_realpath "$PACKAGE_DIR")" != "$(safe_realpath "$PROJECT_ROOT")" ]; then
    err "Installer protection stopped the process."
    echo "This package must be unzipped directly into: $PROJECT_ROOT"
    echo "Current installer folder is: $PACKAGE_DIR"
    echo "Correct command: cd $PROJECT_ROOT && unzip -o Clip24-v1.0.1.zip && bash clip24-smart-installer.sh"
    exit 1
  fi
  if [ ! -d "$PROJECT_ROOT/backend" ] || [ ! -d "$PROJECT_ROOT/mobile" ]; then
    err "Package source folders are missing in project root. Unzip the ZIP directly inside $PROJECT_ROOT."
    exit 1
  fi
}

composer_cmd(){
  if [ -f "$PROJECT_ROOT/composer.phar" ]; then echo "php composer.phar"; return; fi
  if [ -f "$PACKAGE_DIR/composer.phar" ]; then echo "php $PACKAGE_DIR/composer.phar"; return; fi
  if command -v composer >/dev/null 2>&1; then echo "composer"; return; fi
  echo ""
}

require_cmd(){
  if ! command -v "$1" >/dev/null 2>&1; then warn "$1 is not installed or not available in PATH."; return 1; fi
  return 0
}

set_env_value(){
  local key="$1" value="$2" file="$PROJECT_ROOT/.env"
  [ -f "$file" ] || touch "$file"
  if grep -q "^${key}=" "$file"; then
    sed -i "s|^${key}=.*|${key}=${value}|" "$file"
  else
    printf '%s=%s\n' "$key" "$value" >> "$file"
  fi
}

write_env_defaults(){
  step "Writing Clip24 environment defaults"
  if [ ! -f "$PROJECT_ROOT/.env" ] && [ -f "$PROJECT_ROOT/.env.example" ]; then
    cp "$PROJECT_ROOT/.env.example" "$PROJECT_ROOT/.env"
  fi
  set_env_value "APP_URL" "https://$DOMAIN"
  set_env_value "CLIP24_DOMAIN" "$DOMAIN"
  set_env_value "CLIP24_ADMIN_PREFIX" "clip24-admin"
  set_env_value "CLIP24_API_PREFIX" "clip24"
  set_env_value "CLIP24_CACHE_ENABLED" "true"
  set_env_value "CLIP24_CACHE_STORE" "file"
  set_env_value "CLIP24_CACHE_PREFIX" "clip24"
  set_env_value "CLIP24_FEED_CACHE_TTL" "60"
  set_env_value "CLIP24_PROFILE_CACHE_TTL" "300"
}

move_original_zip_to_backup(){
  ensure_backup_dirs
  step "Moving ZIP package to backup ZIP folder"
  local moved=0 ts zip base dest
  ts="$(date +%Y%m%d-%H%M%S)"
  for zip in "$PROJECT_ROOT"/Clip24-v*.zip "$PROJECT_ROOT"/clip24-v*.zip "$PROJECT_ROOT"/Clip24*.zip "$PROJECT_ROOT"/clip24*.zip; do
    [ -f "$zip" ] || continue
    base="$(basename "$zip")"
    dest="$ZIP_BACKUP_DIR/${ts}-${base}"
    mv "$zip" "$dest"
    log "ZIP moved to: $dest"
    moved=1
  done
  if [ "$moved" -eq 0 ]; then
    warn "No Clip24 ZIP file found in $PROJECT_ROOT to move. If you uploaded it elsewhere, move it manually to $ZIP_BACKUP_DIR."
  fi
}

backup_project(){
  protect_path; ensure_backup_dirs
  local ts dest
  ts="$(date +%Y%m%d-%H%M%S)"
  dest="$PROJECT_BACKUP_DIR/clip24-project-backup-$ts.tar.gz"
  step "Creating project backup"
  if [ -d "$PROJECT_ROOT" ] && [ "$(find "$PROJECT_ROOT" -mindepth 1 -maxdepth 1 2>/dev/null | wc -l)" -gt 0 ]; then
    tar \
      --exclude='./clip24-backups' \
      --exclude='./vendor' \
      --exclude='./node_modules' \
      --exclude='./storage/framework/cache/*' \
      --exclude='./storage/framework/views/*' \
      --exclude='./storage/framework/sessions/*' \
      --exclude='./storage/logs/*.log' \
      -czf "$dest" -C "$PROJECT_ROOT" .
    log "Project backup created: $dest"
  else
    warn "Project root is empty. Project backup skipped."
  fi
}

backup_database(){
  protect_path; ensure_backup_dirs
  step "Creating database backup when possible"
  if [ ! -f "$PROJECT_ROOT/.env" ] || ! command -v mysqldump >/dev/null 2>&1; then
    warn "Database backup skipped. .env or mysqldump not available."
    return 0
  fi
  local db user pass host port ts dest
  db="$(grep -E '^DB_DATABASE=' "$PROJECT_ROOT/.env" | tail -n1 | cut -d= -f2- | tr -d '"')"
  user="$(grep -E '^DB_USERNAME=' "$PROJECT_ROOT/.env" | tail -n1 | cut -d= -f2- | tr -d '"')"
  pass="$(grep -E '^DB_PASSWORD=' "$PROJECT_ROOT/.env" | tail -n1 | cut -d= -f2- | tr -d '"')"
  host="$(grep -E '^DB_HOST=' "$PROJECT_ROOT/.env" | tail -n1 | cut -d= -f2- | tr -d '"')"; host="${host:-127.0.0.1}"
  port="$(grep -E '^DB_PORT=' "$PROJECT_ROOT/.env" | tail -n1 | cut -d= -f2- | tr -d '"')"; port="${port:-3306}"
  [ -n "$db" ] && [ -n "$user" ] || { warn "Database name/user missing in .env. Database backup skipped."; return 0; }
  ts="$(date +%Y%m%d-%H%M%S)"; dest="$DB_BACKUP_DIR/clip24-db-backup-$ts.sql.gz"
  MYSQL_PWD="$pass" mysqldump -h "$host" -P "$port" -u "$user" "$db" | gzip > "$dest" && log "Database backup created: $dest" || warn "Database backup failed. Check DB credentials."
}

check_requirements(){
  protect_path; ensure_backup_dirs
  step "Checking requirements"
  echo "Domain      : $DOMAIN"
  echo "Project root: $PROJECT_ROOT"
  echo "Package dir : $PACKAGE_DIR"
  echo "Backup dir  : $BACKUP_ROOT"
  echo "ZIP folder  : $ZIP_BACKUP_DIR"
  require_cmd php || true
  php -v 2>/dev/null | head -n 1 || true
  local ccmd; ccmd="$(composer_cmd)"
  if [ -z "$ccmd" ]; then warn "Composer not found. Upload composer.phar or install Composer."; else log "Composer command: $ccmd"; fi
  require_cmd mysql || warn "mysql client missing. Migrations can still run if Laravel DB is configured."
  require_cmd mysqldump || warn "mysqldump missing. Database backup will be skipped."
  require_cmd ffmpeg || warn "FFmpeg missing. Video compression and thumbnails will not work until installed."
  require_cmd ffprobe || warn "FFprobe missing. Video duration detection will be limited."
  require_cmd node || warn "Node.js missing. Needed only for mobile app development."
  require_cmd npm || warn "npm missing. Needed only for mobile app development."
  if [ -f "$PROJECT_ROOT/artisan" ]; then log "Laravel artisan found."; else warn "Laravel artisan not found. Installer will create a fresh Laravel project."; fi
}

create_laravel_if_missing(){
  if [ -f "$PROJECT_ROOT/artisan" ]; then return 0; fi
  step "Laravel project not found — creating fresh Laravel project"
  local ccmd tmp
  ccmd="$(composer_cmd)"
  if [ -z "$ccmd" ]; then err "Composer not found. Cannot create Laravel project."; exit 1; fi
  tmp="$TMP_DIR/laravel-$(date +%Y%m%d-%H%M%S)"
  log "Creating Laravel in temporary folder: $tmp"
  (cd "$TMP_DIR" && $ccmd create-project laravel/laravel "$(basename "$tmp")")
  log "Copying Laravel files into project root without creating a subfolder."
  (cd "$tmp" && tar -cf - .) | (cd "$PROJECT_ROOT" && tar -xf -)
}

copy_backend_files(){
  assert_direct_root_package
  step "Copying Clip24 backend files into project root"
  (cd "$PROJECT_ROOT/backend" && tar -cf - .) | (cd "$PROJECT_ROOT" && tar -xf -)

  mkdir -p "$PROJECT_ROOT/routes"
  touch "$PROJECT_ROOT/routes/api.php" "$PROJECT_ROOT/routes/web.php" "$PROJECT_ROOT/routes/console.php"

  grep -q "clip24_api.php" "$PROJECT_ROOT/routes/api.php" || echo "require __DIR__.'/clip24_api.php';" >> "$PROJECT_ROOT/routes/api.php"
  grep -q "clip24_web.php" "$PROJECT_ROOT/routes/web.php" || echo "require __DIR__.'/clip24_web.php';" >> "$PROJECT_ROOT/routes/web.php"
  grep -q "clip24_console.php" "$PROJECT_ROOT/routes/console.php" || echo "require __DIR__.'/clip24_console.php';" >> "$PROJECT_ROOT/routes/console.php"
}

install_backend(){
  protect_path; ensure_backup_dirs; assert_direct_root_package
  check_requirements
  backup_project
  backup_database
  create_laravel_if_missing
  write_env_defaults
  copy_backend_files

  step "Installing Composer dependencies"
  local ccmd; ccmd="$(composer_cmd)"
  if [ -n "$ccmd" ]; then
    (cd "$PROJECT_ROOT" && $ccmd install --no-dev --optimize-autoloader || $ccmd install --optimize-autoloader)
  else
    warn "Composer not available. Skipping composer install."
  fi

  step "Preparing Laravel"
  if [ -f "$PROJECT_ROOT/artisan" ]; then
    (cd "$PROJECT_ROOT" && php artisan key:generate --force || true)
    (cd "$PROJECT_ROOT" && php artisan migrate --force)
    (cd "$PROJECT_ROOT" && php artisan db:seed --class=Clip24Seeder --force || true)
    (cd "$PROJECT_ROOT" && php artisan storage:link || true)
    clear_cache
    fix_permissions
    move_original_zip_to_backup
  else
    err "artisan not found after install. Check Laravel installation."
    exit 1
  fi

  log "Clip24 backend installed for https://$DOMAIN"
  show_admin_login
}

repair_backend(){
  protect_path; ensure_backup_dirs; assert_direct_root_package
  backup_project
  backup_database
  write_env_defaults
  copy_backend_files
  if [ -f "$PROJECT_ROOT/artisan" ]; then
    (cd "$PROJECT_ROOT" && php artisan migrate --force || true)
    (cd "$PROJECT_ROOT" && php artisan db:seed --class=Clip24Seeder --force || true)
    clear_cache
    fix_permissions
    move_original_zip_to_backup
  fi
  log "Repair completed."
}

clear_cache(){
  protect_path; ensure_backup_dirs
  step "Clearing Laravel and Clip24 cache"
  if [ -f "$PROJECT_ROOT/artisan" ]; then
    (cd "$PROJECT_ROOT" && php artisan clip24:cache-clear --laravel || true)
    (cd "$PROJECT_ROOT" && php artisan optimize:clear || true)
    (cd "$PROJECT_ROOT" && php artisan config:clear || true)
    (cd "$PROJECT_ROOT" && php artisan route:clear || true)
    (cd "$PROJECT_ROOT" && php artisan view:clear || true)
  else
    warn "artisan not found. Cache clear skipped."
  fi
}

fix_permissions(){
  protect_path; ensure_backup_dirs
  step "Fixing permissions"
  mkdir -p "$PROJECT_ROOT/storage" "$PROJECT_ROOT/bootstrap/cache" "$PROJECT_ROOT/storage/framework/cache/data" "$PROJECT_ROOT/storage/framework/views" "$PROJECT_ROOT/storage/framework/sessions"
  chmod -R ug+rwX "$PROJECT_ROOT/storage" "$PROJECT_ROOT/bootstrap/cache" "$BACKUP_ROOT" 2>/dev/null || true
  log "Permissions fixed for storage, bootstrap/cache, and backup folder."
}

restore_latest_backup(){
  protect_path; ensure_backup_dirs
  local latest
  latest="$(ls -1t "$PROJECT_BACKUP_DIR"/clip24-project-backup-*.tar.gz 2>/dev/null | head -n 1 || true)"
  if [ -z "$latest" ]; then err "No project backup found in $PROJECT_BACKUP_DIR"; return 1; fi
  warn "This will replace files in $PROJECT_ROOT with backup: $latest"
  confirm "Continue restore?" || return 0
  find "$PROJECT_ROOT" -mindepth 1 -maxdepth 1 ! -name "clip24-backups" -exec rm -rf {} +
  tar -xzf "$latest" -C "$PROJECT_ROOT"
  log "Restore completed from $latest"
}

uninstall_clip24(){
  protect_path; ensure_backup_dirs
  warn "This removes Clip24 installed files. Backups remain in $BACKUP_ROOT."
  confirm "Continue uninstall?" || return 0
  backup_project
  backup_database
  rm -rf \
    "$PROJECT_ROOT/app/Models/Clip24" \
    "$PROJECT_ROOT/app/Http/Controllers/Clip24" \
    "$PROJECT_ROOT/app/Http/Middleware/Clip24" \
    "$PROJECT_ROOT/app/Services/Clip24" \
    "$PROJECT_ROOT/resources/views/clip24" \
    "$PROJECT_ROOT/config/clip24.php" \
    "$PROJECT_ROOT/routes/clip24_api.php" \
    "$PROJECT_ROOT/routes/clip24_web.php" \
    "$PROJECT_ROOT/routes/clip24_console.php"
  find "$PROJECT_ROOT/database/migrations" -type f -name '*clip24*' -delete 2>/dev/null || true
  rm -f "$PROJECT_ROOT/database/seeders/Clip24Seeder.php"
  if [ -f "$PROJECT_ROOT/artisan" ] && confirm "Drop Clip24 database tables too?"; then
    (cd "$PROJECT_ROOT" && php artisan tinker --execute="DB::statement('SET FOREIGN_KEY_CHECKS=0'); foreach(['clip24_notifications','clip24_reports','clip24_video_hashtags','clip24_hashtags','clip24_video_comments','clip24_video_likes','clip24_follows','clip24_videos','clip24_user_tokens','clip24_users','clip24_country_rules','clip24_settings','clip24_admins'] as \$t){ Schema::dropIfExists(\$t); } DB::statement('SET FOREIGN_KEY_CHECKS=1');" || true)
  fi
  clear_cache
  log "Uninstall completed."
}

emergency_cleanup(){
  protect_path; ensure_backup_dirs
  step "Emergency cleanup"
  rm -rf "$PROJECT_ROOT/bootstrap/cache"/*.php 2>/dev/null || true
  rm -rf "$PROJECT_ROOT/storage/framework/cache/data"/* 2>/dev/null || true
  rm -rf "$PROJECT_ROOT/storage/framework/views"/* 2>/dev/null || true
  rm -rf "$PROJECT_ROOT/storage/framework/sessions"/* 2>/dev/null || true
  clear_cache
  fix_permissions
  log "Emergency cleanup completed."
}

setup_cron(){
  protect_path; ensure_backup_dirs
  step "Setting up cron"
  local video_line cache_line
  video_line="* * * * * cd $PROJECT_ROOT && php artisan clip24:process-videos >> storage/logs/clip24-video-cron.log 2>&1"
  cache_line="*/10 * * * * cd $PROJECT_ROOT && php artisan clip24:cache-warm --countries=DE,PK,AT,CH >> storage/logs/clip24-cache-cron.log 2>&1"
  (crontab -l 2>/dev/null | grep -v "clip24:process-videos" | grep -v "clip24:cache-warm"; echo "$video_line"; echo "$cache_line") | crontab -
  log "Cron installed: $video_line"
  log "Cron installed: $cache_line"
}

show_admin_login(){
  echo ""
  echo "Domain    : https://$DOMAIN"
  echo "Admin URL : https://$DOMAIN/clip24-admin/login"
  echo "Email     : $DEFAULT_ADMIN_EMAIL"
  echo "Password  : $DEFAULT_ADMIN_PASSWORD"
  echo "Backup dir: $BACKUP_ROOT"
  echo "ZIP dir   : $ZIP_BACKUP_DIR"
  echo "Please change the password immediately."
}

menu(){
  clear || true
  echo -e "${CLR_BOLD}${APP_NAME} ${APP_VERSION} Smart Protected Installer${CLR_RESET}"
  echo "Domain      : $DOMAIN"
  echo "Project root: $PROJECT_ROOT"
  echo "Backup root : $BACKUP_ROOT"
  echo ""
  echo "1) Install backend"
  echo "2) Repair backend files"
  echo "3) Clear Laravel + Clip24 cache"
  echo "4) Backup project"
  echo "5) Backup database"
  echo "6) Restore latest project backup"
  echo "7) Uninstall Clip24"
  echo "8) Emergency cleanup"
  echo "9) Fix permissions"
  echo "10) Check requirements"
  echo "11) Setup cron"
  echo "12) Move ZIP to backup/zips"
  echo "13) Show admin login"
  echo "0) Exit"
  echo ""
  read -r -p "Choose option: " choice
  case "$choice" in
    1) install_backend ;;
    2) repair_backend ;;
    3) clear_cache ;;
    4) backup_project ;;
    5) backup_database ;;
    6) restore_latest_backup ;;
    7) uninstall_clip24 ;;
    8) emergency_cleanup ;;
    9) fix_permissions ;;
    10) check_requirements ;;
    11) setup_cron ;;
    12) move_original_zip_to_backup ;;
    13) show_admin_login ;;
    0) exit 0 ;;
    *) warn "Invalid option" ;;
  esac
}

protect_path
ensure_backup_dirs

if [ "${1:-}" = "--install" ]; then install_backend; exit 0; fi
if [ "${1:-}" = "--repair" ]; then repair_backend; exit 0; fi
if [ "${1:-}" = "--cache" ]; then clear_cache; exit 0; fi
if [ "${1:-}" = "--backup" ]; then backup_project; backup_database; exit 0; fi
if [ "${1:-}" = "--cron" ]; then setup_cron; exit 0; fi
if [ "${1:-}" = "--move-zip" ]; then move_original_zip_to_backup; exit 0; fi

while true; do
  menu
  echo ""
  read -r -p "Press Enter to continue..." _ || true
done
