#!/bin/bash
# 2026.07.06 15

set -euo pipefail

opt_branch=""
opt_device=""
folder_name=""
opt_update=false
opt_keep=false
opt_skip_config=false
opt_skip_make=false
opt_gen_rebuild=false

ARGS=$(getopt -o b:d:f:uksmh --long branch:,device:,folder:,update,keep,skip,skip-make,gen-rebuild,help -- "$@") || exit 1

eval set -- "$ARGS"

while true; do
    case "$1" in
        -b|--branch) opt_branch="$2"; shift 2 ;;
        -d|--device) opt_device="$2"; shift 2 ;;
        -f|--folder) folder_name="$2"; shift 2 ;;
        -u|--update) opt_update=true; shift ;;
        -k|--keep) opt_keep=true; shift ;;
        -s|--skip) opt_skip_config=true; shift ;;
        -m|--skip-make) opt_skip_make=true; shift ;;
        --gen-rebuild) opt_gen_rebuild=true; shift ;;
        -h|--help)
            echo "Usage: $0 [OPTIONS]"
            echo "Options:"
            echo "  -b, --branch <name>    Set branch (lede, imw, 798x)"
            echo "  -d, --device <type>    Set device (x86, r4s, r6c, rm6000, mt6000, mt3600be)"
            echo "  -f, --folder <name>    Set custom clone folder name"
            echo "  -u, --update           Update script"
            echo "  -k, --keep             Keep existing files"
            echo "  -s, --skip             Skip config download"
            echo "  -m, --skip-make        Skip compilation"
            echo "      --gen-rebuild      Generate rebuild script"
            exit 0
            ;;
        --) shift; break ;;
        *) echo "Invalid option: $1"; exit 1 ;;
    esac
done

opt_branch="${opt_branch,,}"
opt_device="${opt_device,,}"
[[ "$opt_branch" == "imw" || -z "$opt_branch" ]] && opt_branch="immortalwrt"
[[ "$opt_branch" == *"798"* ]] && opt_branch="immortalwrt-mt798x"
[[ -z "$folder_name" ]] && folder_name="$opt_branch"

