#!/bin/bash
# cleanup.sh
# Script dọn dẹp các ứng dụng nặng và các bản cũ trên macOS
# Sử dụng: bash cleanup.sh

# -----------------------------
# Function: cleanup chung cho thư mục chứa version
#   $1 = label (vd: "Edge", "Edge Updater")
#   $2 = đường dẫn thư mục
# -----------------------------
cleanup_versions() {
    local label="$1"
    local target_dir="$2"

    echo "--- [$label] ---"
    echo "    $target_dir"

    if [ ! -d "$target_dir" ]; then
        echo "    ⚠ Thư mục không tồn tại."
        return
    fi

    pushd "$target_dir" > /dev/null || return

    # Lấy các thư mục version dạng x.y.z.w và sort theo version số.
    local raw_dirs=()
    local d
    shopt -s nullglob
    for d in [0-9]*.[0-9]*.[0-9]*.[0-9]*; do
        [[ -d "$d" ]] && raw_dirs+=("$d")
    done
    shopt -u nullglob

    if [ ${#raw_dirs[@]} -eq 0 ]; then
        echo "    ⚠ Thư mục rỗng, không có phiên bản nào."
        popd > /dev/null
        return
    fi

    local dirs=()
    while IFS= read -r d; do
        [[ -n "$d" ]] && dirs+=("$d")
    done < <(
        printf '%s\n' "${raw_dirs[@]}" |
        awk -F'.' '{ printf "%05d.%05d.%05d.%05d\t%s\n", $1, $2, $3, $4, $0 }' |
        sort |
        cut -f2-
    )

    local last_index=$(( ${#dirs[@]} - 1 ))
    local keep="${dirs[$last_index]}"

    # Helper: lấy size thư mục
    dir_size() { du -sh "$1" 2>/dev/null | cut -f1 | xargs; }

    if [ ${#dirs[@]} -le 1 ]; then
        echo "    ✓ Phiên bản hiện tại: $keep ($(dir_size "$keep")) — không có bản cũ."
        popd > /dev/null
        return
    fi

    echo "    ✓ Giữ lại: $keep ($(dir_size "$keep"))"
    echo "    ✗ Sẽ xóa:"
    local i
    for ((i = 0; i < ${#dirs[@]} - 1; i++)); do
        echo "      - ${dirs[$i]} ($(dir_size "${dirs[$i]}"))"
    done

    local confirm
    read -r -p "    Xác nhận xóa? (Y/n): " confirm
    if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
        echo "    Đã hủy."
        popd > /dev/null
        return
    fi

    for ((i = 0; i < ${#dirs[@]} - 1; i++)); do
        echo "    Đã xóa: ${dirs[$i]}"
        rm -rf -- "${dirs[$i]}"
    done

    popd > /dev/null
}

# -----------------------------
# Function: Cleanup Go mod cache
# -----------------------------
cleanup_go() {
    echo "--- [Go Mod Cache] ---"
    if ! command -v go &> /dev/null; then
        echo "    ⚠ go command not found."
        return
    fi

    local GOMODCACHE
    GOMODCACHE=$(go env GOMODCACHE)
    
    if [ -d "$GOMODCACHE" ]; then
        echo "    $GOMODCACHE"
        local size
        size=$(du -sh "$GOMODCACHE" 2>/dev/null | cut -f1 | xargs)
        echo "    ✗ Sẽ xóa bộ nhớ cache: $size"
        
        local confirm
        read -r -p "    Xác nhận xóa? (Y/n): " confirm
        if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
            echo "    Đã hủy."
            return
        fi
        
        go clean -modcache
        echo "    Đã xong."
    else
        echo "    ✓ Bộ nhớ cache rỗng hoặc không tồn tại."
    fi
}

# -----------------------------
# Function: Cleanup NPM cache
# -----------------------------
cleanup_npm() {
    echo "--- [NPM Cache] ---"
    if ! command -v npm &> /dev/null; then
        echo "    ⚠ npm command not found."
        return
    fi

    local NPM_CACHE
    NPM_CACHE=$(npm config get cache)
    
    if [ -d "$NPM_CACHE" ]; then
        echo "    $NPM_CACHE"
        local size
        # Lưu ý: npm cache size thực tế thường lớn hơn kết quả du vì cấu trúc thư mục phức tạp
        size=$(du -sh "$NPM_CACHE" 2>/dev/null | cut -f1 | xargs)
        echo "    ✗ Sẽ xóa bộ nhớ cache: $size"
        
        local confirm
        read -r -p "    Xác nhận xóa? (Y/n): " confirm
        if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
            echo "    Đã hủy."
            return
        fi
        
        npm cache clean --force
        echo "    Đã xong."
    else
        echo "    ✓ Bộ nhớ cache rỗng hoặc không tồn tại."
    fi
}

# -----------------------------
# Function: Cleanup old VS Code extensions
# Giữ lại phiên bản mới nhất của mỗi extension
# -----------------------------
cleanup_vscode_extensions() {
    echo "--- [VS Code Extensions] ---"
    local EXT_DIR="$HOME/.vscode/extensions"
    echo "    $EXT_DIR"

    if [ ! -d "$EXT_DIR" ]; then
        echo "    ⚠ Thư mục không tồn tại."
        return
    fi

    # Build "ext_id<TAB>dirname" pairs
    local entries=()
    local basename ext_id

    shopt -s nullglob
    for dir in "$EXT_DIR"/*/; do
        basename=$(command basename "$dir")
        [[ "$basename" == .* ]] && continue
        # Extract extension ID: everything before -<version>
        ext_id=$(echo "$basename" | sed 's/-[0-9][0-9.]*.*$//')
        [ -z "$ext_id" ] && continue
        entries+=("${ext_id}"$'\t'"${basename}")
    done
    shopt -u nullglob

    if [ ${#entries[@]} -eq 0 ]; then
        echo "    ⚠ Không có extension nào."
        return
    fi

    # Sort by ext_id (field 1), then by dirname (field 2) for version ordering
    local sorted
    sorted=$(printf '%s\n' "${entries[@]}" | sort -t$'\t' -k1,1 -k2,2)

    # Group by ext_id, find old versions
    local to_delete=()
    local to_keep=()
    local group=()
    local prev_id=""

    while IFS=$'\t' read -r ext_id dirname; do
        if [ -n "$prev_id" ] && [ "$ext_id" != "$prev_id" ]; then
            # Process previous group
            if [ ${#group[@]} -gt 1 ]; then
                local last=$(( ${#group[@]} - 1 ))
                to_keep+=("${group[$last]}")
                local g
                for ((g = 0; g < last; g++)); do
                    to_delete+=("${group[$g]}")
                done
            fi
            group=()
        fi
        group+=("$dirname")
        prev_id="$ext_id"
    done <<< "$sorted"

    # Process last group
    if [ ${#group[@]} -gt 1 ]; then
        local last=$(( ${#group[@]} - 1 ))
        to_keep+=("${group[$last]}")
        local g
        for ((g = 0; g < last; g++)); do
            to_delete+=("${group[$g]}")
        done
    fi

    if [ ${#to_delete[@]} -eq 0 ]; then
        echo "    ✓ Không có extension cũ để xóa."
        return
    fi

    echo "    ✓ Giữ lại (mới nhất):"
    local k
    for k in "${to_keep[@]}"; do
        local size
        size=$(du -sh "$EXT_DIR/$k" 2>/dev/null | cut -f1 | xargs)
        echo "      + $k ($size)"
    done

    echo "    ✗ Sẽ xóa (cũ):"
    local d
    for d in "${to_delete[@]}"; do
        local size
        size=$(du -sh "$EXT_DIR/$d" 2>/dev/null | cut -f1 | xargs)
        echo "      - $d ($size)"
    done

    local confirm
    read -r -p "    Xác nhận xóa? (Y/n): " confirm
    if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
        echo "    Đã hủy."
        return
    fi

    for d in "${to_delete[@]}"; do
        echo "    Đã xóa: $d"
        rm -rf -- "$EXT_DIR/$d"
    done
}

# -----------------------------
# Function: Cleanup old Antigravity browser recordings
# -----------------------------
cleanup_agy_recordings() {
    local days="${1:-7}"
    local rec_dir="$HOME/.gemini/antigravity/browser_recordings"

    echo "--- [Antigravity Recordings] ---"
    echo "    $rec_dir"

    if [ ! -d "$rec_dir" ]; then
        echo "    ⚠ Thư mục không tồn tại."
        return
    fi

    local to_delete=()
    local total_size=0
    local dir

    shopt -s nullglob
    for dir in "$rec_dir"/*/; do
        [ -d "$dir" ] || continue
        local dirname
        dirname=$(basename "$dir")
        local size mod_date
        size=$(du -sh "$dir" 2>/dev/null | cut -f1 | xargs)
        mod_date=$(stat -f "%Sm" -t "%Y-%m-%d" "$dir")

        if [ "$(find "$dir" -maxdepth 0 -mtime +"$days" 2>/dev/null)" ]; then
            echo "      - $dirname ($size, $mod_date)"
            to_delete+=("$dir")
            total_size=$((total_size + $(du -sk "$dir" | cut -f1)))
        else
            echo "      + $dirname ($size, $mod_date) [KEEP]"
        fi
    done
    shopt -u nullglob

    if [ ${#to_delete[@]} -eq 0 ]; then
        echo "    ✓ Không có recording cũ (>${days} ngày) để xóa."
        return
    fi

    local total_human
    total_human=$(echo "scale=1; $total_size / 1024" | bc)
    echo "    ✗ Sẽ xóa ${#to_delete[@]} recording(s), tổng: ${total_human} MiB"

    local confirm
    read -r -p "    Xác nhận xóa? (Y/n): " confirm
    if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
        echo "    Đã hủy."
        return
    fi

    for dir in "${to_delete[@]}"; do
        echo "    Đã xóa: $(basename "$dir")"
        rm -rf -- "$dir"
    done
}

# -----------------------------
# Function: Cleanup Homebrew
# -----------------------------
cleanup_homebrew() {
    echo "--- [Homebrew] ---"
    if ! command -v brew &> /dev/null; then
        echo "    ⚠ brew command not found."
        return
    fi

    echo "    Đang cập nhật Homebrew..."
    brew update --quiet

    local outdated
    outdated=$(brew outdated 2>/dev/null)
    if [ -n "$outdated" ]; then
        echo "    ✗ Các package cần upgrade:"
        echo "$outdated" | sed 's/^/      - /'
        local confirm
        read -r -p "    Upgrade tất cả? (Y/n): " confirm
        if [[ -z "$confirm" || "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
            brew upgrade --quiet
            echo "    Đã upgrade xong."
        else
            echo "    Bỏ qua upgrade."
        fi
    else
        echo "    ✓ Tất cả package đã cập nhật."
    fi

    # Cleanup cache
    local cache_size
    cache_size=$(brew --cache 2>/dev/null)
    if [ -d "$cache_size" ]; then
        local size
        size=$(du -sh "$cache_size" 2>/dev/null | cut -f1 | xargs)
        echo "    ✗ Cache: $size ($cache_size)"
    fi

    echo "    Đang dọn dẹp cache và autoremove..."
    brew cleanup --prune=all -s 2>/dev/null
    brew autoremove 2>/dev/null
    echo "    Đã xong."
}

# -----------------------------
# Function: Cleanup VS Code C++ Tools cache
# -----------------------------
cleanup_vscode_cpptools() {
    local cache_dir="$HOME/Library/Caches/vscode-cpptools"

    echo "--- [VS Code C++ Tools Cache] ---"
    echo "    $cache_dir"

    if [ ! -d "$cache_dir" ]; then
        echo "    ⚠ Thư mục không tồn tại."
        return
    fi

    local total_size
    total_size=$(du -sh "$cache_dir" 2>/dev/null | cut -f1 | xargs)
    echo "    Tổng dung lượng: $total_size"

    # ipch (IntelliSense cache) - thường chiếm nhiều nhất
    if [ -d "$cache_dir/ipch" ]; then
        local ipch_size
        ipch_size=$(du -sh "$cache_dir/ipch" 2>/dev/null | cut -f1 | xargs)
        echo "      - ipch (IntelliSense cache): $ipch_size"
    fi

    # Các thư mục hash cache khác
    local hash_count=0
    local hash_size=0
    local d
    shopt -s nullglob
    for d in "$cache_dir"/*/; do
        local dirname
        dirname=$(basename "$d")
        [[ "$dirname" == "ipch" ]] && continue
        hash_count=$((hash_count + 1))
        hash_size=$((hash_size + $(du -sk "$d" | cut -f1)))
    done
    shopt -u nullglob

    if [ $hash_count -gt 0 ]; then
        local hash_human
        hash_human=$(echo "scale=1; $hash_size / 1024" | bc)
        echo "      - $hash_count thư mục cache khác: ${hash_human} MiB"
    fi

    echo "    ✗ Sẽ xóa toàn bộ cache"
    local confirm
    read -r -p "    Xác nhận xóa? (Y/n): " confirm
    if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
        echo "    Đã hủy."
        return
    fi

    rm -rf -- "$cache_dir"/*
    echo "    Đã xóa toàn bộ cache. VS Code sẽ tạo lại khi cần."
}

# -----------------------------
# Function: Cleanup IDE logs (JetBrains, Google, etc.)
# Giữ lại phiên bản mới nhất của mỗi IDE
#   $1 = label, $2 = đường dẫn thư mục logs
# -----------------------------
cleanup_ide_logs() {
    local label="$1"
    local logs_dir="$2"

    echo "--- [$label Logs] ---"
    echo "    $logs_dir"

    if [ ! -d "$logs_dir" ]; then
        echo "    ⚠ Thư mục không tồn tại."
        return
    fi

    local to_delete=()
    local all_dirs=()

    shopt -s nullglob
    for d in "$logs_dir"/*/; do
        local dirname
        dirname=$(basename "$d")
        [[ "$dirname" == "Toolbox" || "$dirname" == ".DS_Store" ]] && continue
        all_dirs+=("$dirname")
    done
    shopt -u nullglob

    if [ ${#all_dirs[@]} -eq 0 ]; then
        echo "    ✓ Không có log nào."
        return
    fi

    local sorted
    sorted=$(printf '%s\n' "${all_dirs[@]}" | sort)

    local prev_ide=""
    local group=()

    while IFS= read -r dirname; do
        [ -z "$dirname" ] && continue
        local ide_name
        ide_name=$(echo "$dirname" | sed 's/[0-9].*$//')
        [ -z "$ide_name" ] && continue

        if [ -n "$prev_ide" ] && [ "$ide_name" != "$prev_ide" ]; then
            if [ ${#group[@]} -gt 0 ]; then
                local last_index=$(( ${#group[@]} - 1 ))
                local keep="${group[$last_index]}"
                local keep_size
                keep_size=$(du -sh "$logs_dir/$keep" 2>/dev/null | cut -f1 | xargs)
                echo "    [$prev_ide]"
                echo "      + $keep ($keep_size) [KEEP]"
                local i
                for ((i = 0; i < last_index; i++)); do
                    local old="${group[$i]}"
                    local old_size
                    old_size=$(du -sh "$logs_dir/$old" 2>/dev/null | cut -f1 | xargs)
                    echo "      - $old ($old_size)"
                    to_delete+=("$logs_dir/$old")
                done
            fi
            group=()
        fi
        group+=("$dirname")
        prev_ide="$ide_name"
    done <<< "$sorted"

    # Process the last group
    if [ ${#group[@]} -gt 0 ]; then
        local last_index=$(( ${#group[@]} - 1 ))
        local keep="${group[$last_index]}"
        local keep_size
        keep_size=$(du -sh "$logs_dir/$keep" 2>/dev/null | cut -f1 | xargs)
        echo "    [$prev_ide]"
        echo "      + $keep ($keep_size) [KEEP]"
        local i
        for ((i = 0; i < last_index; i++)); do
            local old="${group[$i]}"
            local old_size
            old_size=$(du -sh "$logs_dir/$old" 2>/dev/null | cut -f1 | xargs)
            echo "      - $old ($old_size)"
            to_delete+=("$logs_dir/$old")
        done
    fi

    if [ ${#to_delete[@]} -eq 0 ]; then
        echo "    ✓ Không có log cũ để xóa."
        return
    fi

    local confirm
    read -r -p "    Xác nhận xóa ${#to_delete[@]} thư mục cũ? (Y/n): " confirm
    if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
        echo "    Đã hủy."
        return
    fi

    for d in "${to_delete[@]}"; do
        echo "    Đã xóa: $(basename "$d")"
        rm -rf -- "$d"
    done
}

# -----------------------------
# Function: Cleanup pip cache
# -----------------------------
cleanup_pip() {
    echo "--- [Pip Cache] ---"
    if ! command -v pip3 &> /dev/null; then
        echo "    ⚠ pip3 command not found."
        return
    fi

    local cache_dir
    cache_dir=$(pip3 cache dir 2>/dev/null)
    if [ -d "$cache_dir" ]; then
        local size
        size=$(du -sh "$cache_dir" 2>/dev/null | cut -f1 | xargs)
        echo "    $cache_dir"
        echo "    ✗ Cache: $size"
        local confirm
        read -r -p "    Xác nhận xóa? (Y/n): " confirm
        if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
            echo "    Đã hủy."
            return
        fi
        pip3 cache purge 2>/dev/null
        echo "    Đã xong."
    else
        echo "    ✓ Cache rỗng."
    fi
}

# -----------------------------
# Function: Cleanup deno cache
# -----------------------------
cleanup_deno() {
    echo "--- [Deno Cache] ---"
    local deno_cache="$HOME/Library/Caches/deno"
    echo "    $deno_cache"

    if [ ! -d "$deno_cache" ]; then
        echo "    ⚠ Thư mục không tồn tại."
        return
    fi

    local size
    size=$(du -sh "$deno_cache" 2>/dev/null | cut -f1 | xargs)
    echo "    ✗ Cache: $size"
    local confirm
    read -r -p "    Xác nhận xóa? (Y/n): " confirm
    if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
        echo "    Đã hủy."
        return
    fi
    rm -rf -- "$deno_cache"/*
    echo "    Đã xong."
}

# -----------------------------
# Function: Cleanup go build cache
# -----------------------------
cleanup_go_build() {
    echo "--- [Go Build Cache] ---"
    if ! command -v go &> /dev/null; then
        echo "    ⚠ go command not found."
        return
    fi

    local cache_dir
    cache_dir=$(go env GOCACHE)
    if [ -d "$cache_dir" ]; then
        local size
        size=$(du -sh "$cache_dir" 2>/dev/null | cut -f1 | xargs)
        echo "    $cache_dir"
        echo "    ✗ Cache: $size"
        local confirm
        read -r -p "    Xác nhận xóa? (Y/n): " confirm
        if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
            echo "    Đã hủy."
            return
        fi
        go clean -cache
        echo "    Đã xong."
    else
        echo "    ✓ Cache rỗng."
    fi
}

# -----------------------------
# Function: Cleanup generic cache directory
#   $1 = label, $2 = đường dẫn thư mục
# -----------------------------
cleanup_cache_dir() {
    local label="$1"
    local cache_dir="$2"

    echo "--- [$label Cache] ---"
    echo "    $cache_dir"

    if [ ! -d "$cache_dir" ]; then
        echo "    ⚠ Thư mục không tồn tại."
        return
    fi

    local size
    size=$(du -sh "$cache_dir" 2>/dev/null | cut -f1 | xargs)
    echo "    ✗ Dung lượng: $size"
    local confirm
    read -r -p "    Xác nhận xóa? (Y/n): " confirm
    if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
        echo "    Đã hủy."
        return
    fi
    rm -rf -- "$cache_dir"/*
    echo "    Đã xong."
}

# =============================================================================
# Interactive Menu System
# =============================================================================

print_welcome_banner() {
    local use_color=0
    local reset=""
    local i=0
    local line
    local -a colors=()
    local -a lines=(
' __       __                                      __                                                          __                        ________  __'
'|  \     /  \                                    |  \                                                        |  \                      |        \|  \'
'| $$\   /  $$  ______    _______         _______ | $$  ______    ______   _______   __    __   ______        | $$____   __    __        \$$$$$$$$| $$'
'| $$$\ /  $$$ |      \  /       \       /       \| $$ /      \  |      \ |       \ |  \  |  \ /      \       | $$    \ |  \  |  \         | $$   | $$'
'| $$$$\  $$$$  \$$$$$$\|  $$$$$$$      |  $$$$$$$| $$|  $$$$$$\  \$$$$$$\| $$$$$$$\| $$  | $$|  $$$$$$\      | $$$$$$$\| $$  | $$         | $$   | $$'
'| $$\$$ $$ $$ /      $$| $$            | $$      | $$| $$    $$ /      $$| $$  | $$| $$  | $$| $$  | $$      | $$  | $$| $$  | $$         | $$   | $$'
'| $$ \$$$| $$|  $$$$$$$| $$_____       | $$_____ | $$| $$$$$$$$|  $$$$$$$| $$  | $$| $$__/ $$| $$__/ $$      | $$__/ $$| $$__/ $$         | $$   | $$_____'
'| $$  \$ | $$ \$$    $$ \$$     \       \$$     \| $$ \$$     \ \$$    $$| $$  | $$ \$$    $$| $$    $$      | $$    $$ \$$    $$         | $$   | $$     \'
' \$$      \$$  \$$$$$$$  \$$$$$$$        \$$$$$$$ \$$  \$$$$$$$  \$$$$$$$ \$$   \$$  \$$$$$$ | $$$$$$$        \$$$$$$$  _\$$$$$$$          \$$    \$$$$$$$$'
'                                                                                             | $$                      |  \__| $$'
'                                                                                             | $$                       \$$    $$'
'                                                                                              \$$                        \$$$$$$'
    )

    if [ -t 1 ]; then
        use_color=1
        reset=$'\033[0m'
        colors=(
            $'\033[1;38;5;51m'
            $'\033[1;38;5;87m'
            $'\033[1;38;5;123m'
            $'\033[1;38;5;159m'
            $'\033[1;38;5;193m'
            $'\033[1;38;5;220m'
            $'\033[1;38;5;214m'
            $'\033[1;38;5;209m'
            $'\033[1;38;5;204m'
            $'\033[1;38;5;198m'
            $'\033[1;38;5;177m'
            $'\033[1;38;5;141m'
        )
    fi

    echo ""
    for line in "${lines[@]}"; do
        if [ "$use_color" -eq 1 ]; then
            printf '%b%s%b\n' "${colors[$i]}" "$line" "$reset"
        else
            printf '%s\n' "$line"
        fi
        i=$((i + 1))
    done
    echo ""
}

# Tên các nhóm cleanup
MENU_ITEMS=(
    "All"
    "Browsers (Edge, Mozilla, Playwright)"
    "IDE (VS Code, AntiGravity)"
    "Dev Caches (Go, NPM, Pip, Deno)"
    "IDE Logs (JetBrains, Google)"
    "Other Caches (Raspberry Pi)"
    "Homebrew"
)

# Trạng thái chọn (0=off, 1=on), mặc định All=on
MENU_SELECTED=(1 1 1 1 1 1 1)

MENU_CURSOR=0
MENU_COUNT=${#MENU_ITEMS[@]}

# Vẽ menu lên terminal
draw_menu() {
    # Di chuyển cursor lên đầu menu để vẽ lại
    if [ "$1" = "redraw" ]; then
        printf "\033[%dA" "$((MENU_COUNT + 2))"
    fi

    echo "  Chọn mục cần dọn dẹp (↑↓: di chuyển | Space: chọn/bỏ chọn | Enter: chạy các mục có [✓]):"
    echo ""

    local i
    for ((i = 0; i < MENU_COUNT; i++)); do
        local prefix="  "
        [ $i -eq $MENU_CURSOR ] && prefix="▸ "

        local check="[ ]"
        [ "${MENU_SELECTED[$i]}" -eq 1 ] && check="[✓]"

        local label="${MENU_ITEMS[$i]}"

        # In dòng, xóa hết ký tự cũ trên dòng
        printf "\r\033[K%s%s %s\n" "$prefix" "$check" "$label"
    done
}

# Toggle All: chọn hoặc bỏ tất cả
toggle_all() {
    local new_val="${MENU_SELECTED[0]}"
    # Nếu All đang bật → tắt hết, ngược lại → bật hết
    if [ "$new_val" -eq 1 ]; then
        new_val=0
    else
        new_val=1
    fi
    local i
    for ((i = 0; i < MENU_COUNT; i++)); do
        MENU_SELECTED[$i]=$new_val
    done
}

# Cập nhật lại trạng thái All dựa trên các item con
sync_all() {
    local all_on=1
    local i
    for ((i = 1; i < MENU_COUNT; i++)); do
        if [ "${MENU_SELECTED[$i]}" -eq 0 ]; then
            all_on=0
            break
        fi
    done
    MENU_SELECTED[0]=$all_on
}

# Chạy interactive menu
run_menu() {
    print_welcome_banner
    echo ""
    echo "===== 🧹 Cleanup macOS ====="
    echo ""

    draw_menu

    while true; do
        # Đọc 1 ký tự (không echo, không buffer)
        IFS= read -rsn1 key

        case "$key" in
            # ESC sequence (arrow keys)
            $'\x1b')
                read -rsn2 seq
                case "$seq" in
                    '[A') # Up
                        MENU_CURSOR=$(( (MENU_CURSOR - 1 + MENU_COUNT) % MENU_COUNT ))
                        ;;
                    '[B') # Down
                        MENU_CURSOR=$(( (MENU_CURSOR + 1) % MENU_COUNT ))
                        ;;
                esac
                ;;
            # Space = toggle
            ' ')
                if [ $MENU_CURSOR -eq 0 ]; then
                    toggle_all
                else
                    if [ "${MENU_SELECTED[$MENU_CURSOR]}" -eq 1 ]; then
                        MENU_SELECTED[$MENU_CURSOR]=0
                    else
                        MENU_SELECTED[$MENU_CURSOR]=1
                    fi
                    sync_all
                fi
                ;;
            # Enter = confirm
            '')
                echo ""
                break
                ;;
        esac

        draw_menu "redraw"
    done
}

# =============================================================================
# Hàm chạy từng nhóm
# =============================================================================

run_browsers() {
    cleanup_versions "Edge" "$HOME/Library/Application Support/Microsoft/EdgeUpdater/apps/msedge-stable"
    echo ""
    cleanup_versions "Edge Updater" "$HOME/Library/Application Support/Microsoft/EdgeUpdater/apps/msedge-updater"
    echo ""
    cleanup_cache_dir "Mozilla" "$HOME/Library/Caches/Mozilla"
    echo ""
    cleanup_cache_dir "Playwright" "$HOME/Library/Caches/ms-playwright"
    echo ""
}

run_ide() {
    cleanup_vscode_extensions
    echo ""
    cleanup_vscode_cpptools
    echo ""
    cleanup_cache_dir "VS Code ShipIt" "$HOME/Library/Caches/com.microsoft.VSCode.ShipIt"
    echo ""
    cleanup_agy_recordings
    echo ""
}

run_dev_caches() {
    cleanup_go
    echo ""
    cleanup_go_build
    echo ""
    cleanup_npm
    echo ""
    cleanup_pip
    echo ""
    cleanup_deno
    echo ""
}

run_ide_logs() {
    cleanup_ide_logs "JetBrains" "$HOME/Library/Logs/JetBrains"
    echo ""
    cleanup_ide_logs "Google" "$HOME/Library/Logs/Google"
    echo ""
}

run_other_caches() {
    cleanup_cache_dir "Raspberry Pi" "$HOME/Library/Caches/Raspberry Pi"
    echo ""
}

run_homebrew() {
    cleanup_homebrew
    echo ""
}

# =============================================================================
# Main
# =============================================================================

# Map index → function
GROUP_FUNCS=(
    ""                 # 0 = All (handled separately)
    "run_browsers"     # 1
    "run_ide"          # 2
    "run_dev_caches"   # 3
    "run_ide_logs"     # 4
    "run_other_caches" # 5
    "run_homebrew"     # 6
)

run_menu

# Kiểm tra có mục nào được chọn không
has_selection=0
for ((i = 1; i < MENU_COUNT; i++)); do
    if [ "${MENU_SELECTED[$i]}" -eq 1 ]; then
        has_selection=1
        break
    fi
done

if [ "$has_selection" -eq 0 ]; then
    echo "Không có mục nào được chọn. Thoát."
    exit 0
fi

# Chạy các nhóm đã chọn
echo "===== Bắt đầu cleanup ====="
echo ""

for ((i = 1; i < MENU_COUNT; i++)); do
    if [ "${MENU_SELECTED[$i]}" -eq 1 ]; then
        ${GROUP_FUNCS[$i]}
    fi
done

echo "===== ✅ Cleanup hoàn tất ====="
