import { getErrorMessage } from "../../utils/error-message.js";
import { randomUUID } from "crypto";
import { performance } from "node:perf_hooks";
import type { ClientChannel } from "ssh2";
import { fileLogger } from "../../utils/logger.js";
import {
  basename,
  dirname,
  getWorkingDir,
  inferPlatformFromPath,
  joinPath,
  normalizeSftpPath,
  pathsOverlap,
  sftpPathToLocalPath,
  type TransferPlatform,
} from "../transfer-paths.js";
import {
  buildTransferScanSummary,
  estimateIncompressibleSample,
  getArchiveTransferReasonKey,
  resolveArchiveTransferMethod,
  type TransferMethodPreference,
  type TransferScanSummary,
} from "./transfer-routing.js";
import { verifySftpFileIntegrity } from "./transfer-integrity.js";
import {
  promisifySftpChmod,
  promisifySftpClose,
  promisifySftpFstat,
  promisifySftpOpen,
  promisifySftpStat,
  promisifySftpUnlink,
} from "./sftp-promisify.js";
import {
  buildTransferHopTimings,
  computeTransferMbPerSec,
  createEmptyXferStats,
  createHopWallClock,
  createThrottledProgress,
  elapsedMs,
  hopSpanMs,
  mergeXferStats,
  noteHopEnd,
  noteHopStart,
  type PipelinedXferStats,
  type TransferTimings,
} from "./transfer-stats.js";
import {
  TransferCancelledError,
  TransferStalledError,
  isRecoverableTransferError,
} from "./transfer-errors.js";
import {
  escapeShell,
  isLocalSshEndpoint,
  isPermissionError,
  isRootOnlyPath,
} from "./transfer-host-utils.js";
import {
  SFTP_OPEN_READ,
  SFTP_OPEN_WRITE,
  SFTP_OPEN_WRITE_RESUME,
} from "./sftp-promisify.js";
import {
  collectFileWorkItems,
  readSftpSample,
  type FileWorkItem,
} from "./transfer-scan.js";
import {
  deletePathSftp,
  ensureDirectoryTreeSftp,
} from "./transfer-sftp-dir.js";
import {
  DEFAULT_PARALLEL_SEGMENT_COUNT,
  SFTP_XFER_SEGMENT_SIZE,
  buildSegmentCopyJobs,
  clampParallelSegmentCount,
  type SegmentCopyJob,
} from "./transfer-segment-copy.js";
import {
  buildDirectProbeCommand,
  buildDirectRsyncCommand,
  quoteShell,
  shouldBenchmarkDirectTransfer,
  shouldUseDirectTransfer,
  type DirectTransferEndpoint,
} from "./direct-transfer-routing.js";
import {
  getRecentDirectRouteDecision,
  getTransferProfile,
  initializeTransferProfiles,
  recordDirectRouteBenchmark,
  recordDirectRouteOutcome,
  recordTransferProfile,
  selectTransferTuning,
} from "./transfer-tuning.js";

export type {
  TransferMethodPreference,
  TransferScanSummary,
} from "./transfer-routing.js";

export interface TransferMethodPreview {
  methodPreference: TransferMethodPreference;
  resolvedMethod: "tar" | "item_sftp";
  reasonKey: ReturnType<typeof getArchiveTransferReasonKey>;
  sourcePlatform: TransferPlatform;
  destPlatform: TransferPlatform;
  sourceHasTar: boolean;
  destHasTar: boolean;
  summary: TransferScanSummary;
}

type SFTPWrapper = import("ssh2").SFTPWrapper;

export interface SSHSessionLike {
  client: import("ssh2").Client;
  isConnected: boolean;
  lastActive: number;
  activeOperations: number;
  sftp?: SFTPWrapper;
  sftpPending?: Promise<SFTPWrapper>;
  channelOpener: { run: <T>(fn: () => Promise<T>) => Promise<T> };
  userId?: string;
  ip?: string;
  port?: number;
  username?: string;
  transferPlatform?: TransferPlatform;
}

export interface HostTransferDeps {
  sshSessions: Record<string, SSHSessionLike>;
  getSessionSftp: (session: SSHSessionLike) => Promise<SFTPWrapper>;
  execChannel: (
    session: SSHSessionLike,
    command: string,
    callback: (err: Error | undefined, stream: ClientChannel) => void,
  ) => void;
  verifySessionOwnership: (session: SSHSessionLike, userId: string) => boolean;
  openDedicatedTransferSession: (
    browseSessionId: string,
    dedicatedSessionId: string,
    userId: string,
    transferId: string,
    options?: { allowBrowseDisconnected?: boolean },
  ) => Promise<SSHSessionLike>;
  closeDedicatedTransferSession: (sessionId: string) => void;
}

export type TransferPhase =
  | "compressing"
  | "transferring"
  | "benchmarking"
  | "verifying"
  | "extracting"
  | "reconnecting";
export type TransferStatus =
  "running" | "success" | "partial" | "error" | "cancelled";
export type TransferMethod = "stream" | "tar" | "item_sftp" | "direct_rsync";

export type {
  TransferHopId,
  TransferHopMetrics,
  TransferTimings,
} from "./transfer-stats.js";

export interface TransferProgress {
  transferId: string;
  status: TransferStatus;
  phase: TransferPhase;
  bytesTransferred?: number;
  totalBytes?: number;
  itemsCompleted?: number;
  totalItems?: number;
  failedPaths?: string[];
  message?: string;
  method?: TransferMethod;
  sourcePaths?: string[];
  destPath?: string;
  userId?: string;
  sourceSessionId?: string;
  destSessionId?: string;
  dedicatedSourceSessionId?: string;
  dedicatedDestSessionId?: string;
  startedAt?: number;
  lastActivityAt?: number;
  reconnectingAt?: number;
  timings?: TransferTimings;
  sourceDeleted?: boolean;
  moveRequested?: boolean;
  methodPreference?: TransferMethodPreference;
  parallelSegmentCount?: number;
  /** Destination paths created or partially written before cancel. */
  destArtifacts?: string[];
  tempArchivePath?: string;
  partialDestRemaining?: boolean;
  cleanupCompleted?: boolean;
  retryable?: boolean;
  integrityVerified?: boolean;
  requestSnapshot?: {
    sourceSessionId: string;
    sourcePaths: string[];
    destSessionId: string;
    destPath: string;
    move?: boolean;
    methodPreference?: TransferMethodPreference;
    parallelSegmentCount?: number;
  };
}

export interface TransferRequest {
  sourceSessionId: string;
  sourcePaths: string[];
  destSessionId: string;
  destPath: string;
  move?: boolean;
  userId: string;
  methodPreference?: TransferMethodPreference;
  /** Explicit parallel lane override; omitted values are tuned automatically. */
  parallelSegmentCount?: number;
}

const activeTransfers = new Map<string, TransferProgress>();
const cancelRequestedTransfers = new Set<string>();
const directRouteCache = new Map<
  string,
  { useDirect: boolean; expiresAt: number; directMs?: number; relayMs?: number }
>();

/** In-flight pipelined SFTP reads; force-closed when the user cancels. */
interface ActiveXferControl {
  abort: (err: Error) => void;
  closeResources: () => Promise<void>;
}
const activeXferControls = new Map<string, ActiveXferControl>();
const cancelWatchdogs = new Map<string, ReturnType<typeof setTimeout>>();

function throwIfCancelled(transferId: string): void {
  if (cancelRequestedTransfers.has(transferId)) {
    throw new TransferCancelledError();
  }
}

function createTransferShouldAbort(transferId: string): () => boolean {
  return () => {
    if (cancelRequestedTransfers.has(transferId)) {
      return true;
    }
    const progress = activeTransfers.get(transferId);
    return progress !== undefined && progress.status !== "running";
  };
}

export function requestTransferCancel(
  transferId: string,
  userId: string,
): boolean {
  const progress = activeTransfers.get(transferId);
  if (
    !progress ||
    progress.userId !== userId ||
    progress.status !== "running"
  ) {
    return false;
  }
  cancelRequestedTransfers.add(transferId);
  updateTransfer(transferId, { message: "Cancellation requested" });
  void forceAbortActiveXfer(transferId);

  if (!cancelWatchdogs.has(transferId)) {
    cancelWatchdogs.set(
      transferId,
      setTimeout(() => {
        cancelWatchdogs.delete(transferId);
        const current = activeTransfers.get(transferId);
        if (
          current?.status === "running" &&
          cancelRequestedTransfers.has(transferId)
        ) {
          void forceAbortActiveXfer(transferId);
          finalizeTransfer(
            transferId,
            cancelledProgressPatch(current, {
              status: "cancelled",
              phase: current.phase ?? "transferring",
              message: "Transfer cancelled by user",
              method: current.method,
              sourcePaths: current.sourcePaths,
              destPath: current.destPath,
              bytesTransferred: current.bytesTransferred,
              totalBytes: current.totalBytes,
              itemsCompleted: current.itemsCompleted,
              totalItems: current.totalItems,
              moveRequested: current.moveRequested,
              sourceDeleted: false,
            }),
          );
          fileLogger.warn("Force-finalized stuck transfer after cancel", {
            operation: "host_transfer",
            transferId,
          });
        }
      }, 8000),
    );
  }

  return true;
}

async function forceAbortActiveXfer(transferId: string): Promise<void> {
  const control = activeXferControls.get(transferId);
  if (!control) return;
  control.abort(new TransferCancelledError());
  await control.closeResources().catch(() => {});
}
const SMALL_FILE_SYNC_THRESHOLD = 10 * 1024 * 1024;
/** OpenSSH SFTP max packet payload is ~256 KiB; larger chunks cut round-trips. */
const SFTP_XFER_CHUNK_SIZE = 256 * 1024;
/** Pipelined in-flight READ requests per leg (ssh2 fastGet/fastPut default is 64). */
const SFTP_XFER_CONCURRENCY = 32;
/** Files above this size use segmented copy; smaller files use a single scheduler run. */
const SFTP_XFER_SEGMENT_THRESHOLD = 32 * 1024 * 1024;
/** Per-segment attempts before giving up (sequential and parallel). */
const SFTP_SEQUENTIAL_SEGMENT_MAX_ATTEMPTS = 4;
/** Per-lane attempts in parallel mode (each opens a fresh lane SSH pair quickly). */
const SFTP_PARALLEL_SEGMENT_MAX_ATTEMPTS = 4;
/** Full copy restarts after segment exhaustion. */
const SFTP_SEQUENTIAL_COPY_MAX_ATTEMPTS = 2;
const SFTP_PARALLEL_COPY_MAX_ATTEMPTS = 2;
/** Short backoff before opening fresh dedicated SSH sessions. */
const TRANSFER_SESSION_RESET_DELAYS_MS = [1000, 2000, 3000];
const TRANSFER_HANDLE_CLOSE_TIMEOUT_MS = 2500;
const HUNG_TRANSFER_MS = 90_000;
const HUNG_RECONNECTING_MS = 180_000;

interface TransferReconnectContext {
  deps: HostTransferDeps;
  userId: string;
  browseSourceSessionId: string;
  browseDestSessionId: string;
  dedicatedSourceSessionId: string;
  dedicatedDestSessionId: string;
  transferId: string;
  profileKey?: string;
}

type TransferReconnectMeta = Omit<
  TransferReconnectContext,
  "deps" | "transferId"
>;

function buildTransferReconnectContext(
  deps: HostTransferDeps,
  transferId: string,
  meta: TransferReconnectMeta,
): TransferReconnectContext {
  return { deps, transferId, ...meta };
}

async function probeDestResumeOffset(
  destSftp: SFTPWrapper,
  destPath: string,
  fileSize: number,
): Promise<number> {
  try {
    const destStat = await promisifySftpStat(destSftp, destPath);
    return Math.min(destStat.size, fileSize);
  } catch {
    return 0;
  }
}

function buildStreamTransferTimings(
  transferId: string,
  fileSize: number,
  prepareDestMs?: number,
): TransferTimings {
  const progress = activeTransfers.get(transferId);
  const wallStart = progress?.startedAt ?? Date.now();
  const totalMs = elapsedMs(wallStart);
  const prepare = prepareDestMs ?? progress?.timings?.prepareDestMs ?? 0;
  const verify = progress?.timings?.verifyMs ?? 0;
  const dataMs = Math.max(1, totalMs - prepare - verify);

  return {
    ...progress?.timings,
    prepareDestMs: prepare > 0 ? prepare : undefined,
    transferMs: dataMs,
    transferBytes: fileSize,
    endToEndMbPerSec: computeTransferMbPerSec(fileSize, dataMs),
    totalMs,
  };
}