case "$opt_branch" in
    "lede")
        git_clone_cmd=(git clone --depth 1 --filter=blob:none https://github.com/coolsnowwolf/lede "$folder_name")
        [[ "$opt_device" == *"x86"* || -z "$opt_device" ]] && opt_device="x86"
        config_filename="${opt_device}-lede.config"
        ;;
    "immortalwrt-mt798x")
        git_clone_cmd=(git clone -b openwrt-24.10-6.6 --single-branch --depth=1 --filter=blob:none https://github.com/padavanonly/immortalwrt-mt798x-6.6 "$folder_name")
        [[ -z "$opt_device" ]] && opt_device="mt6000"
        config_filename="${opt_device}-imw.config"
        ;;
    *)
        git_clone_cmd=(git clone -b openwrt-25.12 --single-branch --depth=1 --filter=blob:none https://github.com/immortalwrt/immortalwrt "$folder_name")
        [[ "$opt_device" == *"x86"* || -z "$opt_device" ]] && opt_device="x86"
        config_filename="${opt_device}-imw.config"
        ;;
esac

function update_script() {
    local current_file="$0"
    local script_name="${0##*/}"
    local download_url="https://dev2.skvm.top/${script_name}"
    local temp_script=$(mktemp)
    local current_version remote_version
    (
        trap "rm -f '$temp_script'" EXIT INT TERM RETURN
        curl -Lso "$temp_script" "$download_url" && [ -s "$temp_script" ] || { echo "Download failed."; exit 1; }

        current_version=$(grep -m 1 -E '^# [0-9]{4}\.[0-9]{2}\.[0-9]{2} [0-9]+$' "$current_file" | sed 's/^# //' || true)
        remote_version=$(grep -m 1 -E '^# [0-9]{4}\.[0-9]{2}\.[0-9]{2} [0-9]+$' "$temp_script" | sed 's/^# //' || true)
        [ -n "$current_version" ] && [ -n "$remote_version" ] || { echo "Version not found."; exit 1; }

        if [ "$current_version" != "$remote_version" ] &&
            printf '%s\n' "$current_version" "$remote_version" | sort -VC 2>/dev/null; then
            diff --color=always -u "$current_file" "$temp_script" || true
            mv "$temp_script" "$current_file"
            chmod +x "$current_file"
            current_version="$remote_version"
            echo "Update success."
        else
            echo "Already up to date."
        fi
        echo "version=$current_version"
    )

    exec "$current_file" -f "$folder_name" --gen-rebuild
}

function generate_rebuild_script() {
    local temp_file=$(mktemp)
    cat << 'EOF' > "$temp_file"
#!/bin/bash

set -euo pipefail

PKG_REPO_POOL="$HOME/openwrt-repo-pool"
PKG_TARGET_DIR="package/custom"

git_clone() {
    local url="$1"
    local name=${2:-$(basename "$url" .git)}
    local branch="${3-}"
    local repo_path="$PKG_REPO_POOL/$name"

    echo -e "\033[34m[Update]\033[0m Processing $name..."

    if [ -d "$repo_path" ]; then
        git -C "$repo_path" pull --rebase
    else
        git clone --depth 1 ${branch:+-b "$branch"} "$url" "$repo_path"
    fi
}

git_sparse_clone() {
    local url="$1"
    local name=${2:-$(basename "$url" .git)}
    local branch="${3-}"
    shift 3
    local sparse_paths=("$@")
    local repo_path="$PKG_REPO_POOL/$name"

    echo -e "\033[34m[Update]\033[0m Processing $name..."

    if [ ! -d "$repo_path" ]; then
        git clone --depth 1 --filter=blob:none --sparse -b "$branch" "$url" "$repo_path"
    fi

    git -C "$repo_path" sparse-checkout set --no-cone "${sparse_paths[@]}"
    git -C "$repo_path" pull --rebase
}

place_path() {
    local action="$1"
    local src="$2"
    local dest="$3"

    rm -rf "$dest"
    mkdir -p "$(dirname "$dest")"
    case "$action" in
        link) ln -s "$src" "$dest" ;;
        copy) cp -a "$src" "$dest" ;;
        *) echo "Unknown action: $action"; exit 1 ;;
    esac
}

