#!/bin/bash
# cleanup-server - Dọn dẹp + nâng cấp server (Ubuntu/Arch), interactive, tuần tự.
# Cách dùng:
#   cleanup-server            # hiện menu chọn target (local hoặc server alias)
#   cleanup-server --run-steps   # (nội bộ) chạy thẳng 6 bước trên máy hiện tại

# -----------------------------
# Color helpers (tự tắt khi không phải TTY)
# -----------------------------
if [ -t 1 ]; then
    C_RESET=$'\033[0m'
    C_TITLE=$'\033[1;36m'   # tiêu đề
    C_OK=$'\033[1;32m'      # thành công
    C_DEL=$'\033[1;31m'     # sẽ xóa / lỗi
    C_WARN=$'\033[1;33m'    # cảnh báo
else
    C_RESET=""; C_TITLE=""; C_OK=""; C_DEL=""; C_WARN=""
fi

# -----------------------------
# Banner rainbow nhưng đọc được: thanh gradient + tiêu đề rõ
# -----------------------------
repeat_char() {
    # $1 = số lượng, $2 = ký tự
    printf "%${1}s" "" | tr ' ' "$2"
}

# In 1 thanh block gradient rainbow (TTY) hoặc '#' (non-TTY)
rainbow_bar() {
    local width="$1"
    if [ -t 1 ]; then
        local -a codes=(51 87 123 159 220 214 209 204)
        local n=${#codes[@]} seg i line=""
        for ((i = 0; i < n; i++)); do
            seg=$(( (width + n - 1 - i) / n ))
            line+="$(printf '\033[1;38;5;%dm' "${codes[$i]}")""$(repeat_char "$seg" "█")"
        done
        printf '%s%s\n' "$line" "$C_RESET"
    else
        repeat_char "$width" "#"
        echo
    fi
}

print_banner() {
    echo ""
    rainbow_bar 56
    echo ""
    printf '  %s🧹  CLEANUP-SERVER%s\n' "$C_TITLE" "$C_RESET"
    printf '  %sDọn dẹp + nâng cấp server (Ubuntu / Arch)%s\n' "$C_WARN" "$C_RESET"
    echo ""
    rainbow_bar 56
    echo ""
}

# -----------------------------
# Phát hiện distro qua /etc/os-release → debian | arch | unknown
# -----------------------------
detect_distro() {
    [ -r /etc/os-release ] || { echo unknown; return; }
    local id id_like
    . /etc/os-release 2>/dev/null
    id="${ID:-}"; id_like="${ID_LIKE:-}"
    case "$id $id_like" in
        *arch*)   echo arch ;;
        *debian*) echo debian ;;
        *ubuntu*) echo debian ;;
        *)        echo unknown ;;
    esac
}

# -----------------------------
# Hỏi Y/n (Enter = Yes). Trả về 0 = đồng ý, 1 = hủy.
# -----------------------------
confirm_yn() {
    local prompt="$1" confirm
    read -r -p "    ${prompt} (Y/n): " confirm
    if [[ -n "$confirm" && ! "$confirm" =~ ^([yY]|[yY][eE][sS])$ ]]; then
        echo "    Đã hủy."
        return 1
    fi
    return 0
}

# -----------------------------
# Danh sách target fix cứng (alias từ ~/.ssh/config)
# -----------------------------
TARGETS=("local" "ta" "toc" "oc" "cse" "vrc" "aws" "tk" "od")
TARGET_CURSOR=0
TARGET=""