async function finalizeStreamTransferIfDestAtSize(
  transferId: string,
  destSftp: SFTPWrapper,
  destPath: string,
  expectedSize: number,
  extra: Partial<TransferProgress> = {},
  verify?: () => Promise<void>,
): Promise<boolean> {
  try {
    const destSize = await probeDestResumeOffset(
      destSftp,
      destPath,
      expectedSize,
    );
    if (destSize < expectedSize) {
      return false;
    }

    await verify?.();

    fileLogger.info("Destination file complete — finalizing transfer", {
      operation: "host_transfer_dest_complete",
      transferId,
      destSize,
      expectedSize,
    });

    finalizeTransfer(transferId, {
      status: "success",
      phase: "transferring",
      method: "stream",
      bytesTransferred: expectedSize,
      totalBytes: expectedSize,
      destPath,
      timings: buildStreamTransferTimings(transferId, expectedSize),
      ...extra,
    });
    return true;
  } catch {
    return false;
  }
}

async function tryFinalizeStreamTransferIfDestComplete(
  deps: HostTransferDeps,
  transferId: string,
  destSession: SSHSessionLike,
  destPath: string,
  expectedSize: number,
  extra: Partial<TransferProgress> = {},
  verify?: () => Promise<void>,
): Promise<boolean> {
  try {
    const destSftp = await deps.getSessionSftp(destSession);
    return finalizeStreamTransferIfDestAtSize(
      transferId,
      destSftp,
      destPath,
      expectedSize,
      extra,
      verify,
    );
  } catch {
    return false;
  }
}

async function reconnectDedicatedTransferSessions(
  ctx: TransferReconnectContext,
  parallelWorkers = 0,
): Promise<{ sourceSession: SSHSessionLike; destSession: SSHSessionLike }> {
  fileLogger.warn("Reconnecting dedicated transfer SSH sessions", {
    operation: "transfer_ssh_reconnect",
    transferId: ctx.transferId,
    parallelWorkers,
  });

  closeAllTransferSessions(ctx.deps, ctx, parallelWorkers);

  const [sourceSession, destSession] = await Promise.all([
    ctx.deps.openDedicatedTransferSession(
      ctx.browseSourceSessionId,
      ctx.dedicatedSourceSessionId,
      ctx.userId,
      ctx.transferId,
      { allowBrowseDisconnected: true },
    ),
    ctx.deps.openDedicatedTransferSession(
      ctx.browseDestSessionId,
      ctx.dedicatedDestSessionId,
      ctx.userId,
      ctx.transferId,
      { allowBrowseDisconnected: true },
    ),
  ]);

  return { sourceSession, destSession };
}

async function resetDedicatedTransferSessions(
  ctx: TransferReconnectContext,
  attempt: number,
  reason: string,
): Promise<{
  sourceSession: SSHSessionLike;
  destSession: SSHSessionLike;
  sourceSftp: SFTPWrapper;
  destSftp: SFTPWrapper;
}> {
  fileLogger.warn("Resetting transfer SSH sessions (fresh connection)", {
    operation: "transfer_session_reset",
    transferId: ctx.transferId,
    attempt,
    reason,
  });

  closeAllTransferSessions(ctx.deps, ctx, 0);

  const delayMs =
    TRANSFER_SESSION_RESET_DELAYS_MS[
      Math.min(attempt - 1, TRANSFER_SESSION_RESET_DELAYS_MS.length - 1)
    ] ?? 3000;
  await new Promise((resolve) => setTimeout(resolve, delayMs));

  const { sourceSession, destSession } =
    await reconnectDedicatedTransferSessions(ctx, 0);
  const sourceSftp = await ctx.deps.getSessionSftp(sourceSession);
  const destSftp = await ctx.deps.getSessionSftp(destSession);

  if (ctx.transferId) {
    updateTransfer(ctx.transferId, { lastActivityAt: Date.now() });
  }

  return { sourceSession, destSession, sourceSftp, destSftp };
}

async function detectTransferPlatform(
  deps: HostTransferDeps,
  session: SSHSessionLike,
  pathHints: string[] = [],
): Promise<TransferPlatform> {
  if (session.transferPlatform) return session.transferPlatform;

  for (const path of pathHints) {
    const inferred = inferPlatformFromPath(path);
    if (inferred === "windows") {
      session.transferPlatform = "windows";
      return "windows";
    }
  }

  try {
    const { code } = await execCommand(deps, session, "uname -s");
    if (code === 0) {
      session.transferPlatform = "unix";
      return "unix";
    }
  } catch {
    /* not unix */
  }

  try {
    const { code } = await execCommand(
      deps,
      session,
      'cmd /c "if defined OS (exit 0) else (exit 1)"',
    );
    if (code === 0) {
      session.transferPlatform = "windows";
      return "windows";
    }
  } catch {
    /* not cmd */
  }

  try {
    const { code } = await execCommand(
      deps,
      session,
      "powershell -NoProfile -Command \"if ($IsWindows -or $env:OS -like 'Windows*') { exit 0 } else { exit 1 }\"",
    );
    if (code === 0) {
      session.transferPlatform = "windows";
      return "windows";
    }
  } catch {
    /* not powershell */
  }

  session.transferPlatform = "unix";
  return "unix";
}

function execCommand(
  deps: HostTransferDeps,
  session: SSHSessionLike,
  command: string,
  options: {
    shouldAbort?: () => boolean;
    onOutput?: (chunk: Buffer) => void;
    timeoutMs?: number;
  } = {},
): Promise<{ code: number; stderr: string }> {
  return new Promise((resolve, reject) => {
    deps.execChannel(session, command, (err, stream) => {
      if (err) {
        reject(err);
        return;
      }
      let settled = false;
      const startedAt = Date.now();
      let stderr = "";
      const abortTimer =
        options.shouldAbort || options.timeoutMs
          ? setInterval(() => {
              const timedOut =
                options.timeoutMs !== undefined &&
                Date.now() - startedAt >= options.timeoutMs;
              if ((!options.shouldAbort?.() && !timedOut) || settled) return;
              settled = true;
              clearInterval(abortTimer);
              stream.signal("KILL");
              stream.close();
              reject(
                timedOut
                  ? new Error(`Command timed out after ${options.timeoutMs}ms`)
                  : new TransferCancelledError(),
              );
            }, 250)
          : undefined;
      stream.on("data", (data: Buffer) => {
        options.onOutput?.(data);
      });
      stream.stderr.on("data", (data: Buffer) => {
        stderr += data.toString();
        options.onOutput?.(data);
      });
      stream.on("close", (code: number) => {
        if (settled) return;
        settled = true;
        if (abortTimer) clearInterval(abortTimer);
        resolve({ code: code ?? 0, stderr });
      });
      stream.on("error", (streamErr: Error) => {
        if (settled) return;
        settled = true;
        if (abortTimer) clearInterval(abortTimer);
        reject(streamErr);
      });
    });
  });
}

async function checkTarAvailable(
  deps: HostTransferDeps,
  session: SSHSessionLike,
): Promise<boolean> {
  const platform = await detectTransferPlatform(deps, session);
  if (platform === "windows") return false;

  try {
    const { code } = await execCommand(deps, session, "command -v tar");
    return code === 0;
  } catch {
    return false;
  }
}

async function ensureDestDirectory(
  deps: HostTransferDeps,
  destSession: SSHSessionLike,
  dirPath: string,
  created: Set<string> = new Set(),
): Promise<void> {
  const destSftp = await deps.getSessionSftp(destSession);
  await ensureDirectoryTreeSftp(destSftp, dirPath, created);
}

function updateTransfer(
  transferId: string,
  patch: Partial<TransferProgress>,
): void {
  const current = activeTransfers.get(transferId);
  if (current) {
    const next: TransferProgress = { ...current, ...patch };
    if (
      patch.bytesTransferred !== undefined &&
      current.totalBytes !== undefined &&
      current.totalBytes > 0
    ) {
      next.bytesTransferred = Math.min(
        patch.bytesTransferred,
        current.totalBytes,
      );
    }
    if (
      patch.bytesTransferred !== undefined &&
      patch.bytesTransferred !== current.bytesTransferred
    ) {
      next.lastActivityAt = Date.now();
    }
    activeTransfers.set(transferId, next);
  }
}

async function closeTransferHandlesSafe(
  handles: TransferFileHandles | null | undefined,
): Promise<void> {
  if (!handles) return;
  await Promise.race([
    handles.close(),
    new Promise<void>((resolve) =>
      setTimeout(resolve, TRANSFER_HANDLE_CLOSE_TIMEOUT_MS),
    ),
  ]).catch(() => {});
}

function checkHungTransfers(): void {
  const now = Date.now();
  for (const [transferId, progress] of activeTransfers) {
    if (progress.status !== "running") continue;

    if (
      progress.method === "stream" &&
      progress.totalBytes &&
      progress.totalBytes > 0 &&
      progress.bytesTransferred !== undefined &&
      progress.bytesTransferred >= progress.totalBytes
    ) {
      fileLogger.info("Transfer progress at 100% — marking complete", {
        operation: "host_transfer_progress_complete",
        transferId,
        bytesTransferred: progress.bytesTransferred,
        totalBytes: progress.totalBytes,
      });
      finalizeTransfer(transferId, {
        status: "success",
        phase: "transferring",
        method: "stream",
        bytesTransferred: progress.totalBytes,
        totalBytes: progress.totalBytes,
        sourcePaths: progress.sourcePaths,
        destPath: progress.destPath,
        moveRequested: progress.moveRequested,
        timings: buildStreamTransferTimings(transferId, progress.totalBytes),
      });
      continue;
    }

    if (progress.phase === "reconnecting") {
      const reconnectStarted =
        progress.reconnectingAt ?? progress.lastActivityAt ?? now;
      if (now - reconnectStarted < HUNG_RECONNECTING_MS) continue;
    }

    const lastActivity = progress.lastActivityAt ?? progress.startedAt ?? now;
    if (now - lastActivity < HUNG_TRANSFER_MS) continue;

    fileLogger.error("Force-finalizing unresponsive transfer", {
      operation: "host_transfer_hung",
      transferId,
      lastActivityAt: lastActivity,
      bytesTransferred: progress.bytesTransferred,
    });

    finalizeTransfer(
      transferId,
      failedProgressPatch(progress, {
        status: "error",
        phase:
          progress.phase === "reconnecting" ? "transferring" : progress.phase,
        message: "Transfer stopped responding",
        method: progress.method,
        sourcePaths: progress.sourcePaths,
        destPath: progress.destPath,
        bytesTransferred: Math.min(
          progress.bytesTransferred ?? 0,
          progress.totalBytes ?? Number.MAX_SAFE_INTEGER,
        ),
        totalBytes: progress.totalBytes,
        itemsCompleted: progress.itemsCompleted,
        totalItems: progress.totalItems,
        moveRequested: progress.moveRequested,
      }),
    );
  }
}

/** Before marking a stalled stream transfer as failed, verify the destination file size. */
export async function probeHungStreamTransfers(
  deps: HostTransferDeps,
): Promise<void> {
  const now = Date.now();
  for (const [transferId, progress] of activeTransfers) {
    if (progress.status !== "running" || progress.method !== "stream") {
      continue;
    }
    if (!progress.destPath || !progress.totalBytes || !progress.userId) {
      continue;
    }

    const lastActivity = progress.lastActivityAt ?? progress.startedAt ?? now;
    if (now - lastActivity < HUNG_TRANSFER_MS) {
      continue;
    }

    const browseDestId = progress.destSessionId;
    if (!browseDestId) {
      continue;
    }

    const destId = progress.dedicatedDestSessionId ?? `xfer:${transferId}:dst`;
    let destSession = deps.sshSessions[destId];
    if (!destSession?.isConnected) {
      try {
        destSession = await deps.openDedicatedTransferSession(
          browseDestId,
          destId,
          progress.userId,
          transferId,
          { allowBrowseDisconnected: true },
        );
      } catch {
        continue;
      }
    }

    await tryFinalizeStreamTransferIfDestComplete(
      deps,
      transferId,
      destSession,
      progress.destPath,
      progress.totalBytes,
      {
        sourcePaths: progress.sourcePaths,
        moveRequested: progress.moveRequested,
      },
    );
  }
}

function trackDestArtifact(transferId: string, path: string): void {
  const normalized = normalizeSftpPath(path);
  const current = activeTransfers.get(transferId);
  if (!current) return;
  const existing = current.destArtifacts ?? [];
  if (existing.includes(normalized)) return;
  updateTransfer(transferId, { destArtifacts: [...existing, normalized] });
}