place_repo() {
    local action="$1"
    local repo_name="$2"
    local mode="${3:-ALL}"
    local repo_path="$PKG_REPO_POOL/$repo_name"
    local src_paths=()

    shift 3
    echo -e "\033[33m[${action^}]\033[0m Processing packages from $repo_name..."

    if [ "$mode" == "ROOT" ]; then
        src_paths+=("$repo_path")
    elif [ "$mode" == "ALL" ]; then
        for item in "$repo_path"/*; do
            local base_name=$(basename "$item")
            case "$base_name" in
                .*|LICENSE*|*.md|*.sh) continue ;;
                *) src_paths+=("$item") ;;
            esac
        done
    else
        for item in "$mode" "$@"; do
            src_paths+=("$repo_path/$item")
        done
    fi

    for src in "${src_paths[@]}"; do
        if [ ! -e "$src" ]; then
            echo "  Warning: Source $src does not exist, skipping."
            continue
        fi
        local item_name=$(basename "$src")
        local dest="$PKG_TARGET_DIR/$item_name"
        place_path "$action" "$src" "$dest"
    done
}

update_all_repo() {
    local tmp_dir status=0 i
    local -a pids=() logs=()

    mkdir -p "$PKG_REPO_POOL"
    tmp_dir=$(mktemp -d)

    run_update() {
        local log="$tmp_dir/${#logs[@]}.log"
        logs+=("$log")
        ( "$@" ) >"$log" 2>&1 &
        pids+=("$!")
    }

    # run_update git_sparse_clone "https://github.com/coolsnowwolf/packages.git" "packages-lede" "master" "lang/rust/"
    run_update git_clone "https://github.com/sbwml/packages_lang_golang.git" "golang-custom" "26.x"
    run_update git_clone "https://github.com/fw876/helloworld.git"
    run_update git_clone "https://github.com/Openwrt-Passwall/openwrt-passwall-packages.git"
    run_update git_clone "https://github.com/Openwrt-Passwall/openwrt-passwall.git"
    run_update git_clone "https://github.com/Openwrt-Passwall/openwrt-passwall2.git"
    run_update git_clone "https://github.com/sbwml/luci-app-mosdns.git"
    run_update git_clone "https://github.com/kenzok78/luci-app-adguardhome.git"
    run_update git_clone "https://github.com/sirpdboy/luci-app-taskplan.git"
    run_update git_clone "https://github.com/sirpdboy/netspeedtest.git" "openwrt-netspeedtest"
    run_update git_clone "https://github.com/EasyTier/luci-app-easytier.git"
    run_update git_clone "https://github.com/Tokisaki-Galaxy/luci-app-tailscale-community.git" "tailscale-luci"
    run_update git_sparse_clone "https://github.com/GuNanOvO/openwrt-tailscale.git" "tailscale" "main" "package/tailscale/"

    for i in "${!pids[@]}"; do
        wait "${pids[$i]}" || status=1
        cat "${logs[$i]}"
    done

    rm -rf "$tmp_dir"
    return "$status"
}

place_all_repo() {
    rm -rf "$PKG_TARGET_DIR"
    mkdir -p "$PKG_TARGET_DIR"
    place_repo link "helloworld" "ALL"
    place_repo link "openwrt-passwall-packages" "ALL"
    place_repo link "openwrt-passwall" "luci-app-passwall"
    place_repo link "openwrt-passwall2" "luci-app-passwall2"
    place_repo link "luci-app-mosdns" "luci-app-mosdns" "mosdns" "v2dat"
    place_repo copy "luci-app-adguardhome" "ROOT"
    sed -i '/call BuildPackage,luci-app-adguardhome/d' "$PKG_TARGET_DIR/luci-app-adguardhome/Makefile"
    place_repo link "luci-app-taskplan" "luci-app-taskplan"
    place_repo link "luci-app-easytier" "ROOT"
    place_repo link "openwrt-netspeedtest" "ALL"
    place_repo link "tailscale-luci" "luci-app-tailscale-community"
}

replace_pkg() {
    place_path copy "$PKG_REPO_POOL/golang-custom" feeds/packages/lang/golang
    awk -F':=' '/^GO_VERSION_MAJOR_MINOR:=/{m=$2} /^GO_VERSION_PATCH:=/{p=$2} END{print "GO_VERSION:=" m "." p}' ./feeds/packages/lang/golang/golang/Makefile

    # rm -rf feeds/packages/lang/rust
    # cp -r "$PKG_REPO_POOL/packages-lede/lang/rust" feeds/packages/lang/rust
    awk -F':=' '/^PKG_VERSION:=/{print "RUST_VERSION:=" $2}' feeds/packages/lang/rust/Makefile

    place_path copy "$PKG_REPO_POOL/tailscale/package/tailscale" feeds/packages/net/tailscale
    sed -i -E 's/,?ts_omit_(taildrop|completion|relayserver|webclient)//g' feeds/packages/net/tailscale/Makefile
    sed -i '/^include \$(TOPDIR)\/rules.mk/a DISABLE_UPX:=1' feeds/packages/net/tailscale/Makefile
    sed -i -E 's/ \(UPX Compressed\)//g; s/OpenWrt-UPX/OpenWrt/g' feeds/packages/net/tailscale/Makefile
    awk -F':=' '/^PKG_VERSION:=/{print "TAILSCALE_VERSION:=" $2}' feeds/packages/net/tailscale/Makefile
}

delete_old_packages() {
    local package repo_name
    rm -rf feeds/packages/lang/golang
    # rm -rf feeds/packages/lang/rust
    for repo_name in helloworld openwrt-passwall-packages; do
        for package in "$PKG_REPO_POOL/$repo_name"/*; do
            [ -d "$package" ] || continue
            rm -rf "feeds/packages/net/$(basename "$package")"
        done
    done
    rm -rf feeds/packages/net/{mosdns,tailscale}
    rm -rf feeds/luci/applications/{*adguardhome,*mosdns,luci-app-passwall*,luci-app-tailscale*,luci-app-easytier}
}

update_feeds() {
    local temp_conf_dir=$(mktemp -d ~/OPENWRT_CONF_XXXXXXXX)
    (
        trap "rm -rf '$temp_conf_dir'" EXIT INT TERM RETURN
        [ -e ".config" ] && cp -vf ".config" "$temp_conf_dir"

        update_all_repo
        delete_old_packages
        ./scripts/feeds update -a || exit 2
        delete_old_packages
        replace_pkg
        place_all_repo
        ./scripts/feeds install -a || exit 2

        [ -e "$temp_conf_dir/.config" ] && cp -vf "$temp_conf_dir/.config" . || true
    )
}

download_config() {
    local config_filename="$1"
    wget "https://dev2.skvm.top/${config_filename}" -O .config
    sed -i -e "/^CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=/c\\CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=\"$( [ $(uname -m) = x86_64 ] && echo '' || echo '/usr/local/go' )\"" .config
    grep "^CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=" .config || true
}

make_with_timer() {
    set -e
    make defconfig
    local time_stage_1=$(date +%s)
    make download -j8
    local time_stage_2=$(date +%s)
    make V=s -j$(nproc) || make V=s -j1
    local time_stage_3=$(date +%s)

    local time_cost_1=$((time_stage_2 - time_stage_1))
    local time_cost_2=$((time_stage_3 - time_stage_2))
    echo "download time cost:    $(($time_cost_1/60))min $(($time_cost_1%60))s"
    echo "compilation time cost: $(($time_cost_2/60))min $(($time_cost_2%60))s"
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    git pull || exit 1
    update_feeds
    echo "Press any key in 5 seconds to exit..."
    read -n 1 -t 5 key && exit 0
    make_with_timer
fi
EOF
    [[ " $@ " =~ " --direct " ]] && mv "$temp_file" rebuild.sh && chmod +x rebuild.sh && return
    shopt -s nullglob
    for d in */; do
        d="${d%/}"
        [[ ! -f "$d/include/toplevel.mk" || ! -e "$d/scripts/feeds" ]] && continue
        if [[ ! -f "$d/rebuild.sh" ]] || ! diff -q "$d/rebuild.sh" "$temp_file" >/dev/null; then
            cp "$temp_file" "$d/rebuild.sh"
            chmod +x "$d/rebuild.sh"
            echo "Updated: $(readlink -f "$d/rebuild.sh")"
        fi
    done
    rm -f "$temp_file"
}


