#!/usr/bin/env bash
set -euo pipefail

# ─────────────────────────────────────────────────────────────────────────────
# 12-remote-manager.sh — SecureGit Remote Operations
#
# Manage git remotes: list, add, remove, rename, change URLs, fetch, push,
# inspect tracking, prune stale refs, and integrate with securegit auth/backup.
#
# Usage:
#   ./12-remote-manager.sh [command] [args]
#   ./12-remote-manager.sh                      # Interactive menu
#   ./12-remote-manager.sh list                 # List remotes
#   ./12-remote-manager.sh add <name> <url>     # Add remote
#   ./12-remote-manager.sh remove <name>        # Remove remote
#   ./12-remote-manager.sh rename <old> <new>   # Rename remote
#   ./12-remote-manager.sh set-url <name> <url> # Change URL
#   ./12-remote-manager.sh fetch [name|--all]   # Fetch
#   ./12-remote-manager.sh push-all             # Push to all
#   ./12-remote-manager.sh tracking             # Show tracking info
#   ./12-remote-manager.sh prune [name|--all]   # Prune stale refs
#   ./12-remote-manager.sh auth                 # Auth status
#   ./12-remote-manager.sh backups              # Backup destinations
# ─────────────────────────────────────────────────────────────────────────────

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/lib/securegit-common.sh"

COMMAND="" EXTRA_ARGS=()
show_help() { sed -n '/^# Usage:/,/^# ──/{ /^# ──/d; s/^# \?//; p }' "$0"; exit 0; }

while [[ $# -gt 0 ]]; do
    case "$1" in
        list|add|remove|rename|set-url|fetch|push-all|tracking|prune|auth|backups) COMMAND="$1"; shift ;;
        --help|-h) show_help ;; *) EXTRA_ARGS+=("$1"); shift ;;
    esac
done

sg_require_repo
CURRENT_BRANCH="$(sg_current_branch)"
PRIMARY_REMOTE="${SG_PRIMARY_REMOTE:-origin}"

require_remote() { sg_remote_exists "$1" || sg_die "Remote '$1' not found."; }

# ─── List ────────────────────────────────────────────────────────────────────
cmd_list() {
    sg_header "Remote Repositories"
    local remotes; remotes="$(git remote 2>/dev/null)"
    [[ -z "$remotes" ]] && { sg_warn "No remotes. Add with: $(basename "$0") add <name> <url>"; return; }
    printf "  ${_C_DIM}%-15s  %-50s  %s${_C_RESET}\n" "NAME" "URL" "INFO"
    sg_divider
    while IFS= read -r r; do
        [[ -z "$r" ]] && continue
        local fetch_url push_url mark=""
        fetch_url="$(git remote get-url "$r" 2>/dev/null || echo "N/A")"
        push_url="$(git remote get-url --push "$r" 2>/dev/null || echo "N/A")"
        [[ "$r" == "$PRIMARY_REMOTE" ]] && mark=" ${_C_CYAN}[primary]${_C_RESET}"
        printf "  ${_C_BOLD}%-15s${_C_RESET}  %-50s  ${_C_DIM}fetch${_C_RESET}%b\n" "$r" "$fetch_url" "$mark"
        [[ "$push_url" != "$fetch_url" ]] && printf "  %-15s  %-50s  ${_C_DIM}push${_C_RESET}\n" "" "$push_url"
    done <<< "$remotes"
    echo
}