# Vẽ menu single-select
draw_target_menu() {
    if [ "$1" = "redraw" ]; then
        printf '\033[%dA' "$(( ${#TARGETS[@]} + 2 ))"
    fi
    echo "  Chọn target (↑↓: di chuyển | Enter: chọn):"
    echo ""
    local i
    for ((i = 0; i < ${#TARGETS[@]}; i++)); do
        local prefix="  "
        if [ "$i" -eq "$TARGET_CURSOR" ]; then
            prefix="${C_TITLE}▸ ${C_RESET}"
        fi
        printf '\r\033[K%s%s\n' "$prefix" "${TARGETS[$i]}"
    done
}

# Chạy menu, đặt biến toàn cục TARGET
select_target() {
    draw_target_menu
    while true; do
        IFS= read -rsn1 key
        case "$key" in
            $'\x1b')
                read -rsn2 seq
                case "$seq" in
                    '[A') TARGET_CURSOR=$(( (TARGET_CURSOR - 1 + ${#TARGETS[@]}) % ${#TARGETS[@]} ));;
                    '[B') TARGET_CURSOR=$(( (TARGET_CURSOR + 1) % ${#TARGETS[@]} ));;
                esac
                ;;
            '')   # Enter
                echo ""
                TARGET="${TARGETS[$TARGET_CURSOR]}"
                return
                ;;
        esac
        draw_target_menu "redraw"
    done
}

# -----------------------------
# Bước 1: Nâng cấp hệ thống theo distro
# -----------------------------
step_upgrade() {
    echo "${C_TITLE}--- [System Upgrade] ---${C_RESET}"
    local distro
    distro=$(detect_distro)
    case "$distro" in
        debian)
            echo "    Distro: Debian/Ubuntu (apt)."
            sudo apt-get update || { echo "${C_DEL}    ✗ apt-get update thất bại.${C_RESET}"; echo ""; return; }
            local upgradable
            upgradable=$(apt list --upgradable 2>/dev/null | grep -c 'upgradable')
            echo "    ${C_WARN}✗ ${upgradable} package có thể nâng cấp.${C_RESET}"
            if confirm_yn "Upgrade + autoremove?"; then
                sudo apt-get upgrade -y
                sudo apt-get autoremove --purge -y
                echo "${C_OK}    ✓ Đã nâng cấp xong.${C_RESET}"
            fi
            ;;
        arch)
            echo "    Distro: Arch (pacman)."
            local helper=""
            command -v paru >/dev/null 2>&1 && helper="paru"
            [ -z "$helper" ] && command -v yay >/dev/null 2>&1 && helper="yay"
            [ -z "$helper" ] && helper="sudo pacman"
            echo "    Helper: $helper"
            if confirm_yn "Chạy $helper -Syu?"; then
                $helper -Syu
                echo "${C_OK}    ✓ Đã nâng cấp xong.${C_RESET}"
            fi
            ;;
        *)
            echo "${C_WARN}    ⚠ Distro không hỗ trợ upgrade, bỏ qua.${C_RESET}"
            ;;
    esac
    echo ""
}

# -----------------------------
# Chọn 'docker' hoặc 'sudo docker' tùy permission
# Trả về chuỗi lệnh qua echo (gán: DC=$(docker_cmd))
# -----------------------------
docker_cmd() {
    if docker info >/dev/null 2>&1; then
        echo "docker"
    elif sudo -n docker info >/dev/null 2>&1; then
        echo "sudo docker"
    else
        echo ""
    fi
}

# -----------------------------
# Bước 2: Docker — df rồi prune từng loại
# -----------------------------
step_docker() {
    echo "${C_TITLE}--- [Docker] ---${C_RESET}"
    if ! command -v docker >/dev/null 2>&1; then
        echo "${C_WARN}    ⚠ docker command not found.${C_RESET}"
        echo ""
        return
    fi
    local DC
    DC=$(docker_cmd)
    if [ -z "$DC" ]; then
        echo "${C_WARN}    ⚠ Không có quyền truy cập docker (cần group docker hoặc sudo).${C_RESET}"
        echo ""
        return
    fi
    echo "    Lệnh: $DC"
    $DC system df
    echo ""
    confirm_yn "Prune images (-a)?"  && $DC image prune -a -f
    confirm_yn "Prune containers?"   && $DC container prune -f
    confirm_yn "Prune volumes?"      && $DC volume prune -f
    confirm_yn "Prune build cache?"  && $DC builder prune -f
    confirm_yn "Prune networks?"     && $DC network prune -f
    echo "${C_OK}    ✓ Docker cleanup xong.${C_RESET}"
    echo ""
}

# -----------------------------
# Bước 3: Journal logs — vacuum log cũ hơn 7 ngày
# -----------------------------
step_journal() {
    echo "${C_TITLE}--- [Journal Logs] ---${C_RESET}"
    if ! command -v journalctl >/dev/null 2>&1; then
        echo "${C_WARN}    ⚠ journalctl not found.${C_RESET}"
        echo ""
        return
    fi
    sudo journalctl --disk-usage
    if confirm_yn "Vacuum log cũ hơn 7 ngày (--vacuum-time=7d)?"; then
        sudo journalctl --vacuum-time=7d
        echo "${C_OK}    ✓ Đã dọn journal.${C_RESET}"
    fi
    echo ""
}

# -----------------------------
# Bước 4: Package cache — apt clean+autoremove hoặc paccache/pacman -Sc
# -----------------------------
step_pkg_cache() {
    echo "${C_TITLE}--- [Package Cache] ---${C_RESET}"
    local distro
    distro=$(detect_distro)
    case "$distro" in
        debian)
            local d="/var/cache/apt/archives"
            [ -d "$d" ] && sudo du -sh "$d"
            if confirm_yn "apt clean + autoremove?"; then
                sudo apt-get clean
                sudo apt-get autoremove -y
                echo "${C_OK}    ✓ Đã dọn apt cache.${C_RESET}"
            fi
            ;;
        arch)
            local d="/var/cache/pacman/pkg"
            [ -d "$d" ] && sudo du -sh "$d"
            if command -v paccache >/dev/null 2>&1; then
                sudo paccache -dk2      # dry-run xem trước
                if confirm_yn "paccache -rk2 (giữ 2 bản)?"; then
                    sudo paccache -rk2
                    echo "${C_OK}    ✓ Đã dọn pacman cache.${C_RESET}"
                fi
            else
                if confirm_yn "Không có paccache, chạy pacman -Sc?"; then
                    sudo pacman -Sc --noconfirm
                    echo "${C_OK}    ✓ Đã dọn pacman cache.${C_RESET}"
                fi
            fi
            ;;
        *)
            echo "${C_WARN}    ⚠ Distro không hỗ trợ dọn package cache.${C_RESET}"
            ;;
    esac
    echo ""
}

