#!/bin/bash
# images build from https://github.com/oneclickvirt/macos
# https://github.com/oneclickvirt/pve
# 2025.05.09

set -e
LANG_MODE="zh"
while [[ $# -gt 0 ]]; do
    case "$1" in
    --lang=*)
        LANG_MODE="${1#*=}"
        shift
        ;;
    *)
        echo "Unknown option: $1"
        echo "Available options: --lang=zh|en"
        exit 1
        ;;
    esac
done

_red() { echo -e "\033[31m\033[01m$@\033[0m"; }
_green() { echo -e "\033[32m\033[01m$@\033[0m"; }
_yellow() { echo -e "\033[33m\033[01m$@\033[0m"; }
_blue() { echo -e "\033[36m\033[01m$@\033[0m"; }

_text() {
    local zh="$1"
    local en="$2"
    if [[ "$LANG_MODE" == "en" ]]; then
        echo "$en"
    else
        echo "$zh"
    fi
}

reading() { read -rp "$(_green "$1")" "$2"; }
utf8_locale=$(locale -a 2>/dev/null | grep -i -m 1 -E "UTF-8|utf8")
if [[ -z "$utf8_locale" ]]; then
    _yellow "$(_text "未找到 UTF-8 本地化" "No UTF-8 locale found")"
else
    export LC_ALL="$utf8_locale"
    export LANG="$utf8_locale"
    export LANGUAGE="$utf8_locale"
    _green "$(_text "本地化已设置为 $utf8_locale" "Locale set to $utf8_locale")"
fi

DOWNLOAD_DIR="/var/lib/vz/template/iso"
DOWNLOAD_TASKS="$DOWNLOAD_DIR/download.tasks"
DECOMPRESS_TASKS="$DOWNLOAD_DIR/decompress.tasks"
if [ ! -d "$DOWNLOAD_DIR" ]; then
    _red "$(_text "目录 $DOWNLOAD_DIR 不存在。请检查路径是否正确。" "Directory $DOWNLOAD_DIR does not exist. Please check the path.")"
    exit 1
fi
touch "$DOWNLOAD_TASKS" "$DECOMPRESS_TASKS"
rm -f "${DOWNLOAD_TASKS}.tmp" "${DECOMPRESS_TASKS}.tmp"

if ! command -v 7z >/dev/null 2>&1; then
    apt install p7zip-full -y
    if ! command -v 7z >/dev/null 2>&1; then
        _red "$(_text "错误：未找到 '7z' 命令。请安装 p7zip-full" "ERROR: '7z' command not found. Please install p7zip-full")"
        exit 1
    fi
fi

check_cdn() {
    local o_url=$1
    local shuffled_cdn_urls=($(shuf -e "${cdn_urls[@]}")) # 打乱数组顺序
    for cdn_url in "${shuffled_cdn_urls[@]}"; do
        if curl -4 -sL -k "$cdn_url$o_url" --max-time 6 | grep -q "success" >/dev/null 2>&1; then
            export cdn_success_url="$cdn_url"
            return
        fi
        sleep 0.5
    done
    export cdn_success_url=""
}

check_cdn_file() {
    check_cdn "https://raw.githubusercontent.com/spiritLHLS/ecs/main/back/test"
    if [ -n "$cdn_success_url" ]; then
        _yellow "CDN available, using CDN"
    else
        _yellow "No CDN available, using original links"
        export cdn_success_url=""
    fi
}

cdn_urls=("https://cdn0.spiritlhl.top/" "http://cdn1.spiritlhl.net/" "http://cdn2.spiritlhl.net/" "http://cdn3.spiritlhl.net/" "http://cdn4.spiritlhl.net/")
check_cdn_file
target_path="/var/lib/vz/template/iso/opencore.iso"
origin_url="https://github.com/oneclickvirt/macos/raw/refs/heads/main/EFI/opencore.iso"
final_url="${cdn_success_url}${origin_url}"
if [ ! -f "$target_path" ]; then
    _yellow "File not found: $target_path"
    _yellow "Downloading opencore.iso from: $([ -n "$cdn_success_url" ] && echo "$final_url" || echo "$origin_url")"
    wget "$([ -n "$cdn_success_url" ] && echo "$final_url" || echo "$origin_url")" -O "$target_path" && chmod 777 "$target_path"
    _yellow "Download completed and permissions set."
fi

