#!/usr/bin/env bash
# gh-sonr-org-migrate
# Migrates all repos from orgs matching "sonr" into sonr-io,
# prompting via gum for renames on collision, then deletes emptied orgs.
#
# Requires: gh (authenticated as org owner on all orgs), gum, jq

TARGET_ORG=sonr-io

red()    { printf '\033[31m%s\033[0m\n' "$*"; }
green()  { printf '\033[32m%s\033[0m\n' "$*"; }
yellow() { printf '\033[33m%s\033[0m\n' "$*"; }
cyan()   { printf '\033[36m%s\033[0m\n' "$*"; }
bcyan()  { printf '\033[1;36m%s\033[0m\n' "$*"; }
bgreen() { printf '\033[1;32m%s\033[0m\n' "$*"; }

# ── Preflight ────────────────────────────────────────────────────────────────
for bin in gh gum jq; do
    if ! command -v "$bin" >/dev/null 2>&1; then
        red "missing dependency: $bin"
        exit 1
    fi
done

if ! gh auth status >/dev/null 2>&1; then
    red "gh is not authenticated"
    exit 1
fi

# ── Discover source orgs ─────────────────────────────────────────────────────
# All orgs the user belongs to whose login contains "sonr", excluding target.
mapfile -t source_orgs < <(gh api user/orgs --paginate --jq '.[].login' \
    | grep 'sonr' | grep -vx "$TARGET_ORG")

if [ "${#source_orgs[@]}" -eq 0 ]; then
    echo "No source orgs found. Nothing to do."
    exit 0
fi

cyan "Source orgs:"
printf '  %s\n' "${source_orgs[@]}"
cyan "Target org:"
echo " $TARGET_ORG"
echo

# Let the user confirm / trim the list interactively
mapfile -t selected_orgs < <(printf '%s\n' "${source_orgs[@]}" | gum choose --no-limit \
    --header "Select orgs to migrate into $TARGET_ORG (space to toggle, enter to confirm)")

if [ "${#selected_orgs[@]}" -eq 0 ]; then
    echo "Nothing selected. Exiting."
    exit 0
fi

# ── Helpers ──────────────────────────────────────────────────────────────────
repo_exists_in_target() {
    gh api "repos/$TARGET_ORG/$1" --silent >/dev/null 2>&1
}

transfer_repo() {
    # $1 = source org, $2 = repo name, $3 = (optional) new name
    local src=$1 repo=$2 new_name=${3:-}
    local args=(-f "new_owner=$TARGET_ORG")
    if [ -n "$new_name" ]; then
        args+=(-f "new_name=$new_name")
    fi
    gh api -X POST "repos/$src/$repo/transfer" "${args[@]}" --silent
}

# ── Migration ────────────────────────────────────────────────────────────────
failed_transfers=()

for org in "${selected_orgs[@]}"; do
    echo
    bcyan "── $org ──"

    mapfile -t repos < <(gh api "orgs/$org/repos" --paginate --jq '.[].name')

    if [ "${#repos[@]}" -eq 0 ]; then
        echo "  (no repos)"
        continue
    fi

    for repo in "${repos[@]}"; do
        new_name=""

        if repo_exists_in_target "$repo"; then
            yellow "  ⚠ $repo already exists in $TARGET_ORG"
            while true; do
                new_name=$(gum input \
                    --header "New name for $org/$repo (exists in $TARGET_ORG)" \
                    --placeholder "$org-$repo" \
                    --value "$org-$repo")
                if [ -z "$new_name" ]; then
                    echo "    skipped $org/$repo"
                    new_name=__SKIP__
                    break
                fi
                if repo_exists_in_target "$new_name"; then
                    yellow "    $new_name also exists — pick another"
                else
                    break
                fi
            done
            [ "$new_name" = __SKIP__ ] && continue
        fi

        label="$org/$repo → $TARGET_ORG/${new_name:-$repo}"
        if transfer_repo "$org" "$repo" "$new_name"; then
            green "  ✓ $label"
        else
            red "  ✗ failed: $label"
            failed_transfers+=("$org/$repo")
        fi
    done
done

if [ "${#failed_transfers[@]}" -gt 0 ]; then
    echo
    red "Failed transfers (orgs containing these will NOT be deleted):"
    printf '  %s\n' "${failed_transfers[@]}"
fi

# ── Wait for transfers to settle ─────────────────────────────────────────────
# GitHub repo transfers are asynchronous; give them time to drain.
echo
gum spin --title "Waiting 30s for transfers to settle..." -- sleep 30

# ── Delete emptied orgs ──────────────────────────────────────────────────────
echo
for org in "${selected_orgs[@]}"; do
    # Skip orgs with failed transfers
    org_had_failure=0
    for f in ${failed_transfers[@]+"${failed_transfers[@]}"}; do
        case "$f" in
            "$org"/*) org_had_failure=1; break ;;
        esac
    done
    if [ "$org_had_failure" -eq 1 ]; then
        yellow "skipping delete: $org (had failures)"
        continue
    fi

    remaining=$(gh api "orgs/$org/repos" --paginate --jq '. | length' | jq -s 'add // 0')

    if [ "$remaining" -gt 0 ]; then
        yellow "skipping delete: $org still has $remaining repo(s) (transfer pending?)"
        continue
    fi

    if gum confirm "Delete empty org $org?"; then
        if gh api -X DELETE "orgs/$org" --silent; then
            green "✓ deleted $org"
        else
            red "✗ could not delete $org (API delete requires org owner; may need manual deletion in Settings)"
        fi
    else
        echo "kept $org"
    fi
done

echo
bgreen "Done."
