#!/bin/bash

# ==========================================
# System Cleanup Script for macOS
# ==========================================
#
# This script helps clean up various caches and temporary files to free up disk space.
# Use with caution - while this script tries to be safe, it's always good to have backups.
#
# Features:
# - Clean development tool caches (Homebrew, npm, pip, etc.)
# - Clean browser caches (Chrome, Firefox, Safari)
# - Clean application caches
# - Clean system caches and logs
# - Interactive menu to choose what to clean
# - Size reporting before and after cleaning
#
# Author: Saravana
# Created: 2025-05-21
# ==========================================

# ==========================================
# Color Definitions
# ==========================================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

# ==========================================
# Helper Functions
# ==========================================

# Print with color
print_header() {
    echo -e "\n${CYAN}===== $1 =====${NC}\n"
}

print_info() {
    echo -e "${BLUE}INFO: $1${NC}"
}

print_warning() {
    echo -e "${YELLOW}WARNING: $1${NC}"
}

print_error() {
    echo -e "${RED}ERROR: $1${NC}"
}

print_success() {
    echo -e "${GREEN}SUCCESS: $1${NC}"
}

print_size() {
    path="$1"
    if [ -e "$path" ]; then
        size=$(du -sh "$path" 2>/dev/null | cut -f1)
        echo -e "${PURPLE}Size of $path: $size${NC}"
    else
        echo -e "${PURPLE}$path does not exist${NC}"
    fi
}

# Check if a directory exists and has content
check_directory() {
    local dir="$1"
    if [ -d "$dir" ] && [ "$(ls -A "$dir" 2>/dev/null)" ]; then
        return 0
    else
        return 1
    fi
}

# Get directory size in human-readable format
get_dir_size() {
    local dir="$1"
    if [ -d "$dir" ]; then
        du -sh "$dir" 2>/dev/null | cut -f1
    else
        echo "0B"
    fi
}

# Get directory size in bytes
get_dir_size_bytes() {
    local dir="$1"
    if [ -d "$dir" ]; then
        du -s "$dir" 2>/dev/null | cut -f1
    else
        echo "0"
    fi
}

# Get free disk space
get_free_space() {
    df -h . | awk 'NR==2 {print $4}'
}

# Confirm action
confirm() {
    local prompt="$1"
    local default="$2"
    
    if [ "$default" = "y" ]; then
        local prompt_text="${prompt} [Y/n] "
    else
        local prompt_text="${prompt} [y/N] "
    fi
    
    read -p "$prompt_text" response
    
    if [ -z "$response" ]; then
        response="$default"
    fi
    
    if [[ "$response" =~ ^[Yy]$ ]]; then
        return 0
    else
        return 1
    fi
}

# ==========================================
# Cleanup Functions
# ==========================================

