#!/usr/bin/env bash
# file-organizer.sh - sorts a messy folder into subfolders by file type.
# SAFE BY DEFAULT: prints a preview and changes nothing until -apply.
# Never deletes anything. Never overwrites: a name collision is skipped.
# Ignores hidden files and files with no extension. Top-level only.
# Run: bash file-organizer.sh [path]
#      bash file-organizer.sh [path] -apply

set -u

PATH_TO_SORT="${1:-$HOME/Downloads}"
APPLY="${2:-}"

if [ ! -d "$PATH_TO_SORT" ]; then
  echo "Not a folder: $PATH_TO_SORT" >&2
  exit 1
fi

group_for() {
  case "$1" in
    .pdf|.doc|.docx|.odt|.rtf|.txt|.md|.xls|.xlsx|.ods|.csv|.ppt|.pptx|.odp) echo "Documents" ;;
    .jpg|.jpeg|.png|.gif|.webp|.bmp|.svg|.heic|.raw|.cr2|.nef) echo "Images" ;;
    .mp4|.mkv|.avi|.mov|.wmv|.flv|.webm|.m4v) echo "Video" ;;
    .mp3|.wav|.flac|.aac|.ogg|.m4a|.wma) echo "Audio" ;;
    .zip|.rar|.7z|.tar|.gz|.bz2|.xz|.iso) echo "Archives" ;;
    .js|.ts|.py|.ps1|.sh|.html|.css|.json|.xml|.c|.cpp|.java|.go|.rs|.rb) echo "Code" ;;
    .exe|.msi|.dmg|.deb|.rpm|.appimage) echo "Installers" ;;
    *) echo "Other" ;;
  esac
}

if [ "$APPLY" = "-apply" ]; then
  echo "APPLYING moves in: $PATH_TO_SORT"
else
  echo "PREVIEW ONLY - nothing will be moved. Re-run with -apply to perform these moves."
fi
echo "(this tool only ever moves files; it never deletes or overwrites)"
echo ""

# Collect top-level regular files with an extension, skipping dotfiles.
files=$(find "$PATH_TO_SORT" -maxdepth 1 -type f ! -name '.*' 2>/dev/null)

if [ -z "$files" ]; then
  echo "Nothing to organize (no regular files with an extension found)."
  exit 0
fi

for g in Documents Images Video Audio Archives Code Installers Other; do
  count=0
  lines=""
  while IFS= read -r f; do
    [ -z "$f" ] && continue
    base=$(basename "$f")
    case "$base" in
      *.*) ;;
      *) continue ;;
    esac
    ext=".${base##*.}"
    [ "$(group_for "$ext")" = "$g" ] || continue
    count=$((count + 1))
    lines="$lines$f
"
  done <<EOF
$files
EOF
  [ "$count" -eq 0 ] && continue
  echo "$g/  ($count files)"
  echo "$lines" | while IFS= read -r f; do
    [ -z "$f" ] && continue
    base=$(basename "$f")
    if [ "$APPLY" = "-apply" ]; then
      dest_dir="$PATH_TO_SORT/$g"
      mkdir -p "$dest_dir"
      dest="$dest_dir/$base"
      if [ -e "$dest" ]; then
        echo "  skipped  $base  (a file with that name already exists)"
      elif mv "$f" "$dest" 2>/dev/null; then
        echo "  moved    $base"
      else
        echo "  FAILED   $base  (could not move)"
      fi
    else
      echo "  $base  ->  $g/"
    fi
  done
done

echo ""
if [ "$APPLY" = "-apply" ]; then
  echo "Done. Review the folders and delete anything you no longer need - manually."
else
  echo "Preview complete. Re-run with -apply to perform these moves."
fi