if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    $opt_update && { update_script "$@"; exit 0; }
    $opt_gen_rebuild && { generate_rebuild_script "$@"; exit 0; }

    echo "folder_name=$folder_name"
    echo "config_filename=$config_filename"
    [[ -n "$folder_name" && "$folder_name" != "." && "$folder_name" != ".." && "$folder_name" != */* && "$folder_name" != *\\* ]] || exit 1

    # clone and enter the folder
    cd "$HOME"
    if [ -d "$folder_name" ] && $opt_keep; then
        cd "$folder_name"
        # backup "dl" "feeds" ".config"
        temp_dir=$(mktemp -d ~/OPENWRT_BAK_XXXXXXXX)
        for item in "dl" "feeds" ".config"; do
            [ -e "$item" ] && mv -v "$item" "$temp_dir"
        done
        # restore to the state of cloning from scratch
        git fetch origin
        git reset --hard origin/$(git branch --show-current)
        git clean -dfx --quiet
        # move "dl" "feeds" ".config" back
        mv -vf "$temp_dir"/* "$temp_dir"/.[!.]* "$temp_dir"/..?* . 2>/dev/null
        rm -rfv "$temp_dir"
    else
        rm -rf "$folder_name"
        "${git_clone_cmd[@]}"
        cd "$folder_name"
    fi

    generate_rebuild_script --direct
    source rebuild.sh
    update_feeds

    # set .config
    if [ ! -e ".config" ]; then
        if $opt_skip_config; then
            [ "$opt_branch" == "immortalwrt-mt798x" ] && cp -vf defconfig/mt7986-ax6000.config .config
            exit 0
        fi
        download_config "$config_filename"
    fi

    # start compilation
    $opt_skip_make && exit 0
    make_with_timer
fi
