import { posix as posixPath } from "node:path";

export const SSH_CD_EXECUTION_MODE = "sequential" as const;

export interface RemoteWorkspaceConnection {
  remoteCwd: string;
  remoteHome: string;
}

export interface RemotePathMappingConnection extends RemoteWorkspaceConnection {
  localCwd: string;
  localHome: string;
}

export interface RemoteCwdChange {
  previousCwd: string;
  remoteCwd: string;
}

export function resolveRemoteCwd(path: string, currentCwd: string, remoteHome: string): string {
  if (typeof path !== "string" || path.length === 0) {
    throw new Error("path must be a non-empty string");
  }
  if (/[\0\r\n]/u.test(path)) {
    throw new Error("path must not contain NUL or newline characters");
  }
  if (!currentCwd.startsWith("/") || !remoteHome.startsWith("/")) {
    throw new Error("the active SSH connection has an invalid remote workspace");
  }
  if (path === "~") return posixPath.normalize(remoteHome);
  if (path.startsWith("~/")) return posixPath.normalize(posixPath.join(remoteHome, path.slice(2)));
  if (path.startsWith("~")) throw new Error("path supports only '~' or '~/' home expansion");
  if (path.startsWith("/")) return posixPath.normalize(path);
  return posixPath.normalize(posixPath.join(currentCwd, path));
}

export async function changeRemoteCwd(
  connection: RemoteWorkspaceConnection,
  path: string,
  verifyDirectory: (requestedCwd: string) => Promise<string>,
): Promise<RemoteCwdChange> {
  const previousCwd = connection.remoteCwd;
  const requestedCwd = resolveRemoteCwd(path, previousCwd, connection.remoteHome);
  const remoteCwd = await verifyDirectory(requestedCwd);
  connection.remoteCwd = remoteCwd;
  return { previousCwd, remoteCwd };
}

export function mapLocalPathToRemote(path: string, connection: RemotePathMappingConnection): string {
  if (path === connection.localCwd) return connection.remoteCwd;
  if (path.startsWith(`${connection.localCwd}/`)) {
    return `${connection.remoteCwd}${path.slice(connection.localCwd.length)}`;
  }
  if (path === connection.localHome) return connection.remoteHome;
  if (path.startsWith(`${connection.localHome}/`)) {
    return `${connection.remoteHome}${path.slice(connection.localHome.length)}`;
  }
  return path;
}