function buildCleanupPaths(progress: TransferProgress): string[] {
  const paths = new Set<string>(progress.destArtifacts ?? []);

  if (progress.tempArchivePath) {
    paths.add(normalizeSftpPath(progress.tempArchivePath));
  }

  if (paths.size === 0 && progress.destPath) {
    if (progress.method === "stream") {
      paths.add(normalizeSftpPath(progress.destPath));
    } else if (progress.sourcePaths?.length) {
      for (const sourcePath of progress.sourcePaths) {
        paths.add(
          normalizeSftpPath(joinPath(progress.destPath, basename(sourcePath))),
        );
      }
    }
  }

  return [...paths];
}

function partialDestWasWritten(progress: TransferProgress): boolean {
  return (
    (progress.bytesTransferred ?? 0) > 0 ||
    (progress.itemsCompleted ?? 0) > 0 ||
    (progress.destArtifacts?.length ?? 0) > 0
  );
}

function failedProgressPatch(
  current: TransferProgress | undefined,
  patch: Partial<TransferProgress>,
): Partial<TransferProgress> {
  const merged = { ...current, ...patch } as TransferProgress;
  const hasPartial = partialDestWasWritten(merged);
  return {
    ...patch,
    partialDestRemaining: hasPartial,
    retryable: hasPartial && !!current?.requestSnapshot,
  };
}

function cancelledProgressPatch(
  current: TransferProgress | undefined,
  patch: Partial<TransferProgress>,
): Partial<TransferProgress> {
  const merged = { ...current, ...patch } as TransferProgress;
  return {
    ...patch,
    partialDestRemaining: partialDestWasWritten(merged),
  };
}

function finalizeTransfer(
  transferId: string,
  patch: Partial<TransferProgress>,
): TransferProgress {
  cancelRequestedTransfers.delete(transferId);
  const watchdog = cancelWatchdogs.get(transferId);
  if (watchdog) {
    clearTimeout(watchdog);
    cancelWatchdogs.delete(transferId);
  }
  const current = activeTransfers.get(transferId);
  const result: TransferProgress = {
    transferId,
    status: "success",
    phase: "transferring",
    ...current,
    ...patch,
  };
  activeTransfers.set(transferId, result);
  return result;
}

async function verifyTransferredFile(
  deps: HostTransferDeps,
  transferId: string,
  reconnectMeta: TransferReconnectMeta,
  sourcePath: string,
  destPath: string,
): Promise<void> {
  updateTransfer(transferId, { phase: "verifying" });
  const verifyStart = Date.now();
  const [sourceSession, destSession] = await Promise.all([
    deps.openDedicatedTransferSession(
      reconnectMeta.browseSourceSessionId,
      reconnectMeta.dedicatedSourceSessionId,
      reconnectMeta.userId,
      transferId,
      { allowBrowseDisconnected: true },
    ),
    deps.openDedicatedTransferSession(
      reconnectMeta.browseDestSessionId,
      reconnectMeta.dedicatedDestSessionId,
      reconnectMeta.userId,
      transferId,
      { allowBrowseDisconnected: true },
    ),
  ]);
  const [sourceSftp, destSftp] = await Promise.all([
    deps.getSessionSftp(sourceSession),
    deps.getSessionSftp(destSession),
  ]);
  await verifySftpFileIntegrity(
    sourceSftp,
    destSftp,
    sourcePath,
    destPath,
    createTransferShouldAbort(transferId),
    () => new TransferCancelledError(),
  );
  const current = activeTransfers.get(transferId);
  updateTransfer(transferId, {
    integrityVerified: true,
    timings: {
      ...current?.timings,
      verifyMs: (current?.timings?.verifyMs ?? 0) + elapsedMs(verifyStart),
    },
  });
}

async function deleteSourcePathsAfterSuccess(
  deps: HostTransferDeps,
  transferId: string,
  sourceSession: SSHSessionLike,
  sourcePaths: string[],
): Promise<number> {
  const deleteStart = Date.now();
  await deleteSourcePaths(deps, sourceSession, sourcePaths);
  const sourceDeleteMs = elapsedMs(deleteStart);
  updateTransfer(transferId, {
    sourceDeleted: true,
    timings: {
      ...activeTransfers.get(transferId)?.timings,
      sourceDeleteMs,
    },
  });
  return sourceDeleteMs;
}

async function ensureDestParentForFile(
  deps: HostTransferDeps,
  destSession: SSHSessionLike,
  filePath: string,
): Promise<void> {
  const parent = dirname(filePath);
  if (!parent || isRootOnlyPath(parent)) return;
  await ensureDestDirectory(deps, destSession, parent);
}

async function scanSourcePathsForRouting(
  sftp: SFTPWrapper,
  sourcePaths: string[],
  transferId: string,
) {
  const scanItems: Array<{ sourcePath: string; size: number }> = [];
  for (const sourcePath of sourcePaths) {
    throwIfCancelled(transferId);
    const work = await collectFileWorkItems(sftp, sourcePath, "/");
    scanItems.push(
      ...work.map((w) => ({ sourcePath: w.sourcePath, size: w.size })),
    );
  }
  const summary = buildTransferScanSummary(scanItems);
  const candidates = [...scanItems]
    .filter((item) => item.size > 0)
    .sort((a, b) => b.size - a.size)
    .slice(0, 3);
  let sampledBytes = 0;
  let sampledIncompressibleBytes = 0;
  for (const item of candidates) {
    throwIfCancelled(transferId);
    try {
      const sample = await readSftpSample(sftp, item.sourcePath, item.size);
      sampledBytes += sample.length;
      if (estimateIncompressibleSample(sample)) {
        sampledIncompressibleBytes += sample.length;
      }
    } catch {
      /* Extension-based routing remains the safe fallback. */
    }
  }
  if (sampledBytes > 0) {
    summary.sampledIncompressibleRatio =
      sampledIncompressibleBytes / sampledBytes;
  }
  return summary;
}

interface PipelinedXferOptions {
  fileSize?: number;
  initialOffset?: number;
  parallelSegmentCount?: number;
  pipelineConcurrency?: number;
  onProgress?: (bytes: number) => void;
  shouldAbort?: () => boolean;
  transferId?: string;
  segmentIndex?: number;
  reconnect?: TransferReconnectContext;
  onResumeOffset?: (offset: number) => void;
}

function closeAllTransferSessions(
  deps: HostTransferDeps,
  ctx: TransferReconnectContext,
  parallelWorkers: number,
): void {
  deps.closeDedicatedTransferSession(ctx.dedicatedSourceSessionId);
  deps.closeDedicatedTransferSession(ctx.dedicatedDestSessionId);
  for (let i = 0; i < parallelWorkers; i++) {
    deps.closeDedicatedTransferSession(`${ctx.dedicatedSourceSessionId}:p${i}`);
    deps.closeDedicatedTransferSession(`${ctx.dedicatedDestSessionId}:p${i}`);
  }
}

interface TransferFileHandles {
  sourceSftp: SFTPWrapper;
  destSftp: SFTPWrapper;
  srcHandle: Buffer;
  dstHandle: Buffer;
  close: () => Promise<void>;
}

async function openTransferFileHandles(
  sourceSftp: SFTPWrapper,
  destSftp: SFTPWrapper,
  sourcePath: string,
  destPath: string,
  resume: boolean,
): Promise<TransferFileHandles> {
  const srcHandle = await promisifySftpOpen(
    sourceSftp,
    sourcePath,
    SFTP_OPEN_READ,
    0o666,
  );
  const dstHandle = await promisifySftpOpen(
    destSftp,
    destPath,
    resume ? SFTP_OPEN_WRITE_RESUME : SFTP_OPEN_WRITE,
    0o666,
  );

  return {
    sourceSftp,
    destSftp,
    srcHandle,
    dstHandle,
    close: async () => {
      await promisifySftpClose(sourceSftp, srcHandle).catch(() => {});
      await promisifySftpClose(destSftp, dstHandle).catch(() => {});
    },
  };
}

/**
 * Parallel SFTP copy using the same scheduling model as ssh2's fastXfer.
 * Scoped to [fileBaseOffset, fileBaseOffset + byteLength) so callers can reset
 * scheduler state between segments on large files.
 */
async function runFastSftpCopy(
  sourceSftp: SFTPWrapper,
  srcHandle: Buffer,
  destSftp: SFTPWrapper,
  dstHandle: Buffer,
  byteLength: number,
  fileBaseOffset: number,
  options: PipelinedXferOptions,
  sourceReadClock: ReturnType<typeof createHopWallClock>,
  destWriteClock: ReturnType<typeof createHopWallClock>,
): Promise<void> {
  let concurrency = options.pipelineConcurrency ?? SFTP_XFER_CONCURRENCY;
  let chunkSize = SFTP_XFER_CHUNK_SIZE;
  let bufsize = chunkSize * concurrency;
  while (bufsize > byteLength && concurrency > 1) {
    bufsize -= chunkSize;
    concurrency -= 1;
  }
  if (byteLength <= chunkSize) {
    chunkSize = byteLength;
    concurrency = 1;
    bufsize = byteLength;
  }

  const readbuf = Buffer.alloc(bufsize);
  const progress = createThrottledProgress(options.onProgress);
  let lastActivity = Date.now();
  let stallTimer: ReturnType<typeof setInterval> | undefined;

  await new Promise<void>((resolve, reject) => {
    let finished = false;
    let hadError = false;
    let pdst = 0;
    let total = 0;

    const fail = (err: Error) => {
      if (hadError) return;
      hadError = true;
      finished = true;
      progress.flush();
      reject(err);
    };

    const succeed = () => {
      if (finished) return;
      finished = true;
      progress.flush();
      resolve();
    };

    stallTimer = setInterval(() => {
      if (finished) return;
      if (options.shouldAbort?.()) {
        fail(new TransferCancelledError());
        return;
      }
      if (Date.now() - lastActivity > 45000) {
        fail(
          new TransferStalledError(
            fileBaseOffset + total,
            options.segmentIndex,
          ),
        );
      }
    }, 10000);

    const onread = (
      err: Error | undefined,
      nb: number,
      _data: Buffer | undefined,
      localDstPos: number,
      datapos: number,
      origChunkLen: number,
    ) => {
      if (err) {
        fail(err);
        return;
      }
      if (options.shouldAbort?.()) {
        fail(new TransferCancelledError());
        return;
      }

      noteHopStart(destWriteClock);
      destSftp.write(
        dstHandle,
        readbuf,
        datapos,
        nb,
        fileBaseOffset + localDstPos,
        (writeErr: Error | undefined) => {
          noteHopEnd(destWriteClock);
          if (writeErr) {
            fail(writeErr);
            return;
          }

          total += nb;
          progress.add(nb);
          lastActivity = Date.now();

          if (options.shouldAbort?.()) {
            fail(new TransferCancelledError());
            return;
          }

          if (nb < origChunkLen) {
            singleRead(datapos, localDstPos + nb, origChunkLen - nb);
            return;
          }

          if (total >= byteLength) {
            succeed();
            return;
          }

          if (pdst >= byteLength) {
            return;
          }

          const chunk = Math.min(chunkSize, byteLength - pdst);
          singleRead(datapos, pdst, chunk);
          pdst += chunk;
        },
      );
    };

    const makeCb =
      (psrc: number, localFilePos: number, chunk: number) =>
      (err: Error | undefined, nb?: number, data?: Buffer) => {
        onread(err, nb ?? 0, data, localFilePos, psrc, chunk);
      };

    const singleRead = (psrc: number, localFilePos: number, chunk: number) => {
      if (options.shouldAbort?.()) {
        fail(new TransferCancelledError());
        return;
      }
      noteHopStart(sourceReadClock);
      sourceSftp.read(
        srcHandle,
        readbuf,
        psrc,
        chunk,
        fileBaseOffset + localFilePos,
        (err, nb, data) => {
          noteHopEnd(sourceReadClock);
          makeCb(psrc, localFilePos, chunk)(err, nb, data);
        },
      );
    };

    const startReads = () => {
      let reads = 0;
      let psrc = 0;
      while (pdst < byteLength && reads < concurrency) {
        const chunk = Math.min(chunkSize, byteLength - pdst);
        singleRead(psrc, pdst, chunk);
        psrc += chunk;
        pdst += chunk;
        reads += 1;
      }
    };

    startReads();
  }).finally(() => {
    if (stallTimer) clearInterval(stallTimer);
  });
}