# -----------------------------
# Bước 5: Snap — forget từng snapshot
# -----------------------------
step_snap() {
    echo "${C_TITLE}--- [Snap] ---${C_RESET}"
    if ! command -v snap >/dev/null 2>&1; then
        echo "${C_WARN}    ⚠ snap not found.${C_RESET}"
        echo ""
        return
    fi
    local saved
    # Cột đầu (Set) là id cần forget; một Set có thể có nhiều Snap → dedupe.
    saved=$(sudo snap saved 2>/dev/null | awk 'NR>1{print $1}' | awk '!seen[$0]++')
    if [ -z "$saved" ]; then
        echo "${C_OK}    ✓ Không có snap snapshot nào.${C_RESET}"
        echo ""
        return
    fi
    local id
    for id in $saved; do
        if confirm_yn "Forget snap snapshot (Set $id)?"; then
            sudo snap forget "$id"
        fi
    done
    echo "${C_OK}    ✓ Snap cleanup xong.${C_RESET}"
    echo ""
}

# -----------------------------
# Bước 6: /tmp & cache cũ — liệt kê file >7 ngày, xác nhận rồi xóa
# -----------------------------
step_tmp_cache() {
    echo "${C_TITLE}--- [/tmp & Cache cũ] ---${C_RESET}"
    local days=7
    echo "    Tìm file cũ hơn ${days} ngày trong /tmp /var/tmp:"
    local old_files
    old_files=$(sudo find /tmp /var/tmp -type f -mtime +"$days" 2>/dev/null)
    if [ -z "$old_files" ]; then
        echo "${C_OK}    ✓ Không có file cũ >${days} ngày.${C_RESET}"
        echo ""
        return
    fi
    local count total_kb total_mib
    count=$(printf '%s\n' "$old_files" | grep -c .)
    total_kb=$(printf '%s\n' "$old_files" | xargs sudo du -ck 2>/dev/null | tail -1 | cut -f1)
    total_mib=$(( total_kb / 1024 ))
    echo "${C_DEL}    ✗ ${count} file, ~${total_mib} MiB.${C_RESET}"
    printf '%s\n' "$old_files" | head -20 | sed 's/^/      - /'
    [ "$count" -gt 20 ] && echo "      ... (và $((count - 20)) file nữa)"
    if confirm_yn "Xóa các file cũ >${days} ngày?"; then
        printf '%s\n' "$old_files" | xargs sudo rm -f --
        echo "${C_OK}    ✓ Đã xóa.${C_RESET}"
    fi
    echo ""
}

# -----------------------------
# Chạy tuần tự 6 bước (stub — các bước thêm ở Task 4-9)
# -----------------------------
run_all_steps() {
    step_upgrade
    step_docker
    step_journal
    step_pkg_cache
    step_snap
    step_tmp_cache
}

# -----------------------------
# Chạy trên target đã chọn.
#   local → chạy tại chỗ.
#   alias → self-bootstrap: base64 script qua argv, giữ stdin=terminal
#           để read/màu tương tác hoạt động qua PTY của `ssh -t`.
# -----------------------------
run_on_target() {
    local target="$1"
    if [ "$target" = "local" ]; then
        run_all_steps
        return $?
    fi
    local b64
    b64=$(base64 < "$0" | tr -d '\n') || {
        echo "${C_DEL}    ✗ Không mã hóa được script.${C_RESET}"
        return 1
    }
    # Giải mã ra file tạm trên remote rồi chạy; stdin không bị redirect → read OK.
    ssh -t "$target" \
        "umask 077; t=\$(mktemp); printf '%s' '$b64' | base64 -d > \"\$t\" && bash \"\$t\" --run-steps; r=\$?; rm -f \"\$t\"; exit \$r" \
        || { echo "${C_DEL}    ✗ ssh tới $target thất bại.${C_RESET}"; return 1; }
}

# -----------------------------
# Main (phân nhánh theo argv)
# -----------------------------
main() {
    if [ "${1:-}" = "--run-steps" ]; then
        echo "${C_TITLE}===== 🧹 Cleanup-server (--run-steps) =====${C_RESET}"
        echo ""
        run_all_steps
        echo ""
        echo "${C_OK}===== ✅ Cleanup-server hoàn tất =====${C_RESET}"
        return
    fi
    print_banner
    echo "${C_TITLE}===== 🧹 Cleanup-server =====${C_RESET}"
    echo ""
    select_target
    echo ""
    run_on_target "$TARGET"
}

main "$@"
