#!/usr/bin/env bash
# gniza4cp/lib/transfer.sh — rsync --link-dest to remote, .partial atomicity, retries

rsync_to_remote() {
    local source_dir="$1"
    local remote_dest="$2"
    local link_dest="${3:-}"
    local attempt=0
    local max_retries="${SSH_RETRIES:-$DEFAULT_SSH_RETRIES}"
    local rsync_ssh; rsync_ssh=$(build_rsync_ssh_cmd)

    local rsync_opts=(-aHAX --numeric-ids --delete --rsync-path="rsync --fake-super")

    if [[ -n "$link_dest" ]]; then
        rsync_opts+=(--link-dest="$link_dest")
    fi

    if [[ "${BWLIMIT:-0}" -gt 0 ]]; then
        rsync_opts+=(--bwlimit="$BWLIMIT")
    fi

    if [[ -n "${RSYNC_EXTRA_OPTS:-}" ]]; then
        # shellcheck disable=SC2206
        rsync_opts+=($RSYNC_EXTRA_OPTS)
    fi

    rsync_opts+=(-e "$rsync_ssh")

    # Ensure source ends with /
    [[ "$source_dir" != */ ]] && source_dir="$source_dir/"

    while (( attempt < max_retries )); do
        ((attempt++)) || true
        log_debug "rsync attempt $attempt/$max_retries: $source_dir -> $remote_dest"

        log_debug "CMD: rsync ${rsync_opts[*]} $source_dir ${REMOTE_USER}@${REMOTE_HOST}:${remote_dest}"
        local rsync_cmd=(rsync "${rsync_opts[@]}" "$source_dir" "${REMOTE_USER}@${REMOTE_HOST}:${remote_dest}")
        if _is_password_mode; then
            export SSHPASS="$REMOTE_PASSWORD"
            rsync_cmd=(sshpass -e "${rsync_cmd[@]}")
        fi
        local rc=0
        "${rsync_cmd[@]}" || rc=$?
        if (( rc == 0 )); then
            log_debug "rsync succeeded on attempt $attempt"
            return 0
        fi

        log_warn "rsync failed (exit $rc), attempt $attempt/$max_retries"

        if (( attempt < max_retries )); then
            local backoff=$(( attempt * 10 ))
            log_info "Retrying in ${backoff}s..."
            sleep "$backoff"
        fi
    done

    log_error "rsync failed after $max_retries attempts"
    return 1
}

transfer_pkgacct() {
    local user="$1"
    local timestamp="$2"
    local prev_snapshot="${3:-}"
    local temp_dir="${TEMP_DIR:-$DEFAULT_TEMP_DIR}"
    local source="$temp_dir/$user"

    if _is_rclone_mode; then
        local snap_subpath="accounts/${user}/snapshots/${timestamp}"
        log_info "Transferring pkgacct data for $user (rclone)..."
        rclone_to_remote "$source" "$snap_subpath"
        return
    fi

    local snap_dir; snap_dir=$(get_snapshot_dir "$user")
    local dest="$snap_dir/${timestamp}.partial/"
    local link_dest=""

    if [[ -n "$prev_snapshot" ]]; then
        # Detect old format (pkgacct/ subdir) vs new format (content at root)
        if remote_exec "test -d '$snap_dir/$prev_snapshot/pkgacct'" 2>/dev/null; then
            link_dest="$snap_dir/$prev_snapshot/pkgacct"
        else
            link_dest="$snap_dir/$prev_snapshot"
        fi
    fi

    ensure_remote_dir "$dest" || return 1

    log_info "Transferring pkgacct data for $user..."
    rsync_to_remote "$source" "$dest" "$link_dest"
}

transfer_homedir() {
    local user="$1"
    local timestamp="$2"
    local prev_snapshot="${3:-}"
    local homedir; homedir=$(get_account_homedir "$user")

    if [[ ! -d "$homedir" ]]; then
        log_warn "Home directory not found for $user: $homedir"
        return 1
    fi

    if _is_rclone_mode; then
        local snap_subpath="accounts/${user}/snapshots/${timestamp}/homedir"
        log_info "Transferring homedir for $user ($homedir) (rclone)..."
        rclone_to_remote "$homedir" "$snap_subpath"
        return
    fi

    local snap_dir; snap_dir=$(get_snapshot_dir "$user")
    local dest="$snap_dir/${timestamp}.partial/homedir/"
    local link_dest=""

    if [[ -n "$prev_snapshot" ]]; then
        link_dest="$snap_dir/$prev_snapshot/homedir"
    fi

    ensure_remote_dir "$dest" || return 1

    log_info "Transferring homedir for $user ($homedir)..."
    rsync_to_remote "$homedir" "$dest" "$link_dest"
}

finalize_snapshot() {
    local user="$1"
    local timestamp="$2"

    if _is_rclone_mode; then
        log_info "Finalizing snapshot for $user: $timestamp (rclone)"
        rclone_finalize_snapshot "$user" "$timestamp"
        return
    fi

    local snap_dir; snap_dir=$(get_snapshot_dir "$user")

    log_info "Finalizing snapshot for $user: $timestamp"
    remote_exec "mv '$snap_dir/${timestamp}.partial' '$snap_dir/$timestamp'" || {
        log_error "Failed to finalize snapshot for $user: $timestamp"
        return 1
    }

    update_latest_symlink "$user" "$timestamp"
}