async function runFastSftpCopySegmented(
  handles: TransferFileHandles,
  fileSize: number,
  options: PipelinedXferOptions,
  sourceReadClock: ReturnType<typeof createHopWallClock>,
  destWriteClock: ReturnType<typeof createHopWallClock>,
  sourcePath: string,
  destPath: string,
): Promise<TransferFileHandles> {
  const parallel = clampParallelSegmentCount(options.parallelSegmentCount);
  if (parallel > 1 && options.reconnect) {
    return runFastSftpCopySegmentedParallel(
      handles,
      fileSize,
      { ...options, parallelSegmentCount: parallel },
      sourceReadClock,
      destWriteClock,
      sourcePath,
      destPath,
    );
  }
  return runFastSftpCopySegmentedSequential(
    handles,
    fileSize,
    options,
    sourceReadClock,
    destWriteClock,
    sourcePath,
    destPath,
  );
}

async function runFastSftpCopySegmentedSequential(
  handles: TransferFileHandles,
  fileSize: number,
  options: PipelinedXferOptions,
  sourceReadClock: ReturnType<typeof createHopWallClock>,
  destWriteClock: ReturnType<typeof createHopWallClock>,
  sourcePath: string,
  destPath: string,
): Promise<TransferFileHandles> {
  const transferId = options.transferId;
  const segmentCount = Math.ceil(fileSize / SFTP_XFER_SEGMENT_SIZE);
  let offset = options.initialOffset ?? 0;
  let currentHandles = handles;

  while (offset < fileSize) {
    if (options.shouldAbort?.()) {
      throw new TransferCancelledError();
    }

    let segLen = Math.min(SFTP_XFER_SEGMENT_SIZE, fileSize - offset);
    const segmentIndex = Math.floor(offset / SFTP_XFER_SEGMENT_SIZE);
    let attempts = 0;

    while (true) {
      fileLogger.info("Transfer segment started", {
        operation: "host_transfer_segment",
        transferId,
        segmentIndex,
        segmentCount,
        fileBaseOffset: offset,
        byteLength: segLen,
        attempt: attempts + 1,
      });

      try {
        await runFastSftpCopy(
          currentHandles.sourceSftp,
          currentHandles.srcHandle,
          currentHandles.destSftp,
          currentHandles.dstHandle,
          segLen,
          offset,
          { ...options, segmentIndex },
          sourceReadClock,
          destWriteClock,
        );

        fileLogger.info("Transfer segment completed", {
          operation: "host_transfer_segment",
          transferId,
          segmentIndex,
          segmentCount,
          fileBaseOffset: offset,
          byteLength: segLen,
        });

        offset += segLen;
        break;
      } catch (err) {
        if (err instanceof TransferCancelledError) {
          throw err;
        }

        const message = getErrorMessage(err, "Segment transfer failed");
        const recoverable =
          options.reconnect &&
          isRecoverableTransferError(err) &&
          attempts < SFTP_SEQUENTIAL_SEGMENT_MAX_ATTEMPTS;

        fileLogger.error("Transfer segment failed", err, {
          operation: "host_transfer_segment",
          transferId,
          segmentIndex,
          fileBaseOffset: offset,
          byteLength: segLen,
          attempt: attempts + 1,
          maxAttempts: SFTP_SEQUENTIAL_SEGMENT_MAX_ATTEMPTS,
          recoverable,
        });

        if (!recoverable || !options.reconnect) {
          throw new Error(
            `Segment ${segmentIndex} failed at offset ${offset}: ${message}`,
          );
        }

        attempts += 1;
        await closeTransferHandlesSafe(currentHandles);

        const { sourceSftp, destSftp } = await resetDedicatedTransferSessions(
          options.reconnect,
          attempts,
          message,
        );

        let resumeOffset = offset;
        try {
          resumeOffset = await probeDestResumeOffset(
            destSftp,
            destPath,
            fileSize,
          );
        } catch {
          /* use last known offset */
        }

        if (resumeOffset > offset) {
          fileLogger.info("Resuming transfer from destination size", {
            operation: "host_transfer_resume",
            transferId,
            previousOffset: offset,
            resumeOffset,
            fileSize,
          });
          offset = resumeOffset;
          options.onResumeOffset?.(offset);
        }

        if (offset >= fileSize) {
          break;
        }

        segLen = Math.min(SFTP_XFER_SEGMENT_SIZE, fileSize - offset);
        currentHandles = await openTransferFileHandles(
          sourceSftp,
          destSftp,
          sourcePath,
          destPath,
          offset > 0,
        );
      }
    }
  }

  return currentHandles;
}

interface WorkerSessionCache {
  sourceSession: SSHSessionLike;
  destSession: SSHSessionLike;
  sourceSftp: SFTPWrapper;
  destSftp: SFTPWrapper;
}

async function runFastSftpCopySegmentedParallel(
  handles: TransferFileHandles,
  fileSize: number,
  options: PipelinedXferOptions,
  sourceReadClock: ReturnType<typeof createHopWallClock>,
  destWriteClock: ReturnType<typeof createHopWallClock>,
  sourcePath: string,
  destPath: string,
): Promise<TransferFileHandles> {
  const transferId = options.transferId;
  const parallel = clampParallelSegmentCount(options.parallelSegmentCount);
  const initialOffset = options.initialOffset ?? 0;
  const reconnect = options.reconnect!;

  let destResumeSize = initialOffset;
  try {
    destResumeSize = await probeDestResumeOffset(
      handles.destSftp,
      destPath,
      fileSize,
    );
  } catch {
    /* use initial offset */
  }

  const jobs = buildSegmentCopyJobs(fileSize, initialOffset, destResumeSize);
  if (jobs.length === 0) {
    options.onResumeOffset?.(fileSize);
    return handles;
  }

  fileLogger.info("Starting parallel segment transfer", {
    operation: "host_transfer_parallel",
    transferId,
    parallel,
    segmentJobs: jobs.length,
    fileSize,
    destResumeSize,
  });

  updateTransfer(transferId ?? "", {
    parallelSegmentCount: parallel,
    bytesTransferred: destResumeSize,
  });
  options.onResumeOffset?.(destResumeSize);

  let aggregateBytes = destResumeSize;
  let lastDestProbeAt = 0;
  const DEST_PROGRESS_PROBE_MS = 1500;

  const refreshDestProgress = async (force = false): Promise<number> => {
    const now = Date.now();
    if (!force && now - lastDestProbeAt < DEST_PROGRESS_PROBE_MS) {
      return aggregateBytes;
    }
    lastDestProbeAt = now;
    try {
      const size = await probeDestResumeOffset(
        handles.destSftp,
        destPath,
        fileSize,
      );
      if (size > aggregateBytes) {
        aggregateBytes = size;
      } else if (force) {
        aggregateBytes = size;
      }
      options.onResumeOffset?.(aggregateBytes);
      if (transferId) {
        updateTransfer(transferId, { bytesTransferred: aggregateBytes });
      }
    } catch {
      /* keep last known progress */
    }
    return aggregateBytes;
  };

  /** Parallel lanes share one dest file — use dest size, not summed segment deltas. */
  const reportDelta = (_delta: number) => {
    void refreshDestProgress(false);
  };

  let nextJobIndex = 0;
  const workerCaches = new Map<number, WorkerSessionCache>();

  const resetParallelLane = async (
    workerId: number,
    attempt: number,
    reason: string,
  ): Promise<void> => {
    fileLogger.warn("Resetting parallel transfer lane (fresh SSH session)", {
      operation: "transfer_lane_reset",
      transferId: reconnect.transferId,
      parallelLane: workerId,
      attempt,
      reason,
    });
    workerCaches.delete(workerId);
    reconnect.deps.closeDedicatedTransferSession(
      `${reconnect.dedicatedSourceSessionId}:p${workerId}`,
    );
    reconnect.deps.closeDedicatedTransferSession(
      `${reconnect.dedicatedDestSessionId}:p${workerId}`,
    );
    const delayMs =
      TRANSFER_SESSION_RESET_DELAYS_MS[
        Math.min(attempt - 1, TRANSFER_SESSION_RESET_DELAYS_MS.length - 1)
      ] ?? 3000;
    await new Promise((resolve) => setTimeout(resolve, delayMs));
  };

  const ensureWorkerSessions = async (
    workerId: number,
  ): Promise<WorkerSessionCache> => {
    const cached = workerCaches.get(workerId);
    if (cached) return cached;

    const srcId = `${reconnect.dedicatedSourceSessionId}:p${workerId}`;
    const dstId = `${reconnect.dedicatedDestSessionId}:p${workerId}`;
    const sourceSession = await reconnect.deps.openDedicatedTransferSession(
      reconnect.browseSourceSessionId,
      srcId,
      reconnect.userId,
      reconnect.transferId,
      { allowBrowseDisconnected: true },
    );
    const destSession = await reconnect.deps.openDedicatedTransferSession(
      reconnect.browseDestSessionId,
      dstId,
      reconnect.userId,
      reconnect.transferId,
      { allowBrowseDisconnected: true },
    );
    const sourceSftp = await reconnect.deps.getSessionSftp(sourceSession);
    const destSftp = await reconnect.deps.getSessionSftp(destSession);
    const entry: WorkerSessionCache = {
      sourceSession,
      destSession,
      sourceSftp,
      destSftp,
    };
    workerCaches.set(workerId, entry);
    return entry;
  };

  const runSegmentJob = async (
    job: SegmentCopyJob,
    workerId: number,
  ): Promise<void> => {
    let attempts = 0;

    while (true) {
      if (options.shouldAbort?.()) {
        throw new TransferCancelledError();
      }

      fileLogger.info("Transfer segment started", {
        operation: "host_transfer_segment",
        transferId,
        segmentIndex: job.segmentIndex,
        fileBaseOffset: job.offset,
        byteLength: job.length,
        attempt: attempts + 1,
        parallelLane: workerId,
      });

      const { sourceSftp, destSftp } = await ensureWorkerSessions(workerId);
      const laneHandles = await openTransferFileHandles(
        sourceSftp,
        destSftp,
        sourcePath,
        destPath,
        job.offset > 0,
      );

      try {
        await runFastSftpCopy(
          laneHandles.sourceSftp,
          laneHandles.srcHandle,
          laneHandles.destSftp,
          laneHandles.dstHandle,
          job.length,
          job.offset,
          {
            ...options,
            segmentIndex: job.segmentIndex,
            onProgress: reportDelta,
          },
          sourceReadClock,
          destWriteClock,
        );

        fileLogger.info("Transfer segment completed", {
          operation: "host_transfer_segment",
          transferId,
          segmentIndex: job.segmentIndex,
          fileBaseOffset: job.offset,
          byteLength: job.length,
          parallelLane: workerId,
        });

        await closeTransferHandlesSafe(laneHandles);
        await refreshDestProgress(true);
        return;
      } catch (err) {
        await closeTransferHandlesSafe(laneHandles);

        if (err instanceof TransferCancelledError) {
          throw err;
        }

        const message = getErrorMessage(err, "Segment transfer failed");
        const recoverable =
          isRecoverableTransferError(err) &&
          attempts < SFTP_PARALLEL_SEGMENT_MAX_ATTEMPTS;

        fileLogger.error("Transfer segment failed", err, {
          operation: "host_transfer_segment",
          transferId,
          segmentIndex: job.segmentIndex,
          fileBaseOffset: job.offset,
          byteLength: job.length,
          attempt: attempts + 1,
          maxAttempts: SFTP_PARALLEL_SEGMENT_MAX_ATTEMPTS,
          recoverable,
          parallelLane: workerId,
        });

        if (!recoverable) {
          if (
            transferId &&
            (await finalizeStreamTransferIfDestAtSize(
              transferId,
              handles.destSftp,
              destPath,
              fileSize,
            ))
          ) {
            return;
          }
          throw new Error(
            `Segment ${job.segmentIndex} failed at offset ${job.offset}: ${message}`,
          );
        }

        attempts += 1;
        await resetParallelLane(workerId, attempts, message);
        await refreshDestProgress(true);
      }
    }
  };

  const runWorker = async (workerId: number) => {
    while (true) {
      if (options.shouldAbort?.()) {
        throw new TransferCancelledError();
      }

      const jobIndex = nextJobIndex;
      nextJobIndex += 1;
      if (jobIndex >= jobs.length) {
        return;
      }

      await runSegmentJob(jobs[jobIndex], workerId);
    }
  };

  try {
    await Promise.all(
      Array.from({ length: parallel }, (_, workerId) => runWorker(workerId)),
    );
    await refreshDestProgress(true);
  } finally {
    workerCaches.clear();
    for (let i = 0; i < parallel; i++) {
      reconnect.deps.closeDedicatedTransferSession(
        `${reconnect.dedicatedSourceSessionId}:p${i}`,
      );
      reconnect.deps.closeDedicatedTransferSession(
        `${reconnect.dedicatedDestSessionId}:p${i}`,
      );
    }
  }

  options.onResumeOffset?.(fileSize);
  return handles;
}