declare -A files=(
    [1]="high-sierra.iso.7z|5.23|https://cnb.cool/oneclickvirt/template/-/lfs/81ae1e766f12f94a283ee51a2b3a0c274ce31b578acdce7eddd22c5ff8cd045e|5226471630"
    [2]="mojave.iso.7z|6.03|https://cnb.cool/oneclickvirt/template/-/lfs/4145b12588e14c933ad0d3e527b4e1f701b882d505d9dae463349f5062f7b6b1|6032600963"
    [3]="catalina.iso.7z|8.33|https://cnb.cool/oneclickvirt/template/-/lfs/660078c8a258c8bcde62c49897e5415751f5a17d30d40749a06ae81dc9b1c424|8178081717"
    [4]="big‑sur.iso.7z|12.21|https://cnb.cool/oneclickvirt/template/-/lfs/e15404924199bcf92c6421980a74ad5fdde1dd18a83551726648bd0a1417133|13154181520"
    [5]="monterey.iso.7z|12.36|https://cnb.cool/oneclickvirt/template/-/lfs/520f9e35fb4981bc171945d398f4587f780ab2f8dbfb4bf3a9463b2401ccb148|13257099123"
    [6]="ventura.iso.7z|12.31|https://cnb.cool/oneclickvirt/template/-/lfs/5f735c627d352f0677b6594e3e5f783467a35e34512fc8c6ae31349fce0c9677|13212673700"
    [7]="sonoma.iso.7z|14.41|https://cnb.cool/oneclickvirt/template/-/lfs/b35ff92067171d72519df05a066d3494b7fdb0eac1603b0a8803c98716707e9c|14644126387"
    [8]="sequoia.iso.7z|15.02|https://cnb.cool/oneclickvirt/template/-/lfs/f22ad0a9eba713645b566fd6a45f55a0daf9f481e6872cca2407856c6fd33b45|16398983272"
)

print_menu() {
    _blue "=== $(_text "macOS 下载器 菜单" "macOS Downloader Menu") ==="
    for i in {1..8}; do
        IFS='|' read -r name size url <<<"${files[$i]}"
        _yellow "  $i) $(_text "下载" "Download") $name ($(_text "大小" "Size"): ${size}GB)"
    done
    _yellow "100) $(_text "显示当前下载任务" "Show current download tasks")"
    _yellow "101) $(_text "删除下载任务及文件" "Delete a download task and file")"
    _yellow "102) $(_text "解压 .7z 文件" "Extract 7z archives")"
    _yellow "103) $(_text "显示当前解压任务" "Show current extraction tasks")"
    _yellow "104) $(_text "删除解压任务及文件" "Delete an extraction task and file")"
    _yellow "  0) $(_text "退出" "Exit")"
}

get_remote_size() {
    local url=$1
    local file_hash=$(basename "$url")
    for i in {1..8}; do
        IFS='|' read -r name size url_info exact_size <<<"${files[$i]}"
        if [[ "$url_info" == *"$file_hash"* ]]; then
            echo "$exact_size"
            return
        fi
    done
    echo "5368709120"
}

get_avail_space() {
    df --output=avail -B1 "$DOWNLOAD_DIR" | tail -1
}

start_download() {
    local fileName=$1 url=$2
    local size avail req
    for i in {1..8}; do
        IFS='|' read -r name _ url_info exact_size <<<"${files[$i]}"
        if [[ "$name" == "$fileName" ]]; then
            size="$exact_size"
            break
        fi
    done
    if [[ -z "$size" ]]; then
        _red "$(_text "错误：无法获取文件大小" "Error: Unable to determine file size")"
        return
    fi
    avail=$(get_avail_space)
    req=$((size * 2 + 2 * 1024 * 1024 * 1024))
    if ((avail < req)); then
        _red "$(_text "空间不足: 可用=${avail} 字节, 需要=${req} 字节" "Insufficient space: available=${avail} bytes, required=${req} bytes")"
        return
    fi
    nohup curl -L "$url" -o "$DOWNLOAD_DIR/$fileName" >"$DOWNLOAD_DIR/$fileName.log" 2>&1 &
    pid=$!
    echo "$pid|$fileName|$url|$size" >>"$DOWNLOAD_TASKS"
    _green "$(_text "下载开始: PID=$pid, 文件路径=$DOWNLOAD_DIR/$fileName" "Download started: PID=$pid, path=$DOWNLOAD_DIR/$fileName")"
}