# Clean Development Tool Caches
clean_dev_caches() {
    print_header "Cleaning Development Tool Caches"
    
    # Homebrew
    if check_directory "$HOME/homebrew/Caches" || check_directory "$HOME/Library/Caches/Homebrew"; then
        print_info "Cleaning Homebrew caches..."
        before_size=$(get_dir_size "$HOME/Library/Caches/Homebrew")
        if confirm "Run 'brew cleanup' to remove old versions and downloads? This will free up space but require re-downloading if needed again." "y"; then
            brew cleanup -s
            rm -rf "$HOME/Library/Caches/Homebrew"/*
            print_success "Homebrew cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Caches/Homebrew")"
        fi
    fi
    
    # Node/npm
    if check_directory "$HOME/.npm"; then
        print_info "Cleaning npm cache..."
        before_size=$(get_dir_size "$HOME/.npm")
        if confirm "Clean npm cache?" "y"; then
            npm cache clean --force
            print_success "npm cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/.npm")"
        fi
    fi
    
    # pnpm
    if check_directory "$HOME/.pnpm-store" || check_directory "$HOME/Library/Caches/pnpm"; then
        print_info "Cleaning pnpm cache..."
        before_size=$(get_dir_size "$HOME/.pnpm-store")
        before_size2=$(get_dir_size "$HOME/Library/Caches/pnpm")
        if confirm "Clean pnpm cache?" "y"; then
            if command -v pnpm &>/dev/null; then
                pnpm store prune
            fi
            rm -rf "$HOME/Library/Caches/pnpm"/*
            print_success "pnpm cache cleaned. Before: $before_size + $before_size2, After: $(get_dir_size "$HOME/.pnpm-store") + $(get_dir_size "$HOME/Library/Caches/pnpm")"
        fi
    fi
    
    # Yarn
    if check_directory "$HOME/.yarn/cache"; then
        print_info "Cleaning Yarn cache..."
        before_size=$(get_dir_size "$HOME/.yarn/cache")
        if confirm "Clean Yarn cache?" "y"; then
            if command -v yarn &>/dev/null; then
                yarn cache clean
            fi
            print_success "Yarn cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/.yarn/cache")"
        fi
    fi
    
    # pip
    if check_directory "$HOME/Library/Caches/pip"; then
        print_info "Cleaning pip cache..."
        before_size=$(get_dir_size "$HOME/Library/Caches/pip")
        if confirm "Clean pip cache?" "y"; then
            if command -v pip &>/dev/null; then
                pip cache purge
            fi
            rm -rf "$HOME/Library/Caches/pip"/*
            print_success "pip cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Caches/pip")"
        fi
    fi
    
    # Cypress
    if check_directory "$HOME/Library/Caches/Cypress"; then
        print_info "Cleaning Cypress cache..."
        before_size=$(get_dir_size "$HOME/Library/Caches/Cypress")
        if confirm "Clean Cypress cache? This includes browser binaries that will need to be re-downloaded." "y"; then
            rm -rf "$HOME/Library/Caches/Cypress"/*
            print_success "Cypress cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Caches/Cypress")"
        fi
    fi
    
    # Playwright
    if check_directory "$HOME/Library/Caches/ms-playwright"; then
        print_info "Cleaning Playwright browsers cache..."
        before_size=$(get_dir_size "$HOME/Library/Caches/ms-playwright")
        if confirm "Clean Playwright browsers cache? These will need to be re-downloaded if used again." "y"; then
            rm -rf "$HOME/Library/Caches/ms-playwright"/*
            print_success "Playwright cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Caches/ms-playwright")"
        fi
    fi
    
    # Gradle
    if check_directory "$HOME/.gradle/caches"; then
        print_info "Cleaning Gradle cache..."
        before_size=$(get_dir_size "$HOME/.gradle/caches")
        if confirm "Clean Gradle cache?" "y"; then
            rm -rf "$HOME/.gradle/caches"/*
            print_success "Gradle cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/.gradle/caches")"
        fi
    fi
    
    # CocoaPods
    if check_directory "$HOME/Library/Caches/CocoaPods"; then
        print_info "Cleaning CocoaPods cache..."
        before_size=$(get_dir_size "$HOME/Library/Caches/CocoaPods")
        if confirm "Clean CocoaPods cache?" "y"; then
            rm -rf "$HOME/Library/Caches/CocoaPods"/*
            print_success "CocoaPods cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Caches/CocoaPods")"
        fi
    fi
    
    # Go modules
    if check_directory "$HOME/go/pkg/mod"; then
        print_info "Cleaning Go module cache..."
        before_size=$(get_dir_size "$HOME/go/pkg/mod")
        if confirm "Clean Go module cache? These will be re-downloaded when needed." "y"; then
            if command -v go &>/dev/null; then
                go clean -modcache
            fi
            print_success "Go module cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/go/pkg/mod")"
        fi
    fi
}

# Clean Browser Caches
clean_browser_caches() {
    print_header "Cleaning Browser Caches"
    
    # Check and close browsers first
    for browser in "Firefox" "Google Chrome" "Safari" "Microsoft Edge" "Brave Browser"; do
        if pgrep "$browser" >/dev/null; then
            print_warning "$browser is currently running."
            if confirm "Would you like to close $browser before cleaning its cache?" "y"; then
                osascript -e "tell application \"$browser\" to quit"
                sleep 2
            else
                print_warning "Skipping $browser cleanup to avoid potential issues."
                continue
            fi
        fi
        
        case "$browser" in
            "Firefox")
                if check_directory "$HOME/Library/Caches/Firefox"; then
                    print_info "Cleaning Firefox cache..."
                    before_size=$(get_dir_size "$HOME/Library/Caches/Firefox")
                    if confirm "Clean Firefox cache?" "y"; then
                        rm -rf "$HOME/Library/Caches/Firefox"/*
                        print_success "Firefox cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Caches/Firefox")"
                    fi
                fi
                ;;
                
            "Google Chrome")
                if check_directory "$HOME/Library/Caches/Google/Chrome"; then
                    print_info "Cleaning Chrome cache..."
                    before_size=$(get_dir_size "$HOME/Library/Caches/Google/Chrome")
                    if confirm "Clean Chrome cache?" "y"; then
                        rm -rf "$HOME/Library/Caches/Google/Chrome"/*
                        print_success "Chrome cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Caches/Google/Chrome")"
                    fi
                fi
                ;;
                
            "Safari")
                if check_directory "$HOME/Library/Caches/com.apple.Safari"; then
                    print_info "Cleaning Safari cache..."
                    if confirm "Clean Safari cache?" "y"; then
                        print_warning "Safari caches require administrator privileges."
                        if confirm "Run with sudo (will prompt for password)?" "n"; then
                            sudo rm -rf "$HOME/Library/Caches/com.apple.Safari"/*
                            print_success "Safari cache cleaned."
                        fi
                    fi
                fi
                ;;
                
            "Microsoft Edge")
                if check_directory "$HOME/Library/Caches/Microsoft Edge"; then
                    print_info "Cleaning Microsoft Edge cache..."
                    before_size=$(get_dir_size "$HOME/Library/Caches/Microsoft Edge")
                    if confirm "Clean Microsoft Edge cache?" "y"; then
                        rm -rf "$HOME/Library/Caches/Microsoft Edge"/*
                        print_success "Microsoft Edge cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Caches/Microsoft Edge")"
                    fi
                fi
                ;;
                
            "Brave Browser")
                if check_directory "$HOME/Library/Caches/BraveSoftware/Brave-Browser"; then
                    print_info "Cleaning Brave Browser cache..."
                    before_size=$(get_dir_size "$HOME/Library/Caches/BraveSoftware/Brave-Browser")
                    if confirm "Clean Brave Browser cache?" "y"; then
                        rm -rf "$HOME/Library/Caches/BraveSoftware/Brave-Browser"/*
                        print_success "Brave Browser cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Caches/BraveSoftware/Brave-Browser")"
                    fi
                fi
                ;;
        esac
    done
}

# Clean Application Caches
clean_app_caches() {
    print_header "Cleaning Application Caches"
    
    # Check for common application caches
    cache_dir="$HOME/Library/Caches"
    
    # List large application caches
    print_info "Scanning for large application caches..."
    
    # Get top 10 largest cache directories
    large_caches=$(find "$cache_dir" -type d -maxdepth 1 2>/dev/null | xargs du -sh 2>/dev/null | sort -hr | head -n 10)
    
    echo -e "${YELLOW}Largest application caches:${NC}"
    echo "$large_caches"
    echo
    
    # Spotify
    if check_directory "$HOME/Library/Caches/com.spotify.client"; then
        print_info "Cleaning Spotify cache..."
        before_size=$(get_dir_size "$HOME/Library/Caches/com.spotify.client")
        if confirm "Clean Spotify cache? This may remove offline songs." "n"; then
            rm -rf "$HOME/Library/Caches/com.spotify.client"/*
            print_success "Spotify cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Caches/com.spotify.client")"
        fi
    fi
    
    # Slack
    if check_directory "$HOME/Library/Caches/com.tinyspeck.slackmacgap"; then
        print_info "Cleaning Slack cache..."
        before_size=$(get_dir_size "$HOME/Library/Caches/com.tinyspeck.slackmacgap")
        if confirm "Clean Slack cache?" "y"; then
            rm -rf "$HOME/Library/Caches/com.tinyspeck.slackmacgap"/*
            print_success "Slack cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Caches/com.tinyspeck.slackmacgap")"
        fi
    fi
    
    # Visual Studio Code
    if check_directory "$HOME/Library/Caches/com.microsoft.VSCode"; then
        print_info "Cleaning VS Code cache..."
        before_size=$(get_dir_size "$HOME/Library/Caches/com.microsoft.VSCode")
        if confirm "Clean VS Code cache?" "y"; then
            rm -rf "$HOME/Library/Caches/com.microsoft.VSCode"/*
            print_success "VS Code cache cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Caches/com.microsoft.VSCode")"
        fi
    fi
    
    # Docker
    if check_directory "$HOME/Library/Containers/com.docker.docker"; then
        print_info "Found Docker containers cache..."
        before_size=$(get_dir_size "$HOME/Library/Containers/com.docker.docker")
        if confirm "Would you like to see Docker disk usage? (This will run 'docker system df')" "y"; then
            if command -v docker &>/dev/null; then
                docker system df
                if confirm "Clean unused Docker data? (This will run 'docker system prune')" "n"; then
                    docker system prune -f
                    print_success "Docker unused data cleaned."
                fi
            else
                print_error "Docker command not found."
            fi
        fi
    fi
    
    # Clean other large caches
    if confirm "Would you like to see and clean other large application caches?" "y"; then
        print_info "Select cache directories to clean (enter numbers separated by space):"
        
        # Get all cache directories
        cache_dirs=()
        while IFS= read -r line; do
            cache_dirs+=("$line")
        done < <(find "$cache_dir" -type d -maxdepth 1 2>/dev/null | sort)
        
        # Get sizes for each directory
        cache_sizes=()
        for dir in "${cache_dirs[@]}"; do
            if [ -d "$dir" ]; then
                size=$(du -sh "$dir" 2>/dev/null | cut -f1)
                cache_sizes+=("$size")
            else
                cache_sizes+=("")
            fi
        done
        
        # Display directories with their sizes
        for i in "${!cache_dirs[@]}"; do
            if [ -n "${cache_sizes[$i]}" ] && [ "${cache_dirs[$i]}" != "$cache_dir" ]; then
                echo "$i) ${cache_sizes[$i]} - ${cache_dirs[$i]}"
            fi
        done
        
        read -p "Enter numbers to clean (or 'all' for all, 'skip' to skip): " selections
        
        if [ "$selections" = "all" ]; then
            for i in "${!cache_dirs[@]}"; do
                if [ "${cache_dirs[$i]}" != "$cache_dir" ] && [ -d "${cache_dirs[$i]}" ]; then
                    dir_name=$(basename "${cache_dirs[$i]}")
                    if confirm "Clean $dir_name (${cache_sizes[$i]})?" "n"; then
                        before_size=$(get_dir_size "${cache_dirs[$i]}")
                        rm -rf "${cache_dirs[$i]}"/*
                        print_success "$dir_name cache cleaned. Before: $before_size, After: $(get_dir_size "${cache_dirs[$i]}")"
                    fi
                fi
            done
        elif [ "$selections" != "skip" ]; then
            for sel in $selections; do
                if [ -n "${cache_dirs[$sel]}" ] && [ "${cache_dirs[$sel]}" != "$cache_dir" ]; then
                    dir_name=$(basename "${cache_dirs[$sel]}")
                    before_size=$(get_dir_size "${cache_dirs[$sel]}")
                    rm -rf "${cache_dirs[$sel]}"/*
                    print_success "$dir_name cache cleaned. Before: $before_size, After: $(get_dir_size "${cache_dirs[$sel]}")"
                fi
            done
        fi
    fi
}

# Clean System Caches and Logs
clean_system_caches() {
    print_header "Cleaning System Caches and Logs"
    
    # macOS system logs
    print_info "Checking system logs..."
    if confirm "Clean system logs? This requires administrator privileges." "n"; then
        print_warning "This will clear system logs. You'll be prompted for your password."
        sudo rm -rf /private/var/log/*
        print_success "System logs cleaned."
    fi
    
    # Temporary files
    print_info "Checking temporary files..."
    before_size=$(get_dir_size /tmp)
    if confirm "Clean temporary files in /tmp?" "y"; then
        rm -rf /tmp/* 2>/dev/null
        print_success "Temporary files cleaned. Before: $before_size, After: $(get_dir_size /tmp)"
    fi
    
    # User cache
    print_info "Checking user cache..."
    before_size=$(get_dir_size "$HOME/Library/Caches")
    if confirm "Clean all user caches? (This is aggressive and may remove important cached data)" "n"; then
        find "$HOME/Library/Caches" -depth 1 -not -name "." -not -name ".." -exec rm -rf {} \; 2>/dev/null
        print_success "User caches cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Caches")"
    fi
    
    # Clear DNS cache
    if confirm "Clear DNS cache?" "y"; then
        sudo dscacheutil -flushcache
        sudo killall -HUP mDNSResponder
        print_success "DNS cache flushed."
    fi
    
    # Application logs
    if check_directory "$HOME/Library/Logs"; then
        print_info "Checking application logs..."
        before_size=$(get_dir_size "$HOME/Library/Logs")
        if confirm "Clean application logs?" "y"; then
            find "$HOME/Library/Logs" -type f -delete 2>/dev/null
            print_success "Application logs cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Logs")"
        fi
    fi
    
    # XCode derived data
    if check_directory "$HOME/Library/Developer/Xcode/DerivedData"; then
        print_info "Checking XCode derived data..."
        before_size=$(get_dir_size "$HOME/Library/Developer/Xcode/DerivedData")
        if confirm "Clean XCode derived data? This is safe but will require rebuilding projects." "y"; then
            rm -rf "$HOME/Library/Developer/Xcode/DerivedData"/*
            print_success "XCode derived data cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Developer/Xcode/DerivedData")"
        fi
    fi
    
    # iOS Device Support files
    if check_directory "$HOME/Library/Developer/Xcode/iOS DeviceSupport"; then
        print_info "Checking iOS Device Support files..."
        before_size=$(get_dir_size "$HOME/Library/Developer/Xcode/iOS DeviceSupport")
        if confirm "Clean iOS Device Support files? These will be recreated when you connect iOS devices." "y"; then
            rm -rf "$HOME/Library/Developer/Xcode/iOS DeviceSupport"/*
            print_success "iOS Device Support files cleaned. Before: $before_size, After: $(get_dir_size "$HOME/Library/Developer/Xcode/iOS DeviceSupport")"
        fi
    fi
    
    # macOS trash
    print_info "Checking trash bin..."
    if [ -d "$HOME/.Trash" ]; then
        before_size=$(get_dir_size "$HOME/.Trash")
        if [ "$before_size" != "0B" ]; then
            if confirm "Empty trash bin? This action cannot be undone." "n"; then
                rm -rf "$HOME/.Trash"/*
                print_success "Trash emptied. Before: $before_size, After: $(get_dir_size "$HOME/.Trash")"
            fi
        else
            print_info "Trash is already empty."
        fi
    fi
    
    # Software update downloads
    if check_directory "/Library/Updates"; then
        if confirm "Clean software update downloads? This requires administrator privileges." "n"; then
            print_warning "This will clear downloaded software updates. You'll be prompted for your password."
            sudo rm -rf /Library/Updates/*
            print_success "Software update downloads cleaned."
        fi
    fi
}

# Show disk usage summary
show_disk_usage() {
    print_header "Disk Usage Summary"
    
    # System disk usage
    echo -e "${CYAN}System Disk Usage:${NC}"
    df -h / | awk 'NR==1 || NR==2 {print}'
    echo
    
    # User directory sizes
    echo -e "${CYAN}User Directory Sizes:${NC}"
    du -h -d 1 ~ 2>/dev/null | sort -hr | head -n 10
    echo
    
    # Large directories
    echo -e "${CYAN}Large Directories:${NC}"
    du -h -d 2 ~ 2>/dev/null | sort -hr | head -n 5
    echo
    
    # Development caches
    echo -e "${CYAN}Development Tool Caches:${NC}"
    print_size "$HOME/Library/Caches/Homebrew"
    print_size "$HOME/.npm"
    print_size "$HOME/Library/Caches/pip"
    print_size "$HOME/Library/Caches/Cypress"
    print_size "$HOME/Library/Caches/pnpm"
    print_size "$HOME/Library/Caches/ms-playwright"
    echo
    
    # Browser caches
    echo -e "${CYAN}Browser Caches:${NC}"
    print_size "$HOME/Library/Caches/Google/Chrome"
    print_size "$HOME/Library/Caches/Firefox"
    print_size "$HOME/Library/Caches/com.apple.Safari"
    print_size "$HOME/Library/Caches/Microsoft Edge"
    print_size "$HOME/Library/Caches/BraveSoftware/Brave-Browser"
    echo
}

# Main menu
main_menu() {
    local initial_free_space=$(get_free_space)
    
    # Initial disk usage report
    clear
    print_header "MacOS Cleanup Utility"
    echo -e "Current free space: ${GREEN}$initial_free_space${NC}"
    echo
    
    while true; do
        echo -e "${CYAN}Please select an option:${NC}"
        echo "1) Show disk usage summary"
        echo "2) Clean development tool caches"
        echo "3) Clean browser caches"
        echo "4) Clean application caches"
        echo "5) Clean system caches and logs"
        echo "6) Run all cleanups"
        echo "7) Exit"
        echo
        
        read -p "Enter your choice (1-7): " choice
        echo
        
        case $choice in
            1)
                show_disk_usage
                ;;
            2)
                clean_dev_caches
                ;;
            3)
                clean_browser_caches
                ;;
            4)
                clean_app_caches
                ;;
            5)
                clean_system_caches
                ;;
            6)
                print_header "Running All Cleanups"
                print_warning "This will run all cleanup options. You'll be prompted for each action."
                if confirm "Do you want to continue?" "n"; then
                    clean_dev_caches
                    clean_browser_caches
                    clean_app_caches
                    clean_system_caches
                fi
                ;;
            7)
                break
                ;;
            *)
                print_error "Invalid choice. Please enter a number between 1 and 7."
                ;;
        esac
        
        echo
        echo -e "Press Enter to return to the menu..."
        read
        clear
        print_header "MacOS Cleanup Utility"
        echo -e "Current free space: ${GREEN}$(get_free_space)${NC} (was ${BLUE}$initial_free_space${NC})"
        echo
    done
    
    # Show final summary
    local final_free_space=$(get_free_space)
    print_header "Cleanup Complete"
    echo -e "Initial free space: ${BLUE}$initial_free_space${NC}"
    echo -e "Final free space: ${GREEN}$final_free_space${NC}"
    
    # Calculate space saved
    local initial_bytes=$(echo "$initial_free_space" | sed 's/G//g')
    local final_bytes=$(echo "$final_free_space" | sed 's/G//g')
    
    if (( $(echo "$final_bytes > $initial_bytes" | bc -l) )); then
        local saved=$(echo "$final_bytes - $initial_bytes" | bc -l)
        echo -e "You freed approximately ${GREEN}${saved}GB${NC} of disk space!"
    fi
    
    echo
    print_info "Thank you for using the MacOS Cleanup Utility!"
    echo
}

# Run main menu
main_menu