function promisifyFastGet(
  sftp: SFTPWrapper,
  remotePath: string,
  localPath: string,
  opts: {
    concurrency?: number;
    chunkSize?: number;
    fileSize?: number;
    step?: (totalTransferred: number, chunk: number, total: number) => void;
  },
): Promise<void> {
  return new Promise((resolve, reject) => {
    sftp.fastGet(remotePath, localPath, opts, (err) => {
      if (err) reject(err);
      else resolve();
    });
  });
}

async function pipelinedSftpFile(
  sourceSftp: SFTPWrapper,
  destSftp: SFTPWrapper,
  sourcePath: string,
  destPath: string,
  options: PipelinedXferOptions = {},
): Promise<PipelinedXferStats> {
  let fileSize = options.fileSize ?? 0;
  const stats = createEmptyXferStats();
  stats.destWriteKind = "sftp";

  let handles: TransferFileHandles | null = null;
  const transferId = options.transferId;

  try {
    if (!fileSize) {
      const srcProbe = await promisifySftpOpen(
        sourceSftp,
        sourcePath,
        SFTP_OPEN_READ,
        0o666,
      );
      try {
        const fstats = await promisifySftpFstat(sourceSftp, srcProbe);
        fileSize = fstats.size;
      } finally {
        await promisifySftpClose(sourceSftp, srcProbe).catch(() => {});
      }
    }
    if (fileSize <= 0) return stats;

    stats.bytes = fileSize;

    const sourceReadClock = createHopWallClock();
    const destWriteClock = createHopWallClock();

    const runCopyWithRetry = async (): Promise<void> => {
      let attempts = 0;
      let sftpSource = sourceSftp;
      let sftpDest = destSftp;
      const parallelLanes = clampParallelSegmentCount(
        options.parallelSegmentCount,
      );
      const isParallelCopy = parallelLanes > 1;
      const maxCopyAttempts = isParallelCopy
        ? SFTP_PARALLEL_COPY_MAX_ATTEMPTS
        : SFTP_SEQUENTIAL_COPY_MAX_ATTEMPTS;

      while (true) {
        const resumeOffset = await probeDestResumeOffset(
          sftpDest,
          destPath,
          fileSize,
        );
        if (resumeOffset >= fileSize) {
          options.onResumeOffset?.(resumeOffset);
          return;
        }
        if (resumeOffset > 0) {
          options.onResumeOffset?.(resumeOffset);
          if (attempts === 0) {
            fileLogger.info("Resuming transfer from destination size", {
              operation: "host_transfer_resume",
              transferId,
              resumeOffset,
              fileSize,
            });
          }
        }

        try {
          if (handles) {
            await handles.close().catch(() => {});
          }
          handles = await openTransferFileHandles(
            sftpSource,
            sftpDest,
            sourcePath,
            destPath,
            resumeOffset > 0,
          );

          if (fileSize <= SFTP_XFER_SEGMENT_THRESHOLD) {
            await runFastSftpCopy(
              handles.sourceSftp,
              handles.srcHandle,
              handles.destSftp,
              handles.dstHandle,
              fileSize - resumeOffset,
              resumeOffset,
              options,
              sourceReadClock,
              destWriteClock,
            );
          } else {
            handles = await runFastSftpCopySegmented(
              handles,
              fileSize,
              { ...options, initialOffset: resumeOffset },
              sourceReadClock,
              destWriteClock,
              sourcePath,
              destPath,
            );
          }
          return;
        } catch (err) {
          if (err instanceof TransferCancelledError) {
            throw err;
          }

          const recoverable =
            options.reconnect &&
            isRecoverableTransferError(err) &&
            attempts < maxCopyAttempts;

          fileLogger.error("Transfer copy attempt failed", err, {
            operation: "host_transfer_copy",
            transferId,
            attempt: attempts + 1,
            maxAttempts: maxCopyAttempts,
            recoverable,
            parallelLanes: isParallelCopy ? parallelLanes : undefined,
          });

          if (!recoverable || !options.reconnect) {
            if (
              transferId &&
              (await finalizeStreamTransferIfDestAtSize(
                transferId,
                sftpDest,
                destPath,
                fileSize,
              ))
            ) {
              return;
            }
            throw err;
          }

          attempts += 1;
          await closeTransferHandlesSafe(handles);

          if (isParallelCopy) {
            closeAllTransferSessions(
              options.reconnect.deps,
              options.reconnect,
              parallelLanes,
            );
            const delayMs =
              TRANSFER_SESSION_RESET_DELAYS_MS[
                Math.min(
                  attempts - 1,
                  TRANSFER_SESSION_RESET_DELAYS_MS.length - 1,
                )
              ] ?? 3000;
            fileLogger.warn(
              "Restarting parallel copy after segment exhaustion",
              {
                operation: "host_transfer_parallel_restart",
                transferId,
                attempt: attempts,
                delayMs,
              },
            );
            await new Promise((resolve) => setTimeout(resolve, delayMs));
          } else {
            const reset = await resetDedicatedTransferSessions(
              options.reconnect,
              attempts,
              getErrorMessage(err, "copy failed"),
            );
            sftpSource = reset.sourceSftp;
            sftpDest = reset.destSftp;
          }
        }
      }
    };

    if (transferId) {
      let abortFn: ((err: Error) => void) | null = null;
      const control: ActiveXferControl = {
        abort: (err) => abortFn?.(err),
        closeResources: async () => {
          await closeTransferHandlesSafe(handles);
        },
      };
      activeXferControls.set(transferId, control);

      try {
        await new Promise<void>((resolve, reject) => {
          abortFn = reject;
          runCopyWithRetry().then(resolve).catch(reject);
        });
      } finally {
        activeXferControls.delete(transferId);
      }
    } else {
      await runCopyWithRetry();
    }

    stats.sourceReadSpanMs = hopSpanMs(sourceReadClock);
    stats.destWriteSpanMs = hopSpanMs(destWriteClock);
  } finally {
    if (handles) {
      await handles.close().catch(() => {});
    }
  }

  return stats;
}

/** Source SFTP → local filesystem (skips SFTP write when dest SSH target is this host). */
async function pipelinedSftpToLocalFile(
  sourceSftp: SFTPWrapper,
  sourcePath: string,
  destPath: string,
  options: PipelinedXferOptions = {},
): Promise<PipelinedXferStats> {
  let fileSize = options.fileSize ?? 0;
  const stats = createEmptyXferStats();
  stats.destWriteKind = "local";

  if (!fileSize) {
    const srcHandle = await promisifySftpOpen(
      sourceSftp,
      sourcePath,
      SFTP_OPEN_READ,
      0o666,
    );
    try {
      const fstats = await promisifySftpFstat(sourceSftp, srcHandle);
      fileSize = fstats.size;
    } finally {
      await promisifySftpClose(sourceSftp, srcHandle).catch(() => {});
    }
  }
  if (fileSize <= 0) return stats;

  stats.bytes = fileSize;
  const localPath = sftpPathToLocalPath(destPath);
  const progress = createThrottledProgress(options.onProgress);
  const transferStart = Date.now();

  await promisifyFastGet(sourceSftp, sourcePath, localPath, {
    concurrency: options.pipelineConcurrency ?? SFTP_XFER_CONCURRENCY,
    chunkSize: SFTP_XFER_CHUNK_SIZE,
    fileSize,
    step: (_total, chunk) => {
      if (options.shouldAbort?.()) {
        throw new TransferCancelledError();
      }
      progress.add(chunk);
    },
  });

  progress.flush();
  stats.sourceReadSpanMs = elapsedMs(transferStart);
  stats.destWriteSpanMs = stats.sourceReadSpanMs;
  return stats;
}

async function transferFileData(
  sourceSftp: SFTPWrapper,
  destSftp: SFTPWrapper,
  destSession: SSHSessionLike,
  sourcePath: string,
  destPath: string,
  fileSize: number,
  onProgress?: (bytes: number) => void,
  shouldAbort?: () => boolean,
  transferId?: string,
  reconnect?: TransferReconnectContext,
  onResumeOffset?: (offset: number) => void,
  parallelSegmentCount?: number,
): Promise<PipelinedXferStats> {
  const tuning = selectTransferTuning(
    fileSize,
    reconnect?.profileKey
      ? getTransferProfile(reconnect.profileKey)
      : undefined,
    parallelSegmentCount,
  );
  const pipeOptions: PipelinedXferOptions = {
    fileSize,
    onProgress,
    shouldAbort,
    transferId,
    reconnect,
    onResumeOffset,
    parallelSegmentCount: tuning.parallelSegmentCount,
    pipelineConcurrency: tuning.pipelineConcurrency,
  };

  if (transferId) {
    updateTransfer(transferId, {
      parallelSegmentCount: tuning.parallelSegmentCount,
    });
  }

  const startedAt = Date.now();
  const shouldProfile = fileSize >= SFTP_XFER_SEGMENT_THRESHOLD;
  fileLogger.info("Selected adaptive transfer tuning", {
    operation: "host_transfer_tuning",
    transferId,
    fileSize,
    parallelSegmentCount: tuning.parallelSegmentCount,
    pipelineConcurrency: tuning.pipelineConcurrency,
    profileSamples: reconnect?.profileKey
      ? getTransferProfile(reconnect.profileKey)?.samples
      : undefined,
    explicitParallelOverride: parallelSegmentCount !== undefined,
  });
  try {
    const stats = isLocalSshEndpoint(destSession.ip)
      ? await pipelinedSftpToLocalFile(
          sourceSftp,
          sourcePath,
          destPath,
          pipeOptions,
        )
      : await pipelinedSftpFile(
          sourceSftp,
          destSftp,
          sourcePath,
          destPath,
          pipeOptions,
        );
    if (shouldProfile && reconnect?.profileKey) {
      recordTransferProfile(reconnect.profileKey, {
        bytes: stats.bytes,
        durationMs: Math.max(1, Date.now() - startedAt),
        lanes: tuning.parallelSegmentCount,
        pipelineConcurrency: tuning.pipelineConcurrency,
        failed: false,
      });
    }
    return stats;
  } catch (err) {
    if (shouldProfile && reconnect?.profileKey) {
      recordTransferProfile(reconnect.profileKey, {
        bytes: 0,
        durationMs: Math.max(1, Date.now() - startedAt),
        lanes: tuning.parallelSegmentCount,
        pipelineConcurrency: tuning.pipelineConcurrency,
        failed: true,
      });
    }
    throw err;
  }
}

const DIRECT_BENCHMARK_BYTES = 8 * 1024 * 1024;
const DIRECT_ROUTE_CACHE_MS = 10 * 60 * 1000;

function getDirectEndpoint(
  sourceSession: SSHSessionLike,
  destSession: SSHSessionLike,
): DirectTransferEndpoint | null {
  if (
    !sourceSession.ip ||
    !destSession.ip ||
    !destSession.username ||
    !destSession.port ||
    sourceSession.transferPlatform !== "unix" ||
    destSession.transferPlatform !== "unix"
  ) {
    return null;
  }
  return {
    host: destSession.ip,
    port: destSession.port,
    username: destSession.username,
  };
}

function directRouteKey(
  sourceSession: SSHSessionLike,
  endpoint: DirectTransferEndpoint,
): string {
  return `${sourceSession.username ?? ""}@${sourceSession.ip}->${endpoint.username}@${endpoint.host}:${endpoint.port}`;
}

function transferProfileKey(
  sourceSession: SSHSessionLike,
  destSession: SSHSessionLike,
  userId: string,
): string {
  return `${userId}:${sourceSession.username ?? ""}@${sourceSession.ip ?? "local"}:${sourceSession.port ?? 22}->${destSession.username ?? ""}@${destSession.ip ?? "local"}:${destSession.port ?? 22}`;
}