show_downloads() {
    if [[ ! -s "$DOWNLOAD_TASKS" ]]; then
        _yellow "$(_text "没有下载任务" "No download tasks")"
        return
    fi
    while IFS='|' read -r pid file url size_bytes; do
        if ps -p "$pid" >/dev/null 2>&1; then
            downloaded=$(du -b "$DOWNLOAD_DIR/$file" 2>/dev/null | cut -f1 || echo 0)
            if [[ -n "$size_bytes" && "$size_bytes" -gt 0 ]]; then
                pct=$(awk "BEGIN{printf \"%.2f\", $downloaded*100/$size_bytes}")
                _blue "PID $pid: $file — $downloaded/$size_bytes 字节 ($pct%)，路径=$DOWNLOAD_DIR/$file"
            else
                _blue "PID $pid: $file — $downloaded 字节 (总大小未知)，路径=$DOWNLOAD_DIR/$file"
            fi
        else
            _yellow "PID $pid: $(_text "未运行 ▶ 从任务列表移除" "not running ▶ removing from task list")"
            grep -v "^$pid|" "$DOWNLOAD_TASKS" >"$DOWNLOAD_TASKS.tmp" && mv "$DOWNLOAD_TASKS.tmp" "$DOWNLOAD_TASKS"
        fi
    done <"$DOWNLOAD_TASKS"
}