# ─── Add ─────────────────────────────────────────────────────────────────────
cmd_add() {
    sg_header "Add Remote"
    local name="" url=""
    if [[ ${#EXTRA_ARGS[@]} -ge 2 ]]; then name="${EXTRA_ARGS[0]}"; url="${EXTRA_ARGS[1]}"
    else [[ ${#EXTRA_ARGS[@]} -eq 1 ]] && name="${EXTRA_ARGS[0]}" || name="$(sg_prompt "Remote name")"
        url="$(sg_prompt "Remote URL")"; fi
    [[ -z "$name" ]] && sg_die "Name required."; [[ -z "$url" ]] && sg_die "URL required."
    sg_remote_exists "$name" && sg_die "'$name' already exists. Use set-url."
    [[ ! "$url" =~ ^(https?://|git@|ssh://|git://) ]] && { sg_warn "URL format unusual."; sg_confirm "Add anyway?" "n" || sg_die "Aborted."; }
    printf "  Name: ${_C_BOLD}%s${_C_RESET}  URL: ${_C_BOLD}%s${_C_RESET}\n\n" "$name" "$url"
    if sg_confirm "Add this remote?"; then
        _sg_cmd remote add "$name" "$url" 2>&1; sg_success "Remote '$name' added."
        sg_confirm "Fetch from '$name' now?" && { _sg_cmd fetch "$name" 2>&1; sg_success "Fetched."; }
        sg_undo_available
    fi
}

# ─── Remove ──────────────────────────────────────────────────────────────────
cmd_remove() {
    sg_header "Remove Remote"
    local name=""
    if [[ ${#EXTRA_ARGS[@]} -ge 1 ]]; then name="${EXTRA_ARGS[0]}"
    else
        local remotes=()
        while IFS= read -r r; do [[ -n "$r" ]] && remotes+=("$r"); done < <(git remote 2>/dev/null)
        [[ ${#remotes[@]} -eq 0 ]] && sg_die "No remotes."
        for i in "${!remotes[@]}"; do
            local url mark=""; url="$(git remote get-url "${remotes[$i]}" 2>/dev/null)"
            [[ "${remotes[$i]}" == "$PRIMARY_REMOTE" ]] && mark=" ${_C_CYAN}[primary]${_C_RESET}"
            printf "  ${_C_BOLD}%2d)${_C_RESET} %-15s  %s%b\n" "$((i+1))" "${remotes[$i]}" "$url" "$mark"
        done; echo
        local c; printf "Select [1-%d]: " "${#remotes[@]}"; read -r c
        [[ "$c" =~ ^[0-9]+$ ]] && (( c >= 1 && c <= ${#remotes[@]} )) && name="${remotes[$((c-1))]}" || sg_die "Invalid."
    fi
    require_remote "$name"
    [[ "$name" == "$PRIMARY_REMOTE" ]] && sg_warn "'$name' is the primary remote!"
    local url; url="$(git remote get-url "$name" 2>/dev/null)"
    printf "  Remote: ${_C_BOLD}%s${_C_RESET}  URL: %s\n" "$name" "$url"
    local tracking; tracking="$(git branch -vv 2>/dev/null | grep "\[$name/" || true)"
    [[ -n "$tracking" ]] && { echo; sg_warn "Branches tracking '$name':"; echo "$tracking" | head -10; }
    echo; sg_confirm "Remove '$name'?" "n" && { _sg_cmd remote remove "$name" 2>&1; sg_success "Removed."; sg_undo_available; }
}

# ─── Rename ──────────────────────────────────────────────────────────────────
cmd_rename() {
    sg_header "Rename Remote"
    local old="" new=""
    if [[ ${#EXTRA_ARGS[@]} -ge 2 ]]; then old="${EXTRA_ARGS[0]}"; new="${EXTRA_ARGS[1]}"
    else [[ ${#EXTRA_ARGS[@]} -eq 1 ]] && old="${EXTRA_ARGS[0]}" || old="$(sg_prompt "Current name")"
        new="$(sg_prompt "New name")"; fi
    [[ -z "$old" || -z "$new" ]] && sg_die "Both names required."
    require_remote "$old"; sg_remote_exists "$new" && sg_die "'$new' already exists."
    printf "  ${_C_BOLD}%s${_C_RESET} -> ${_C_BOLD}%s${_C_RESET}\n\n" "$old" "$new"
    if sg_confirm "Rename?"; then
        _sg_cmd remote rename "$old" "$new" 2>&1; sg_success "Renamed."
        [[ "$old" == "$PRIMARY_REMOTE" ]] && sg_warn "Update SG_PRIMARY_REMOTE=$new in config."
        sg_undo_available
    fi
}

# ─── Set URL ─────────────────────────────────────────────────────────────────
cmd_set_url() {
    sg_header "Change Remote URL"
    local name="" url=""
    if [[ ${#EXTRA_ARGS[@]} -ge 2 ]]; then name="${EXTRA_ARGS[0]}"; url="${EXTRA_ARGS[1]}"
    else [[ ${#EXTRA_ARGS[@]} -eq 1 ]] && name="${EXTRA_ARGS[0]}" || name="$(sg_prompt "Remote" "$PRIMARY_REMOTE")"
        url="$(sg_prompt "New URL")"; fi
    [[ -z "$name" || -z "$url" ]] && sg_die "Name and URL required."
    require_remote "$name"
    local old_url; old_url="$(git remote get-url "$name" 2>/dev/null)"
    [[ "$old_url" == "$url" ]] && { sg_info "Already set."; return; }
    printf "  Current: %s\n  New:     ${_C_BOLD}%s${_C_RESET}\n\n" "$old_url" "$url"
    if sg_confirm "Update URL?"; then
        _sg_cmd remote set-url "$name" "$url" 2>&1; sg_success "URL updated."
        if sg_confirm "Fetch to verify?"; then
            _sg_cmd fetch "$name" 2>&1 && sg_success "Fetch OK." || {
                sg_warn "Fetch failed."; sg_confirm "Revert to old URL?" "n" && _sg_cmd remote set-url "$name" "$old_url" 2>&1
            }
        fi
        sg_undo_available
    fi
}

# ─── Fetch ───────────────────────────────────────────────────────────────────
cmd_fetch() {
    sg_header "Fetch from Remotes"
    local target=""; [[ ${#EXTRA_ARGS[@]} -ge 1 ]] && target="${EXTRA_ARGS[0]}"
    if [[ "$target" == "--all" || -z "$target" ]]; then
        local errors=0
        while IFS= read -r r; do
            [[ -z "$r" ]] && continue
            printf "  Fetching ${_C_BOLD}%s${_C_RESET}... " "$r"
            _sg_cmd fetch "$r" --prune 2>&1 && printf "${_C_GREEN}ok${_C_RESET}\n" || { printf "${_C_RED}fail${_C_RESET}\n"; ((errors++)); }
        done < <(git remote 2>/dev/null)
        echo; [[ $errors -eq 0 ]] && sg_success "All fetched." || sg_warn "$errors failed."
    else
        require_remote "$target"; _sg_cmd fetch "$target" --prune 2>&1; sg_success "Fetched '$target'."
    fi
    echo; sg_info "Recent remote updates:"
    git for-each-ref --sort=-committerdate --count=8 --format='  %(refname:short)  %(committerdate:relative)' refs/remotes/ 2>/dev/null
    echo
}

# ─── Push all ────────────────────────────────────────────────────────────────
cmd_push_all() {
    sg_header "Push to All Remotes"
    local count; count="$(git remote 2>/dev/null | wc -l)"
    [[ "$count" -eq 0 ]] && sg_die "No remotes."
    sg_info "Pushing '$CURRENT_BRANCH' to $count remote(s):"
    git remote 2>/dev/null | while IFS= read -r r; do
        printf "  ${_C_BOLD}%s${_C_RESET}  %s\n" "$r" "$(git remote get-url --push "$r" 2>/dev/null)"
    done; echo
    sg_confirm "Push to all?" || sg_die "Cancelled."
    if [[ "${SG_PRE_PUSH_SCAN:-true}" == "true" ]] && command -v securegit &>/dev/null; then
        securegit scan --min-severity high 2>/dev/null || { sg_warn "Scan found issues."; sg_confirm "Push anyway?" "n" || sg_die "Cancelled."; }
    fi
    local errors=0
    while IFS= read -r r; do
        [[ -z "$r" ]] && continue; printf "  Pushing ${_C_BOLD}%s${_C_RESET}... " "$r"
        _sg_cmd push "$r" "$CURRENT_BRANCH" 2>&1 && printf "${_C_GREEN}ok${_C_RESET}\n" || { printf "${_C_RED}fail${_C_RESET}\n"; ((errors++)); }
    done < <(git remote 2>/dev/null)
    echo; [[ $errors -eq 0 ]] && sg_success "All pushed." || sg_warn "$errors failed."
}

# ─── Tracking ────────────────────────────────────────────────────────────────
cmd_tracking() {
    sg_header "Branch Tracking Relationships"
    printf "  ${_C_DIM}%-25s  %-30s  %s${_C_RESET}\n" "LOCAL" "UPSTREAM" "STATUS"
    sg_divider
    while IFS= read -r branch; do
        [[ -z "$branch" ]] && continue
        local up; up="$(git rev-parse --abbrev-ref "$branch@{upstream}" 2>/dev/null || echo "-")"
        local status="" mark=""
        [[ "$branch" == "$CURRENT_BRANCH" ]] && mark=" ${_C_GREEN}*${_C_RESET}"
        if [[ "$up" != "-" ]]; then
            local a b; a="$(git rev-list --count "$up".."$branch" 2>/dev/null || echo 0)"
            b="$(git rev-list --count "$branch".."$up" 2>/dev/null || echo 0)"
            if [[ "$a" -eq 0 && "$b" -eq 0 ]]; then status="${_C_GREEN}up to date${_C_RESET}"
            elif [[ "$a" -gt 0 && "$b" -gt 0 ]]; then status="${_C_YELLOW}diverged +$a/-$b${_C_RESET}"
            elif [[ "$a" -gt 0 ]]; then status="${_C_CYAN}ahead $a${_C_RESET}"
            else status="${_C_YELLOW}behind $b${_C_RESET}"; fi
        else status="${_C_DIM}no upstream${_C_RESET}"; fi
        printf "  %-25s  %-30s  %b%b\n" "$branch" "$up" "$status" "$mark"
    done < <(git for-each-ref --format='%(refname:short)' refs/heads/ 2>/dev/null)
    echo; sg_info "Untracked remote branches:"
    local ct=0
    while IFS= read -r rb; do
        [[ -z "$rb" || "$rb" == *"/HEAD" ]] && continue
        sg_branch_exists "${rb#*/}" || { printf "  ${_C_DIM}%s${_C_RESET}\n" "$rb"; ((ct++)); }
    done < <(git for-each-ref --format='%(refname:short)' refs/remotes/ 2>/dev/null)
    [[ $ct -eq 0 ]] && sg_info "  All tracked." || sg_info "  Track with: git checkout -b <name> <remote/branch>"
    echo
}

# ─── Prune ───────────────────────────────────────────────────────────────────
cmd_prune() {
    sg_header "Prune Stale Remote References"
    local targets=()
    if [[ ${#EXTRA_ARGS[@]} -ge 1 && "${EXTRA_ARGS[0]}" != "--all" ]]; then
        require_remote "${EXTRA_ARGS[0]}"; targets=("${EXTRA_ARGS[0]}")
    else while IFS= read -r r; do [[ -n "$r" ]] && targets+=("$r"); done < <(git remote 2>/dev/null); fi
    local total=0
    for r in "${targets[@]}"; do
        git remote prune "$r" --dry-run 2>/dev/null | grep '\[would prune\]' | while IFS= read -r l; do
            printf "  ${_C_DIM}stale:${_C_RESET} %s\n" "$(echo "$l" | awk '{print $NF}')"; ((total++)) || true
        done
    done; echo
    sg_confirm "Prune stale references?" && { for r in "${targets[@]}"; do _sg_cmd remote prune "$r" 2>&1; done; sg_success "Pruned."; }
}

# ─── Auth ────────────────────────────────────────────────────────────────────
cmd_auth() {
    sg_header "Authentication Status"
    command -v securegit &>/dev/null && { securegit auth status 2>&1 || true; echo; } || sg_warn "securegit not installed."
    sg_info "Connectivity test:"
    while IFS= read -r r; do
        [[ -z "$r" ]] && continue; printf "  ${_C_BOLD}%s${_C_RESET}... " "$r"
        git ls-remote --heads "$r" HEAD &>/dev/null && printf "${_C_GREEN}ok${_C_RESET}\n" || printf "${_C_RED}fail${_C_RESET}\n"
    done < <(git remote 2>/dev/null); echo
}

# ─── Backups ─────────────────────────────────────────────────────────────────
cmd_backups() {
    sg_header "Backup Destinations"
    sg_info "Remotes (code distribution):"
    while IFS= read -r r; do [[ -n "$r" ]] && printf "  ${_C_BOLD}%s${_C_RESET}  %s\n" "$r" "$(git remote get-url "$r" 2>/dev/null)"; done < <(git remote 2>/dev/null)
    echo; sg_divider
    if command -v securegit &>/dev/null; then
        sg_info "SecureGit backup destinations:"; securegit backup list 2>&1 || sg_info "  None configured."
        sg_info "Add: securegit backup add --name <n> --destination <path>"
    else sg_warn "securegit not installed for backup features."; fi
    echo
}

# ─── Interactive menu ────────────────────────────────────────────────────────
interactive_menu() {
    sg_header "SecureGit Remote Manager"
    sg_info "Branch: ${_C_BOLD}$CURRENT_BRANCH${_C_RESET}"
    sg_has_remote && { echo; git remote 2>/dev/null | while IFS= read -r r; do
        local m=""; [[ "$r" == "$PRIMARY_REMOTE" ]] && m=" ${_C_CYAN}[primary]${_C_RESET}"
        printf "  ${_C_BOLD}%s${_C_RESET}  %s%b\n" "$r" "$(git remote get-url "$r" 2>/dev/null)" "$m"
    done; }
    echo; sg_divider
    printf "\n  ${_C_BOLD}View${_C_RESET}                              ${_C_BOLD}Manage${_C_RESET}\n"
    printf "  ${_C_BOLD}1)${_C_RESET} List remotes                ${_C_BOLD}5)${_C_RESET} Add remote\n"
    printf "  ${_C_BOLD}2)${_C_RESET} Tracking relationships      ${_C_BOLD}6)${_C_RESET} Remove remote\n"
    printf "  ${_C_BOLD}3)${_C_RESET} Auth status                 ${_C_BOLD}7)${_C_RESET} Rename remote\n"
    printf "  ${_C_BOLD}4)${_C_RESET} Backup destinations         ${_C_BOLD}8)${_C_RESET} Change URL\n"
    printf "\n  ${_C_BOLD}Sync${_C_RESET}\n"
    printf "  ${_C_BOLD}9)${_C_RESET} Fetch all  ${_C_BOLD}10)${_C_RESET} Push all  ${_C_BOLD}11)${_C_RESET} Prune stale  ${_C_BOLD}q)${_C_RESET} Quit\n\n"
    local c; printf "Select [1-11, q]: "; read -r c
    case "$c" in
        1) cmd_list ;; 2) cmd_tracking ;; 3) cmd_auth ;; 4) cmd_backups ;;
        5) cmd_add ;; 6) cmd_remove ;; 7) cmd_rename ;; 8) cmd_set_url ;;
        9) EXTRA_ARGS=("--all"); cmd_fetch ;; 10) cmd_push_all ;; 11) EXTRA_ARGS=("--all"); cmd_prune ;;
        q|quit) exit 0 ;; *) sg_die "Invalid." ;;
    esac
}

# ─── Main ────────────────────────────────────────────────────────────────────
case "$COMMAND" in
    list) cmd_list ;; add) cmd_add ;; remove) cmd_remove ;; rename) cmd_rename ;;
    set-url) cmd_set_url ;; fetch) cmd_fetch ;; push-all) cmd_push_all ;;
    tracking) cmd_tracking ;; prune) cmd_prune ;; auth) cmd_auth ;; backups) cmd_backups ;;
    "") interactive_menu ;; *) sg_die "Unknown: $COMMAND. Use --help." ;;
esac