async function benchmarkTransferRoutes(
  deps: HostTransferDeps,
  transferId: string,
  sourceSession: SSHSessionLike,
  destSession: SSHSessionLike,
  endpoint: DirectTransferEndpoint,
  profileKey?: string,
): Promise<{ useDirect: boolean; directMs?: number; relayMs?: number }> {
  const key = directRouteKey(sourceSession, endpoint);
  const cached = directRouteCache.get(key);
  if (cached && cached.expiresAt > Date.now()) return cached;
  const learned = profileKey
    ? getRecentDirectRouteDecision(profileKey, DIRECT_ROUTE_CACHE_MS)
    : undefined;
  if (learned) {
    const result = {
      ...learned,
      expiresAt: Date.now() + DIRECT_ROUTE_CACHE_MS,
    };
    directRouteCache.set(key, result);
    return result;
  }

  updateTransfer(transferId, { phase: "benchmarking" });
  const probe = await execCommand(
    deps,
    sourceSession,
    `command -v rsync >/dev/null && ${buildDirectProbeCommand(endpoint)}`,
    { timeoutMs: 8000 },
  ).catch(() => ({ code: 1, stderr: "" }));
  if (probe.code !== 0) {
    const result = {
      useDirect: false,
      expiresAt: Date.now() + DIRECT_ROUTE_CACHE_MS,
    };
    directRouteCache.set(key, result);
    return result;
  }

  const probeId = randomUUID();
  const sourceProbe = `/tmp/termix-route-${probeId}.bin`;
  const directProbe = `/tmp/termix-route-${probeId}.direct`;
  const relayProbe = `/tmp/termix-route-${probeId}.relay`;
  const cleanup = async () => {
    await Promise.allSettled([
      execCommand(deps, sourceSession, `rm -f ${quoteShell(sourceProbe)}`),
      execCommand(
        deps,
        destSession,
        `rm -f ${quoteShell(directProbe)} ${quoteShell(relayProbe)}`,
      ),
    ]);
  };

  try {
    const created = await execCommand(
      deps,
      sourceSession,
      `dd if=/dev/zero of=${quoteShell(sourceProbe)} bs=1048576 count=8 status=none`,
      { timeoutMs: 8000 },
    );
    if (created.code !== 0) throw new Error("Failed to create route probe");

    const directStart = performance.now();
    const direct = await execCommand(
      deps,
      sourceSession,
      buildDirectRsyncCommand(endpoint, [sourceProbe], directProbe, false),
      { timeoutMs: 15000 },
    );
    const directMs = performance.now() - directStart;
    if (direct.code !== 0) throw new Error("Direct route probe failed");

    const [sourceSftp, destSftp] = await Promise.all([
      deps.getSessionSftp(sourceSession),
      deps.getSessionSftp(destSession),
    ]);
    const relayStart = performance.now();
    const relayDeadline = Date.now() + 15000;
    await transferFileData(
      sourceSftp,
      destSftp,
      destSession,
      sourceProbe,
      relayProbe,
      DIRECT_BENCHMARK_BYTES,
      undefined,
      () => Date.now() >= relayDeadline,
    );
    const relayMs = performance.now() - relayStart;
    const profile = profileKey
      ? recordDirectRouteBenchmark(profileKey, directMs, relayMs)
      : undefined;
    const useDirect =
      shouldUseDirectTransfer(directMs, relayMs) &&
      (!profile || profile.outcomeSamples < 2 || profile.failureRate < 0.25);
    const result = {
      useDirect,
      directMs,
      relayMs,
      expiresAt: Date.now() + DIRECT_ROUTE_CACHE_MS,
    };
    directRouteCache.set(key, result);
    updateTransfer(transferId, {
      timings: {
        ...activeTransfers.get(transferId)?.timings,
        directBenchmarkMs: directMs,
        relayBenchmarkMs: relayMs,
      },
    });
    return result;
  } catch {
    const result = {
      useDirect: false,
      expiresAt: Date.now() + DIRECT_ROUTE_CACHE_MS,
    };
    directRouteCache.set(key, result);
    return result;
  } finally {
    await cleanup();
  }
}

async function tryAdaptiveDirectTransfer(
  deps: HostTransferDeps,
  transferId: string,
  sourceSession: SSHSessionLike,
  destSession: SSHSessionLike,
  sourcePaths: string[],
  destPath: string,
  move: boolean,
  reconnectMeta: TransferReconnectMeta,
): Promise<TransferProgress | null> {
  const endpoint = getDirectEndpoint(sourceSession, destSession);
  if (!endpoint) return null;

  const sourceSftp = await deps.getSessionSftp(sourceSession);
  const firstStats = await promisifySftpStat(sourceSftp, sourcePaths[0]);
  const destIsDirectory = sourcePaths.length > 1 || firstStats.isDirectory();
  const summary = await scanSourcePathsForRouting(
    sourceSftp,
    sourcePaths,
    transferId,
  );
  if (!shouldBenchmarkDirectTransfer(summary.totalBytes)) return null;

  const route = await benchmarkTransferRoutes(
    deps,
    transferId,
    sourceSession,
    destSession,
    endpoint,
    reconnectMeta.profileKey,
  );
  if (!route.useDirect) return null;
  if (destIsDirectory) {
    await ensureDestDirectory(deps, destSession, destPath);
  } else {
    await ensureDestParentForFile(deps, destSession, destPath);
  }

  updateTransfer(transferId, {
    method: "direct_rsync",
    phase: "transferring",
    bytesTransferred: 0,
    totalBytes: summary.totalBytes,
  });
  const transferStart = performance.now();
  let outputBuffer = "";

  try {
    const result = await execCommand(
      deps,
      sourceSession,
      buildDirectRsyncCommand(endpoint, sourcePaths, destPath, destIsDirectory),
      {
        shouldAbort: createTransferShouldAbort(transferId),
        onOutput: (chunk) => {
          outputBuffer = `${outputBuffer}${chunk.toString()}`.slice(-2048);
          const matches = [...outputBuffer.matchAll(/([\d,]+)\s+(\d+)%/g)];
          const last = matches.at(-1);
          if (!last) return;
          const bytes = Number(last[1].replace(/,/g, ""));
          if (Number.isFinite(bytes)) {
            updateTransfer(transferId, {
              bytesTransferred: Math.min(bytes, summary.totalBytes),
            });
          }
        },
      },
    );
    if (result.code !== 0) {
      throw new Error(result.stderr || "Direct rsync transfer failed");
    }

    const workItems: FileWorkItem[] = [];
    if (destIsDirectory) {
      for (const sourcePath of sourcePaths) {
        workItems.push(
          ...(await collectFileWorkItems(sourceSftp, sourcePath, destPath)),
        );
      }
    } else {
      workItems.push({
        sourcePath: sourcePaths[0],
        destPath,
        mode: firstStats.mode,
        size: firstStats.size,
      });
    }
    for (const item of workItems) {
      await verifyTransferredFile(
        deps,
        transferId,
        reconnectMeta,
        item.sourcePath,
        item.destPath,
      );
    }
    if (move) {
      await deleteSourcePathsAfterSuccess(
        deps,
        transferId,
        sourceSession,
        sourcePaths,
      );
    }

    const transferMs = performance.now() - transferStart;
    if (reconnectMeta.profileKey) {
      recordDirectRouteOutcome(
        reconnectMeta.profileKey,
        false,
        Date.now(),
        DIRECT_ROUTE_CACHE_MS,
      );
    }
    return finalizeTransfer(transferId, {
      status: "success",
      phase: "verifying",
      method: "direct_rsync",
      bytesTransferred: summary.totalBytes,
      totalBytes: summary.totalBytes,
      sourcePaths,
      destPath,
      sourceDeleted: move,
      moveRequested: move,
      integrityVerified: true,
      timings: {
        ...activeTransfers.get(transferId)?.timings,
        transferMs,
        transferBytes: summary.totalBytes,
        endToEndMbPerSec: computeTransferMbPerSec(
          summary.totalBytes,
          transferMs,
        ),
      },
    });
  } catch (error) {
    if (error instanceof TransferCancelledError) throw error;
    fileLogger.warn("Direct transfer failed; falling back to relay", {
      operation: "host_transfer_direct_fallback",
      transferId,
      error: getErrorMessage(error, "Direct transfer failed"),
    });
    if (reconnectMeta.profileKey) {
      recordDirectRouteOutcome(
        reconnectMeta.profileKey,
        true,
        Date.now(),
        DIRECT_ROUTE_CACHE_MS,
      );
    }
    directRouteCache.set(directRouteKey(sourceSession, endpoint), {
      useDirect: false,
      expiresAt: Date.now() + DIRECT_ROUTE_CACHE_MS,
    });
    updateTransfer(transferId, {
      method: undefined,
      phase: "transferring",
      bytesTransferred: 0,
      integrityVerified: false,
    });
    return null;
  }
}

async function transferSingleFile(
  deps: HostTransferDeps,
  transferId: string,
  sourceSession: SSHSessionLike,
  destSession: SSHSessionLike,
  sourcePath: string,
  destPath: string,
  move: boolean,
  reconnectMeta: TransferReconnectMeta,
  requestedParallelSegments?: number,
): Promise<TransferProgress> {
  const sourceSftp = await deps.getSessionSftp(sourceSession);
  const destSftp = await deps.getSessionSftp(destSession);
  const shouldAbort = createTransferShouldAbort(transferId);

  const reconnect = buildTransferReconnectContext(
    deps,
    transferId,
    reconnectMeta,
  );

  const stats = await promisifySftpStat(sourceSftp, sourcePath);
  if (!stats.isFile()) {
    throw new Error(`Source is not a regular file: ${sourcePath}`);
  }

  updateTransfer(transferId, {
    method: "stream",
    phase: "transferring",
    totalBytes: stats.size,
  });

  let bytesTransferred = 0;
  try {
    const destStat = await promisifySftpStat(destSftp, destPath);
    bytesTransferred = Math.min(destStat.size, stats.size);
  } catch {
    /* destination file does not exist yet */
  }

  updateTransfer(transferId, { bytesTransferred });
  const prepareStart = Date.now();
  await ensureDestParentForFile(deps, destSession, destPath);
  const prepareDestMs = elapsedMs(prepareStart);
  updateTransfer(transferId, { timings: { prepareDestMs } });

  const syncProgress = (absoluteOffset: number) => {
    bytesTransferred = absoluteOffset;
    updateTransfer(transferId, { bytesTransferred: absoluteOffset });
  };

  const tuning = selectTransferTuning(
    stats.size,
    reconnect.profileKey ? getTransferProfile(reconnect.profileKey) : undefined,
    requestedParallelSegments,
  );
  const parallelLanes = tuning.parallelSegmentCount;
  const useAbsoluteProgressOnly = parallelLanes > 1;

  throwIfCancelled(transferId);
  trackDestArtifact(transferId, destPath);
  await transferFileData(
    sourceSftp,
    destSftp,
    destSession,
    sourcePath,
    destPath,
    stats.size,
    useAbsoluteProgressOnly
      ? undefined
      : (n) => {
          bytesTransferred += n;
          updateTransfer(transferId, { bytesTransferred });
        },
    shouldAbort,
    transferId,
    reconnect,
    syncProgress,
    requestedParallelSegments,
  );

  await verifyTransferredFile(
    deps,
    transferId,
    reconnectMeta,
    sourcePath,
    destPath,
  );

  if (move) {
    await deleteSourcePathsAfterSuccess(deps, transferId, sourceSession, [
      sourcePath,
    ]);
  }

  return finalizeTransfer(transferId, {
    status: "success",
    phase: "transferring",
    method: "stream",
    bytesTransferred: stats.size,
    totalBytes: stats.size,
    sourcePaths: [sourcePath],
    destPath,
    sourceDeleted: move,
    moveRequested: move,
    timings: buildStreamTransferTimings(transferId, stats.size, prepareDestMs),
  });
}

async function cleanupDestItems(
  deps: HostTransferDeps,
  destSession: SSHSessionLike,
  destDir: string,
  basenames: string[],
): Promise<void> {
  const destSftp = await deps.getSessionSftp(destSession);
  for (const name of basenames) {
    const target = joinPath(destDir, name);
    try {
      await deletePathSftp(destSftp, target);
    } catch {
      /* best effort */
    }
  }
}

async function deleteSourcePaths(
  deps: HostTransferDeps,
  sourceSession: SSHSessionLike,
  sourcePaths: string[],
): Promise<void> {
  const sourceSftp = await deps.getSessionSftp(sourceSession);
  for (const path of sourcePaths) {
    try {
      await deletePathSftp(sourceSftp, path);
    } catch {
      /* best effort */
    }
  }
}