delete_download() {
    reading "$(_text "输入要删除的下载 PID" "Enter download PID to delete"): " pid
    if ! grep -q "^$pid|" "$DOWNLOAD_TASKS"; then
        _red "$(_text "PID $pid 未找到" "PID $pid not found")"
        return
    fi
    line=$(grep "^$pid|" "$DOWNLOAD_TASKS")
    file=${line#*|}
    file=${file%%|*}
    kill "$pid" 2>/dev/null || true
    rm -f "$DOWNLOAD_DIR/$file" "$DOWNLOAD_DIR/$file.log"
    grep -v "^$pid|" "$DOWNLOAD_TASKS" >"$DOWNLOAD_TASKS.tmp" && mv "$DOWNLOAD_TASKS.tmp" "$DOWNLOAD_TASKS"
    _green "$(_text "已删除下载任务: $file，路径=$DOWNLOAD_DIR/$file" "Deleted download task for $file, path=$DOWNLOAD_DIR/$file")"
}

extract_7z() {
    mapfile -t archives < <(ls "$DOWNLOAD_DIR"/*.7z 2>/dev/null)
    if [[ ${#archives[@]} -eq 0 ]]; then
        _yellow "$(_text "目录中无 .7z 文件" "No .7z archives found in $DOWNLOAD_DIR")"
        return
    fi
    _blue "$(_text "可用 .7z 归档:" "Available .7z archives:")"
    for i in "${!archives[@]}"; do
        num=$((i + 1))
        _yellow "  $num) $(basename "${archives[i]}")"
    done
    reading "$(_text "选择要解压的索引" "Select index to extract"): " idx
    if ! [[ "$idx" =~ ^[0-9]+$ ]] || ((idx < 1 || idx > ${#archives[@]})); then
        _red "$(_text "无效选择" "Invalid selection")"
        return
    fi
    archive="${archives[$((idx - 1))]}"
    nohup 7z x "$archive" -o"$DOWNLOAD_DIR" >"$DOWNLOAD_DIR/$(basename "$archive").extract.log" 2>&1 &
    pid=$!
    echo "$pid|$(basename "$archive")" >>"$DECOMPRESS_TASKS"
    _green "$(_text "开始解压: PID=$pid, 归档路径=$DOWNLOAD_DIR/$(basename "$archive")" "Extraction started: PID=$pid, path=$DOWNLOAD_DIR/$(basename "$archive")")"
}

show_extracts() {
    if [[ ! -s "$DECOMPRESS_TASKS" ]]; then
        _yellow "$(_text "没有解压任务" "No extraction tasks")"
        return
    fi
    while IFS='|' read -r pid archive; do
        if ps -p "$pid" >/dev/null 2>&1; then
            _blue "PID $pid: $(_text "正在解压" "extracting") $archive，路径=$DOWNLOAD_DIR/$archive"
        else
            _yellow "PID $pid: $(_text "未运行 ▶ 解压完成，正在清理并从任务列表移除" "not running ▶ completed, cleaning up and removing from task list")"
            expected_iso="${archive%.7z}.iso"
            if [ -f "$DOWNLOAD_DIR/$expected_iso" ] || [ -f "$DOWNLOAD_DIR/output/$expected_iso" ]; then
                _green "$(_text "解压成功: $expected_iso 已创建" "Extraction successful: $expected_iso created")"
                if [ -f "$DOWNLOAD_DIR/output/$expected_iso" ]; then
                    mv "$DOWNLOAD_DIR/output/$expected_iso" "$DOWNLOAD_DIR/" || _red "$(_text "移动ISO文件失败" "Failed to move ISO file")"
                fi
                rm -f "$DOWNLOAD_DIR/$archive" "$DOWNLOAD_DIR/${archive}.extract.log" || true
                rm -rf "$DOWNLOAD_DIR/$archive.log" || true
            else
                _red "$(_text "警告: 解压可能失败，未找到预期的ISO文件" "Warning: Extraction may have failed, expected ISO file not found")"
            fi
            if [ -d "$DOWNLOAD_DIR/output" ]; then
                if [ "$(ls -A "$DOWNLOAD_DIR/output" 2>/dev/null)" ]; then
                    mv "$DOWNLOAD_DIR/output/"* "$DOWNLOAD_DIR" 2>/dev/null || _red "$(_text "移动解压文件失败" "Failed to move extracted files")"
                fi
                rm -rf "$DOWNLOAD_DIR/output" || true
            fi
            grep -v "^$pid|" "$DECOMPRESS_TASKS" >"$DECOMPRESS_TASKS.tmp" && mv "$DECOMPRESS_TASKS.tmp" "$DECOMPRESS_TASKS"
        fi
    done <"$DECOMPRESS_TASKS"
    if [[ ! -s "$DECOMPRESS_TASKS" ]]; then
        _yellow "$(_text "没有活跃的解压任务" "No active extraction tasks")"
        >"$DECOMPRESS_TASKS"
        if [[ -d "$DOWNLOAD_DIR/output" && -z "$(ls -A "$DOWNLOAD_DIR/output" 2>/dev/null)" ]]; then
            rm -rf "$DOWNLOAD_DIR/output"
        fi
    fi
}

delete_extract() {
    reading "$(_text "输入要删除的解压 PID" "Enter extraction PID to delete"): " pid
    if ! grep -q "^$pid|" "$DECOMPRESS_TASKS"; then
        _red "$(_text "PID $pid 未找到" "PID $pid not found")"
        return
    fi
    line=$(grep "^$pid|" "$DECOMPRESS_TASKS")
    archive=${line#*|}
    expected_iso="${archive%.7z}.iso"
    if ps -p "$pid" >/dev/null 2>&1; then
        kill "$pid" 2>/dev/null && _yellow "$(_text "已终止解压进程 PID=$pid" "Terminated extraction process PID=$pid")" || _red "$(_text "无法终止进程 PID=$pid" "Could not terminate process PID=$pid")"
    fi
    rm -f "$DOWNLOAD_DIR/$expected_iso" 2>/dev/null
    rm -f "$DOWNLOAD_DIR/$archive.extract.log" 2>/dev/null
    grep -v "^$pid|" "$DECOMPRESS_TASKS" >"$DECOMPRESS_TASKS.tmp" && mv "$DECOMPRESS_TASKS.tmp" "$DECOMPRESS_TASKS"
    _green "$(_text "已删除解压任务: $archive，路径=$DOWNLOAD_DIR/$archive" "Deleted extraction task for $archive, path=$DOWNLOAD_DIR/$archive")"
}

while true; do
    print_menu
    reading "$(_text "选择操作" "Choice"): " choice
    case "$choice" in
    [1-8])
        clear
        pair=${files[$choice]}
        IFS='|' read -r fname fsize furl fexact_size <<<"$pair"
        start_download "$fname" "$furl"
        ;;
    100)
        clear
        show_downloads
        ;;
    101)
        delete_download
        sleep 5
        clear
        ;;
    102)
        clear
        extract_7z
        ;;
    103)
        clear
        show_extracts
        ;;
    104)
        delete_extract
        sleep 5
        clear
        ;;
    0)
        _green "$(_text "退出程序" "Exit")"
        exit 0
        ;;
    *)
        clear
        _red "$(_text "无效选项" "Invalid option")"
        ;;
    esac
    echo
done