async function transferViaTar(
  deps: HostTransferDeps,
  transferId: string,
  sourceSession: SSHSessionLike,
  destSession: SSHSessionLike,
  sourcePaths: string[],
  destPath: string,
  move: boolean,
  reconnectMeta: TransferReconnectMeta,
): Promise<TransferProgress> {
  const sourceSftp = await deps.getSessionSftp(sourceSession);
  const destSftp = await deps.getSessionSftp(destSession);
  const reconnect = buildTransferReconnectContext(
    deps,
    transferId,
    reconnectMeta,
  );
  const archiveId = randomUUID();
  const tempArchive = `/tmp/termix-transfer-${archiveId}.tar.gz`;
  updateTransfer(transferId, { tempArchivePath: tempArchive });
  trackDestArtifact(transferId, tempArchive);
  const workingDir = getWorkingDir(sourcePaths);
  const basenames = sourcePaths.map((p) => basename(p));
  const escapedNames = basenames.map((n) => `'${escapeShell(n)}'`).join(" ");
  const escapedDir = escapeShell(workingDir);
  const escapedArchive = escapeShell(tempArchive);
  const escapedDest = escapeShell(destPath);

  await ensureDestDirectory(deps, destSession, destPath);

  updateTransfer(transferId, {
    method: "tar",
    phase: "compressing",
  });

  throwIfCancelled(transferId);
  const compressStart = Date.now();
  const compressCmd = `cd '${escapedDir}' && tar -czf '${escapedArchive}' ${escapedNames}`;
  const compressResult = await execCommand(deps, sourceSession, compressCmd);
  const compressMs = elapsedMs(compressStart);
  updateTransfer(transferId, { timings: { compressMs } });
  if (compressResult.code !== 0) {
    throw new Error(
      compressResult.stderr || "Failed to compress on source host",
    );
  }

  throwIfCancelled(transferId);
  let archiveSize = 0;
  try {
    const archiveStats = await promisifySftpStat(sourceSftp, tempArchive);
    archiveSize = archiveStats.size;
  } catch {
    /* size unknown */
  }

  updateTransfer(transferId, {
    phase: "transferring",
    totalBytes: archiveSize,
    bytesTransferred: 0,
  });

  let bytesTransferred = 0;
  const transferStart = Date.now();
  const xferStats = createEmptyXferStats();
  const syncProgress = (absoluteOffset: number) => {
    bytesTransferred = absoluteOffset;
    updateTransfer(transferId, { bytesTransferred: absoluteOffset });
  };
  try {
    const fileStats = await transferFileData(
      sourceSftp,
      destSftp,
      destSession,
      tempArchive,
      tempArchive,
      archiveSize,
      (n) => {
        bytesTransferred += n;
        updateTransfer(transferId, { bytesTransferred });
      },
      () => cancelRequestedTransfers.has(transferId),
      transferId,
      reconnect,
      syncProgress,
    );
    mergeXferStats(xferStats, fileStats);
    await verifyTransferredFile(
      deps,
      transferId,
      reconnectMeta,
      tempArchive,
      tempArchive,
    );
  } catch (err) {
    if (!(err instanceof TransferCancelledError)) {
      await promisifySftpUnlink(destSftp, tempArchive).catch(() => {});
      await cleanupDestItems(deps, destSession, destPath, basenames);
    }
    throw err;
  } finally {
    await promisifySftpUnlink(sourceSftp, tempArchive);
  }
  throwIfCancelled(transferId);
  const transferMs = elapsedMs(transferStart);
  const hopTimings = buildTransferHopTimings(xferStats, transferMs);
  updateTransfer(transferId, {
    timings: {
      ...activeTransfers.get(transferId)?.timings,
      transferMs,
      ...hopTimings,
    },
  });

  updateTransfer(transferId, { phase: "extracting" });

  throwIfCancelled(transferId);
  const extractStart = Date.now();
  const extractCmd = `tar -xzf '${escapedArchive}' -C '${escapedDest}'`;
  const extractResult = await execCommand(deps, destSession, extractCmd);
  const extractMs = elapsedMs(extractStart);

  await promisifySftpUnlink(destSftp, tempArchive);

  if (extractResult.code !== 0) {
    await cleanupDestItems(deps, destSession, destPath, basenames);
    throw new Error(
      extractResult.stderr || "Failed to extract on destination host",
    );
  }

  if (move) {
    await deleteSourcePathsAfterSuccess(
      deps,
      transferId,
      sourceSession,
      sourcePaths,
    );
  }

  return finalizeTransfer(transferId, {
    status: "success",
    phase: "extracting",
    method: "tar",
    bytesTransferred,
    totalBytes: archiveSize,
    sourcePaths,
    destPath,
    sourceDeleted: move,
    moveRequested: move,
    timings: {
      ...activeTransfers.get(transferId)?.timings,
      extractMs,
      ...hopTimings,
    },
  });
}

async function transferViaItemSftp(
  deps: HostTransferDeps,
  transferId: string,
  sourceSession: SSHSessionLike,
  destSession: SSHSessionLike,
  sourcePaths: string[],
  destPath: string,
  move: boolean,
  destPlatform: TransferPlatform,
  reconnectMeta: TransferReconnectMeta,
): Promise<TransferProgress> {
  const sourceSftp = await deps.getSessionSftp(sourceSession);
  const destSftp = await deps.getSessionSftp(destSession);
  const reconnect = buildTransferReconnectContext(
    deps,
    transferId,
    reconnectMeta,
  );

  const createdDirs = new Set<string>();
  await ensureDirectoryTreeSftp(destSftp, destPath, createdDirs);

  const allWork: FileWorkItem[] = [];
  for (const sourcePath of sourcePaths) {
    const items = await collectFileWorkItems(sourceSftp, sourcePath, destPath);
    allWork.push(...items);
  }

  allWork.sort((a, b) => b.size - a.size);

  const totalBytes = allWork.reduce((sum, item) => sum + item.size, 0);

  updateTransfer(transferId, {
    method: "item_sftp",
    phase: "transferring",
    totalItems: allWork.length,
    itemsCompleted: 0,
    totalBytes,
    bytesTransferred: 0,
  });

  const failedPaths: string[] = [];
  const createdFiles: string[] = [];
  let itemsCompleted = 0;
  let bytesTransferred = 0;
  const transferStart = Date.now();
  const xferStats = createEmptyXferStats();

  for (const item of allWork) {
    throwIfCancelled(transferId);
    trackDestArtifact(transferId, item.destPath);
    const bytesBeforeItem = bytesTransferred;
    try {
      const parentDir = dirname(item.destPath);
      if (parentDir && !isRootOnlyPath(parentDir)) {
        await ensureDirectoryTreeSftp(destSftp, parentDir, createdDirs);
      }
      const itemStats = await promisifySftpStat(sourceSftp, item.sourcePath);
      const itemXferStats = await transferFileData(
        sourceSftp,
        destSftp,
        destSession,
        item.sourcePath,
        item.destPath,
        itemStats.size,
        (n) => {
          bytesTransferred += n;
          updateTransfer(transferId, { bytesTransferred });
        },
        () => cancelRequestedTransfers.has(transferId),
        transferId,
        reconnect,
        (absoluteOffset) => {
          bytesTransferred = bytesBeforeItem + absoluteOffset;
          updateTransfer(transferId, { bytesTransferred });
        },
      );
      mergeXferStats(xferStats, itemXferStats);
      await verifyTransferredFile(
        deps,
        transferId,
        reconnectMeta,
        item.sourcePath,
        item.destPath,
      );
      updateTransfer(transferId, { phase: "transferring" });
      if (destPlatform !== "windows") {
        await promisifySftpChmod(destSftp, item.destPath, item.mode);
      }
      createdFiles.push(item.destPath);
      itemsCompleted++;
      updateTransfer(transferId, { itemsCompleted, bytesTransferred });
    } catch (err) {
      if (isPermissionError(err as Error)) {
        failedPaths.push(item.sourcePath);
        itemsCompleted++;
        updateTransfer(transferId, { itemsCompleted, bytesTransferred });
        continue;
      }
      if (!(err instanceof TransferCancelledError)) {
        await deletePathSftp(destSftp, item.destPath).catch(() => {});
        for (const created of [...createdFiles].reverse()) {
          await deletePathSftp(destSftp, created).catch(() => {});
        }
      }
      throw err;
    }
  }

  const transferMs = elapsedMs(transferStart);
  const hopTimings = buildTransferHopTimings(xferStats, transferMs);

  const status: TransferStatus = failedPaths.length > 0 ? "partial" : "success";

  // Move only after every file succeeded — never delete source on partial transfer
  if (status === "success" && move) {
    await deleteSourcePathsAfterSuccess(
      deps,
      transferId,
      sourceSession,
      sourcePaths,
    );
  }

  return finalizeTransfer(transferId, {
    status,
    phase: "transferring",
    method: "item_sftp",
    itemsCompleted,
    totalItems: allWork.length,
    failedPaths: failedPaths.length > 0 ? failedPaths : undefined,
    sourcePaths,
    destPath,
    sourceDeleted: status === "success" && move,
    moveRequested: move,
    integrityVerified: status === "success",
    timings: {
      ...activeTransfers.get(transferId)?.timings,
      transferMs,
      ...hopTimings,
    },
  });
}

async function runTransfer(
  deps: HostTransferDeps,
  transferId: string,
  request: TransferRequest,
): Promise<void> {
  await initializeTransferProfiles();
  const {
    sourceSessionId: browseSourceSessionId,
    sourcePaths,
    destSessionId: browseDestSessionId,
    destPath,
    move = false,
    userId,
    methodPreference = "auto",
    parallelSegmentCount: requestParallelSegments,
  } = request;

  const parallelSegmentCount = requestParallelSegments;

  const dedicatedSourceSessionId = `xfer:${transferId}:src`;
  const dedicatedDestSessionId = `xfer:${transferId}:dst`;
  const runStart = Date.now();
  const reconnectMeta: TransferReconnectMeta = {
    userId,
    browseSourceSessionId,
    browseDestSessionId,
    dedicatedSourceSessionId,
    dedicatedDestSessionId,
  };

  try {
    const sourceSession = await deps.openDedicatedTransferSession(
      browseSourceSessionId,
      dedicatedSourceSessionId,
      userId,
      transferId,
    );
    const destSession = await deps.openDedicatedTransferSession(
      browseDestSessionId,
      dedicatedDestSessionId,
      userId,
      transferId,
    );

    reconnectMeta.profileKey = transferProfileKey(
      sourceSession,
      destSession,
      userId,
    );

    sourceSession.lastActive = Date.now();
    destSession.lastActive = Date.now();

    updateTransfer(transferId, {
      parallelSegmentCount:
        parallelSegmentCount ?? DEFAULT_PARALLEL_SEGMENT_COUNT,
      dedicatedSourceSessionId,
      dedicatedDestSessionId,
    });

    const pathHints = [destPath, ...sourcePaths];
    const sourcePlatform = await detectTransferPlatform(
      deps,
      sourceSession,
      pathHints,
    );
    const destPlatform = await detectTransferPlatform(
      deps,
      destSession,
      pathHints,
    );

    const sourceSftp = await deps.getSessionSftp(sourceSession);

    for (const path of sourcePaths) {
      try {
        await promisifySftpStat(sourceSftp, path);
      } catch {
        throw new Error(`Source not found: ${path}`);
      }
    }

    if (browseSourceSessionId === browseDestSessionId) {
      for (const src of sourcePaths) {
        if (pathsOverlap(src, destPath)) {
          throw new Error("Source and destination paths overlap");
        }
      }
    }

    const directResult =
      methodPreference === "auto"
        ? await tryAdaptiveDirectTransfer(
            deps,
            transferId,
            sourceSession,
            destSession,
            sourcePaths,
            destPath,
            move,
            reconnectMeta,
          )
        : null;
    if (directResult) {
      updateTransfer(transferId, {
        timings: {
          ...directResult.timings,
          totalMs: elapsedMs(runStart),
        },
      });
      return;
    }

    let useArchive = sourcePaths.length > 1;

    if (sourcePaths.length === 1) {
      const stats = await promisifySftpStat(sourceSftp, sourcePaths[0]);
      useArchive = stats.isDirectory();
    }

    if (!useArchive) {
      await transferSingleFile(
        deps,
        transferId,
        sourceSession,
        destSession,
        sourcePaths[0],
        destPath,
        move,
        reconnectMeta,
        parallelSegmentCount,
      );
    } else {
      const prepareStart = Date.now();
      await ensureDestDirectory(deps, destSession, destPath);
      updateTransfer(transferId, {
        timings: { prepareDestMs: elapsedMs(prepareStart) },
      });

      const sourceHasTar =
        sourcePlatform === "unix" &&
        (await checkTarAvailable(deps, sourceSession));
      const destHasTar =
        destPlatform === "unix" && (await checkTarAvailable(deps, destSession));

      throwIfCancelled(transferId);
      const scanSummary = await scanSourcePathsForRouting(
        sourceSftp,
        sourcePaths,
        transferId,
      );
      const archiveMethod = resolveArchiveTransferMethod(
        methodPreference,
        scanSummary,
        sourcePlatform,
        destPlatform,
        sourceHasTar,
        destHasTar,
      );

      fileLogger.info("Resolved archive transfer method", {
        operation: "host_transfer",
        transferId,
        methodPreference,
        archiveMethod,
        fileCount: scanSummary.fileCount,
        totalBytes: scanSummary.totalBytes,
        incompressibleRatio: scanSummary.incompressibleRatio,
      });

      if (archiveMethod === "tar") {
        await transferViaTar(
          deps,
          transferId,
          sourceSession,
          destSession,
          sourcePaths,
          destPath,
          move,
          reconnectMeta,
        );
      } else {
        await transferViaItemSftp(
          deps,
          transferId,
          sourceSession,
          destSession,
          sourcePaths,
          destPath,
          move,
          destPlatform,
          reconnectMeta,
        );
      }
    }

    fileLogger.success("Host transfer completed", {
      operation: "host_transfer",
      transferId,
      browseSourceSessionId,
      browseDestSessionId,
      sourcePaths,
      destPath,
      move,
      timings: {
        ...activeTransfers.get(transferId)?.timings,
        totalMs: elapsedMs(runStart),
      },
    });
    updateTransfer(transferId, {
      moveRequested: move,
      timings: {
        ...activeTransfers.get(transferId)?.timings,
        totalMs: elapsedMs(runStart),
      },
    });
  } catch (err) {
    if (err instanceof TransferCancelledError) {
      const current = activeTransfers.get(transferId);
      finalizeTransfer(
        transferId,
        cancelledProgressPatch(current, {
          status: "cancelled",
          phase: current?.phase ?? "transferring",
          message: "Transfer cancelled by user",
          method: current?.method,
          sourcePaths,
          destPath,
          bytesTransferred: current?.bytesTransferred,
          totalBytes: current?.totalBytes,
          itemsCompleted: current?.itemsCompleted,
          totalItems: current?.totalItems,
          moveRequested: move,
          sourceDeleted: false,
          integrityVerified: false,
          timings: {
            ...current?.timings,
            totalMs: elapsedMs(runStart),
          },
        }),
      );
      fileLogger.info("Host transfer cancelled", {
        operation: "host_transfer",
        transferId,
        sourcePaths,
        destPath,
      });
      return;
    }

    const current = activeTransfers.get(transferId);
    const message = getErrorMessage(err, "Transfer failed");

    if (
      sourcePaths.length === 1 &&
      current?.method === "stream" &&
      current.destPath &&
      current.totalBytes
    ) {
      try {
        const destSession = await deps.openDedicatedTransferSession(
          browseDestSessionId,
          dedicatedDestSessionId,
          userId,
          transferId,
          { allowBrowseDisconnected: true },
        );
        const finalized = await tryFinalizeStreamTransferIfDestComplete(
          deps,
          transferId,
          destSession,
          current.destPath,
          current.totalBytes,
          {
            sourcePaths,
            moveRequested: move,
            sourceDeleted: current.sourceDeleted,
          },
          () =>
            verifyTransferredFile(
              deps,
              transferId,
              reconnectMeta,
              sourcePaths[0],
              current.destPath!,
            ),
        );
        if (finalized) {
          fileLogger.info("Host transfer succeeded after destination verify", {
            operation: "host_transfer",
            transferId,
            sourcePaths,
            destPath,
          });
          return;
        }
      } catch {
        /* fall through to error */
      }
    }

    finalizeTransfer(
      transferId,
      failedProgressPatch(current, {
        status: "error",
        phase: current?.phase ?? "transferring",
        message,
        method: current?.method,
        sourcePaths,
        destPath,
        bytesTransferred: current?.bytesTransferred,
        totalBytes: current?.totalBytes,
        itemsCompleted: current?.itemsCompleted,
        totalItems: current?.totalItems,
        moveRequested: move,
        integrityVerified: false,
        timings: {
          ...current?.timings,
          totalMs: elapsedMs(runStart),
        },
      }),
    );
    fileLogger.error(
      err instanceof TransferStalledError
        ? "Host transfer stalled"
        : "Host transfer failed",
      err,
      {
        operation: "host_transfer",
        transferId,
        sourcePaths,
        destPath,
      },
    );
  } finally {
    deps.closeDedicatedTransferSession(dedicatedSourceSessionId);
    deps.closeDedicatedTransferSession(dedicatedDestSessionId);
  }
}

export function getTransferStatus(
  transferId: string,
  userId: string,
): TransferProgress | null {
  checkHungTransfers();
  const progress = activeTransfers.get(transferId);
  if (!progress || progress.userId !== userId) return null;
  return progress;
}

export function listActiveTransfers(userId: string): TransferProgress[] {
  return Array.from(activeTransfers.values()).filter(
    (progress) => progress.userId === userId && progress.status === "running",
  );
}

export async function cleanupCancelledTransfer(
  deps: HostTransferDeps,
  transferId: string,
  userId: string,
): Promise<{ removedPaths: string[]; failedPaths: string[] }> {
  const progress = activeTransfers.get(transferId);
  if (!progress || progress.userId !== userId) {
    throw new Error("Transfer not found");
  }
  if (progress.status !== "cancelled") {
    throw new Error("Transfer is not cancelled");
  }
  if (progress.cleanupCompleted) {
    return { removedPaths: [], failedPaths: [] };
  }
  if (!progress.destSessionId) {
    throw new Error("Transfer has no destination session");
  }

  const pathsToRemove = buildCleanupPaths(progress);
  if (pathsToRemove.length === 0) {
    updateTransfer(transferId, { cleanupCompleted: true });
    return { removedPaths: [], failedPaths: [] };
  }

  const cleanupSessionId = `xfer:cleanup:${transferId}:dst`;
  const removedPaths: string[] = [];
  const failedPaths: string[] = [];

  try {
    const destSession = await deps.openDedicatedTransferSession(
      progress.destSessionId,
      cleanupSessionId,
      userId,
      transferId,
      { allowBrowseDisconnected: true },
    );
    const destSftp = await deps.getSessionSftp(destSession);

    for (const path of pathsToRemove) {
      try {
        await deletePathSftp(destSftp, path);
        removedPaths.push(path);
      } catch {
        failedPaths.push(path);
      }
    }
  } finally {
    deps.closeDedicatedTransferSession(cleanupSessionId);
  }

  updateTransfer(transferId, { cleanupCompleted: true });
  return { removedPaths, failedPaths };
}

export function retryHostTransfer(
  deps: HostTransferDeps,
  transferId: string,
  userId: string,
): boolean {
  const progress = activeTransfers.get(transferId);
  if (
    !progress ||
    progress.userId !== userId ||
    progress.status !== "error" ||
    !progress.retryable ||
    !progress.requestSnapshot
  ) {
    return false;
  }

  void (async () => {
    if (
      progress.method === "stream" &&
      progress.destPath &&
      progress.totalBytes &&
      progress.destSessionId
    ) {
      const destId =
        progress.dedicatedDestSessionId ?? `xfer:${transferId}:dst`;
      try {
        const destSession = await deps.openDedicatedTransferSession(
          progress.destSessionId,
          destId,
          userId,
          transferId,
          { allowBrowseDisconnected: true },
        );
        const done = await tryFinalizeStreamTransferIfDestComplete(
          deps,
          transferId,
          destSession,
          progress.destPath,
          progress.totalBytes,
          {
            sourcePaths: progress.sourcePaths,
            moveRequested: progress.moveRequested,
          },
        );
        if (done) {
          return;
        }
      } catch {
        /* destination not ready — restart transfer below */
      }
    }

    const latest = activeTransfers.get(transferId);
    if (!latest || latest.status !== "error" || !latest.requestSnapshot) {
      return;
    }

    updateTransfer(transferId, {
      status: "running",
      phase: "transferring",
      message: undefined,
      retryable: false,
      parallelSegmentCount:
        latest.requestSnapshot?.parallelSegmentCount ??
        latest.parallelSegmentCount,
    });

    await runTransfer(deps, transferId, {
      ...latest.requestSnapshot,
      userId,
      parallelSegmentCount: latest.requestSnapshot.parallelSegmentCount,
    });
  })();

  return true;
}

export async function previewArchiveTransferMethod(
  deps: HostTransferDeps,
  request: {
    sourceSessionId: string;
    destSessionId: string;
    sourcePaths: string[];
    destPath: string;
    methodPreference?: TransferMethodPreference;
    userId: string;
  },
): Promise<TransferMethodPreview> {
  const {
    sourceSessionId,
    destSessionId,
    sourcePaths,
    destPath,
    methodPreference = "auto",
    userId,
  } = request;

  const sourceSession = deps.sshSessions[sourceSessionId];
  const destSession = deps.sshSessions[destSessionId];

  if (!sourceSession?.isConnected || !destSession?.isConnected) {
    throw new Error("SSH session not connected");
  }

  if (
    !deps.verifySessionOwnership(sourceSession, userId) ||
    !deps.verifySessionOwnership(destSession, userId)
  ) {
    throw new Error("Session access denied");
  }

  const pathHints = [destPath, ...sourcePaths];
  const sourcePlatform = await detectTransferPlatform(
    deps,
    sourceSession,
    pathHints,
  );
  const destPlatform = await detectTransferPlatform(
    deps,
    destSession,
    pathHints,
  );

  const sourceSftp = await deps.getSessionSftp(sourceSession);
  const scanSummary = await scanSourcePathsForRouting(
    sourceSftp,
    sourcePaths,
    "preview",
  );

  const sourceHasTar =
    sourcePlatform === "unix" && (await checkTarAvailable(deps, sourceSession));
  const destHasTar =
    destPlatform === "unix" && (await checkTarAvailable(deps, destSession));

  const resolvedMethod = resolveArchiveTransferMethod(
    methodPreference,
    scanSummary,
    sourcePlatform,
    destPlatform,
    sourceHasTar,
    destHasTar,
  );

  const reasonKey = getArchiveTransferReasonKey(
    methodPreference,
    resolvedMethod,
    scanSummary,
    sourcePlatform,
    destPlatform,
    sourceHasTar,
    destHasTar,
  );

  return {
    methodPreference,
    resolvedMethod,
    reasonKey,
    sourcePlatform,
    destPlatform,
    sourceHasTar,
    destHasTar,
    summary: scanSummary,
  };
}

export function startHostTransfer(
  deps: HostTransferDeps,
  request: TransferRequest,
): { transferId: string; syncResult?: TransferProgress } {
  const transferId = randomUUID();

  activeTransfers.set(transferId, {
    transferId,
    status: "running",
    phase: "transferring",
    sourcePaths: request.sourcePaths,
    destPath: request.destPath,
    userId: request.userId,
    sourceSessionId: request.sourceSessionId,
    destSessionId: request.destSessionId,
    startedAt: Date.now(),
    moveRequested: request.move ?? false,
    methodPreference: request.methodPreference ?? "auto",
    parallelSegmentCount: clampParallelSegmentCount(
      request.parallelSegmentCount,
    ),
    requestSnapshot: {
      sourceSessionId: request.sourceSessionId,
      sourcePaths: request.sourcePaths,
      destSessionId: request.destSessionId,
      destPath: request.destPath,
      move: request.move,
      methodPreference: request.methodPreference,
      parallelSegmentCount: request.parallelSegmentCount,
    },
  });

  const isSingleSmallFile = request.sourcePaths.length === 1 && !request.move;

  if (isSingleSmallFile) {
    const sourceSession = deps.sshSessions[request.sourceSessionId];
    if (sourceSession?.sftp || sourceSession?.isConnected) {
      void (async () => {
        try {
          const sftp = await deps.getSessionSftp(sourceSession);
          const stats = await promisifySftpStat(sftp, request.sourcePaths[0]);
          if (stats.isFile() && stats.size <= SMALL_FILE_SYNC_THRESHOLD) {
            await runTransfer(deps, transferId, request);
            return;
          }
        } catch {
          /* fall through to async */
        }
        void runTransfer(deps, transferId, request);
      })();
      return { transferId };
    }
  }

  void runTransfer(deps, transferId, request);
  return { transferId };
}

export function cleanupOldTransfers(maxAgeMs = 60 * 60 * 1000): void {
  const now = Date.now();
  for (const [id, progress] of activeTransfers.entries()) {
    if (
      progress.status !== "running" &&
      now - (progress as TransferProgress & { _ts?: number })._ts! > maxAgeMs
    ) {
      activeTransfers.delete(id);
    }
  }
}
