import { getErrorMessage } from "../lib/error-message.js";
import axios from "axios";
import { asHttpError } from "@/lib/http-error";
import {
  authApi,
  fileManagerApi,
  handleApiError,
  getFileManagerApiForSession,
  setSessionOrigin,
  clearSessionOrigin,
} from "@/main-axios";
import { resolveConnectionOrigin } from "@/lib/connection-origin";
import { fileLogger } from "@/lib/frontend-logger";
import type { FileItem, SSHHost } from "@/types/index";
import { getCachedFileList } from "@/lib/file-list-request-cache";
import {
  getCachedFileContent,
  invalidateCachedFileContent,
  type FileContentResult,
} from "@/lib/file-content-request-cache";

type ApiConnectionLog = {
  type: "info" | "success" | "warning" | "error";
  stage: string;
  message: string;
  details?: Record<string, unknown>;
};

type ConnectErrorResponse = {
  error?: string;
  message?: string;
  connectionLogs?: ApiConnectionLog[];
  requires_totp?: boolean;
  requires_warpgate?: boolean;
  sessionId?: string;
  prompt?: string;
  url?: string;
  securityKey?: string;
  status?: string;
  reason?: string;
};

/**
 * The interactive-auth branches /ssh/connect can take before a session exists.
 * Callers switch on these, so they cannot stay behind Record<string, unknown>.
 */
export interface SSHConnectResult {
  success?: boolean;
  status?: string;
  reason?: "timeout" | "no_keyboard" | "auth_failed";
  requires_totp?: boolean;
  requires_warpgate?: boolean;
  sessionId?: string;
  prompt?: string;
  url?: string;
  securityKey?: string;
}

function buildFileManagerUrl(path: string): string {
  const baseURL = String(fileManagerApi.defaults.baseURL || "");
  return `${baseURL.replace(/\/$/, "")}${path}`;
}

function triggerBlobDownload(blob: Blob, fileName: string): void {
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = fileName;
  link.style.display = "none";

  document.body.appendChild(link);
  link.click();

  window.setTimeout(() => {
    link.remove();
    URL.revokeObjectURL(url);
  }, 1000);
}

// SSH FILE OPERATIONS
// ============================================================================

export async function connectSSH(
  sessionId: string,
  config: {
    hostId?: number;
    /** Names the host across a sync pair; hostId only names it locally. */
    syncId?: string | null;
    ip: string;
    port: number;
    username: string;
    password?: string;
    sshKey?: string;
    keyPassword?: string;
    authType?: string;
    credentialId?: number;
    userId?: string;
    forceKeyboardInteractive?: boolean;
    useSocks5?: boolean;
    socks5Host?: string;
    socks5Port?: number;
    socks5Username?: string;
    socks5Password?: string;
    socks5ProxyChain?: unknown;
    jumpHosts?: Array<{ hostId: number }>;
  },
): Promise<SSHConnectResult> {
  try {
    const response = await getFileManagerApiForSession(sessionId).post(
      "/ssh/connect",
      { sessionId, ...config },
      { timeout: 120000 },
    );
    return response.data;
  } catch (error: unknown) {
    if (
      axios.isAxiosError<ConnectErrorResponse>(error) &&
      error.response?.data?.connectionLogs
    ) {
      const data = error.response.data;
      const errorWithLogs = new Error(
        data.error || data.message || error.message,
      );
      Object.assign(errorWithLogs, {
        connectionLogs: data.connectionLogs,
      });
      if (data.requires_totp) {
        Object.assign(errorWithLogs, {
          requires_totp: true,
          sessionId: data.sessionId,
          prompt: data.prompt,
        });
      }
      if (data.requires_warpgate) {
        Object.assign(errorWithLogs, {
          requires_warpgate: true,
          sessionId: data.sessionId,
          url: data.url,
          securityKey: data.securityKey,
        });
      }
      if (data.status === "auth_required") {
        Object.assign(errorWithLogs, {
          status: "auth_required",
          reason: data.reason,
        });
      }
      throw errorWithLogs;
    }
    handleApiError(error, "connect SSH");
  }
}

export async function disconnectSSH(
  sessionId: string,
): Promise<Record<string, unknown>> {
  try {
    const response = await getFileManagerApiForSession(sessionId).post(
      "/ssh/disconnect",
      { sessionId },
    );
    return response.data;
  } catch (error) {
    handleApiError(error, "disconnect SSH");
  } finally {
    clearSessionOrigin(sessionId);
  }
}

export async function verifySSHTOTP(
  sessionId: string,
  totpCode: string,
): Promise<Record<string, unknown>> {
  try {
    const response = await getFileManagerApiForSession(sessionId).post(
      "/ssh/connect-totp",
      { sessionId, totpCode },
    );
    return response.data;
  } catch (error) {
    handleApiError(error, "verify SSH TOTP");
  }
}

export async function verifySSHWarpgate(
  sessionId: string,
): Promise<Record<string, unknown>> {
  try {
    const response = await getFileManagerApiForSession(sessionId).post(
      "/ssh/connect-warpgate",
      { sessionId },
    );
    return response.data;
  } catch (error) {
    handleApiError(error, "verify SSH Warpgate");
  }
}

/**
 * @openapi
 * /ssh/quick-connect:
 *   post:
 *     summary: Create a temporary SSH connection without saving to database
 *     description: Returns a temporary host configuration for immediate use
 *     tags:
 *       - SSH
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required:
 *               - ip
 *               - port
 *               - username
 *               - authType
 *             properties:
 *               ip:
 *                 type: string
 *                 description: SSH server IP or hostname
 *               port:
 *                 type: number
 *                 description: SSH server port
 *               username:
 *                 type: string
 *                 description: SSH username
 *               authType:
 *                 type: string
 *                 enum: [password, key, credential]
 *                 description: Authentication method
 *               password:
 *                 type: string
 *                 description: Password (required if authType is password)
 *               key:
 *                 type: string
 *                 description: SSH private key (required if authType is key)
 *               keyPassword:
 *                 type: string
 *                 description: SSH key password (optional)
 *               keyType:
 *                 type: string
 *                 description: SSH key type
 *               credentialId:
 *                 type: number
 *                 description: Credential ID (required if authType is credential)
 *               overrideCredentialUsername:
 *                 type: boolean
 *                 description: Use provided username instead of credential username
 *     responses:
 *       200:
 *         description: Temporary host configuration created successfully
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               description: SSHHost object
 *       400:
 *         description: Invalid request data
 *       401:
 *         description: Unauthorized
 *       500:
 *         description: Server error
 */
export async function quickConnect(
  data: Record<string, unknown>,
): Promise<SSHHost> {
  try {
    const response = await authApi.post("/host/quick-connect", data);
    return response.data;
  } catch (error) {
    throw handleApiError(error, "quick connect");
  }
}

export async function getSSHStatus(
  sessionId: string,
): Promise<{ connected: boolean }> {
  try {
    const response = await getFileManagerApiForSession(sessionId).get(
      "/ssh/status",
      { params: { sessionId } },
    );
    return response.data;
  } catch (error) {
    handleApiError(error, "get SSH status");
  }
}

export async function keepSSHAlive(
  sessionId: string,
): Promise<Record<string, unknown>> {
  try {
    const response = await getFileManagerApiForSession(sessionId).post(
      "/ssh/keepalive",
      { sessionId },
    );
    return response.data;
  } catch (error) {
    handleApiError(error, "SSH keepalive");
  }
}

export async function listSSHFiles(
  sessionId: string,
  path: string,
  options: { force?: boolean } = {},
): Promise<{ files: FileItem[]; path: string }> {
  return getCachedFileList(
    sessionId,
    path,
    async () => {
      try {
        const response = await getFileManagerApiForSession(sessionId).get(
          "/ssh/listFiles",
          { params: { sessionId, path } },
        );
        return response.data || { files: [], path };
      } catch (error) {
        handleApiError(error, "list SSH files");
      }
    },
    options.force,
  );
}

export async function identifySSHSymlink(
  sessionId: string,
  path: string,
): Promise<{ path: string; target: string; type: "directory" | "file" }> {
  try {
    const response = await getFileManagerApiForSession(sessionId).get(
      "/ssh/identifySymlink",
      { params: { sessionId, path } },
    );
    return response.data;
  } catch (error) {
    handleApiError(error, "identify SSH symlink");
  }
}

export async function resolveSSHPath(
  sessionId: string,
  path: string,
): Promise<string> {
  try {
    const response = await getFileManagerApiForSession(sessionId).get(
      "/ssh/resolvePath",
      { params: { sessionId, path } },
    );
    return response.data?.resolvedPath || path;
  } catch {
    return path;
  }
}

export async function readSSHFile(
  sessionId: string,
  path: string,
  options: { force?: boolean } = {},
): Promise<FileContentResult> {
  return getCachedFileContent(
    sessionId,
    path,
    async () => {
      try {
        const response = await getFileManagerApiForSession(sessionId).get(
          "/ssh/readFile",
          { params: { sessionId, path } },
        );
        return response.data;
      } catch (error: unknown) {
        const httpError = asHttpError(error);
        if (httpError.response?.status === 404) {
          const customError = new Error("File not found");
          (
            customError as Error & {
              response?: unknown;
              isFileNotFound?: boolean;
            }
          ).response = httpError.response;
          (
            customError as Error & {
              response?: unknown;
              isFileNotFound?: boolean;
            }
          ).isFileNotFound = httpError.response.data?.fileNotFound || true;
          throw customError;
        }
        handleApiError(error, "read SSH file");
      }
    },
    options.force,
  );
}

export async function writeSSHFile(
  sessionId: string,
  path: string,
  content: string,
  hostId?: number,
  userId?: string,
): Promise<Record<string, unknown>> {
  try {
    const response = await getFileManagerApiForSession(sessionId).post(
      "/ssh/writeFile",
      { sessionId, path, content, hostId, userId },
    );

    if (
      response.data &&
      (response.data.message === "File written successfully" ||
        response.status === 200)
    ) {
      invalidateCachedFileContent(sessionId, path);
      return response.data;
    } else {
      throw new Error("File write operation did not return success status");
    }
  } catch (error) {
    handleApiError(error, "write SSH file");
  }
}

export async function uploadSSHFile(
  sessionId: string,
  path: string,
  fileName: string,
  file: File,
  hostId?: number,
  userId?: string,
  onChunkProgress?: (progress: {
    chunkIndex: number;
    totalChunks: number;
    bytesSent: number;
    totalBytes: number;
  }) => void,
): Promise<Record<string, unknown>> {
  // Browser-side safety: any single multipart body approaching 2^31 bytes (~2.14GB)
  // crashes the XHR/ArrayBuffer pipeline in both Chromium (Electron) and Firefox,
  // surfacing as "DOMException: File could not be read" inside FileManager-*.js.
  // For larger files we slice into <=8MB chunks and upload each one separately,
  // never materializing the whole file in JS memory.
  const CHUNK_THRESHOLD_BYTES = 1.5 * 1024 * 1024 * 1024; // 1.5 GiB
  const CHUNK_SIZE_BYTES = 8 * 1024 * 1024; // 8 MiB

  try {
    if (file.size > CHUNK_THRESHOLD_BYTES) {
      const totalChunks = Math.ceil(file.size / CHUNK_SIZE_BYTES);
      fileLogger.info("Starting chunked upload", {
        operation: "file_upload_chunked_start",
        fileName,
        fileSize: file.size,
        totalChunks,
        chunkSize: CHUNK_SIZE_BYTES,
      });

      let bytesSent = 0;
      for (let i = 0; i < totalChunks; i++) {
        const start = i * CHUNK_SIZE_BYTES;
        const end = Math.min(start + CHUNK_SIZE_BYTES, file.size);
        const chunkBlob = file.slice(start, end);

        const form = new FormData();
        form.append("sessionId", sessionId);
        form.append("path", path);
        form.append("fileName", fileName);
        form.append("chunkIndex", String(i));
        form.append("totalChunks", String(totalChunks));
        form.append("totalSize", String(file.size));
        form.append("chunk", chunkBlob, fileName);

        const response = await getFileManagerApiForSession(sessionId).postForm(
          "/ssh/uploadFileChunk",
          form,
          { timeout: 0 },
        );

        bytesSent = end;
        onChunkProgress?.({
          chunkIndex: i,
          totalChunks,
          bytesSent,
          totalBytes: file.size,
        });

        if (i === totalChunks - 1) {
          fileLogger.success("Chunked upload completed", {
            operation: "file_upload_chunked_complete",
            fileName,
            fileSize: file.size,
            totalChunks,
          });
          return response.data;
        }
      }
      return { message: "File uploaded successfully", chunked: true };
    }

    const form = new FormData();
    form.append("sessionId", sessionId);
    form.append("path", path);
    if (hostId !== undefined) form.append("hostId", String(hostId));
    if (userId !== undefined) form.append("userId", userId);
    form.append("file", file, fileName);

    const response = await getFileManagerApiForSession(sessionId).postForm(
      "/ssh/uploadFileStream",
      form,
      {
        timeout: 0,
      },
    );
    return response.data;
  } catch (error) {
    handleApiError(error, "upload SSH file");
  }
}

export interface DownloadedSSHFile {
  /** base64-encoded file contents */
  content: string;
  fileName: string;
  size: number;
  mimeType: string;
  path: string;
}

export async function downloadSSHFile(
  sessionId: string,
  filePath: string,
  hostId?: number,
  userId?: string,
): Promise<DownloadedSSHFile> {
  try {
    const response = await getFileManagerApiForSession(sessionId).post(
      "/ssh/downloadFile",
      {
        sessionId,
        path: filePath,
        hostId,
        userId,
      },
      { timeout: 0 },
    );
    return response.data;
  } catch (error) {
    handleApiError(error, "download SSH file");
  }
}

export interface DownloadProgressEvent {
  loaded: number;
  total?: number;
}

export async function downloadSSHFileStream(
  sessionId: string,
  filePath: string,
  onProgress?: (event: DownloadProgressEvent) => void,
): Promise<void> {
  const response = await getFileManagerApiForSession(sessionId).post(
    "/ssh/downloadFileStream",
    { sessionId, path: filePath },
    {
      responseType: "blob",
      timeout: 0,
      onDownloadProgress: onProgress
        ? (event) => onProgress({ loaded: event.loaded, total: event.total })
        : undefined,
    },
  );
  const blob = response.data as Blob;
  const fileName = filePath.split("/").pop() || "download";
  triggerBlobDownload(blob, fileName);
}

export async function createSSHFile(
  sessionId: string,
  path: string,
  fileName: string,
  content: string = "",
  hostId?: number,
  userId?: string,
): Promise<Record<string, unknown>> {
  try {
    const response = await getFileManagerApiForSession(sessionId).post(
      "/ssh/createFile",
      { sessionId, path, fileName, content, hostId, userId },
    );
    return response.data;
  } catch (error) {
    handleApiError(error, "create SSH file");
  }
}

export async function createSSHFolder(
  sessionId: string,
  path: string,
  folderName: string,
  hostId?: number,
  userId?: string,
): Promise<Record<string, unknown>> {
  try {
    const response = await getFileManagerApiForSession(sessionId).post(
      "/ssh/createFolder",
      { sessionId, path, folderName, hostId, userId },
    );
    return response.data;
  } catch (error) {
    handleApiError(error, "create SSH folder");
  }
}

export async function deleteSSHItem(
  sessionId: string,
  path: string,
  isDirectory: boolean,
  hostId?: number,
  userId?: string,
  permanent = false,
): Promise<Record<string, unknown>> {
  try {
    const response = await getFileManagerApiForSession(sessionId).delete(
      "/ssh/deleteItem",
      {
        data: {
          sessionId,
          path,
          isDirectory,
          hostId,
          userId,
          permanent,
        },
      },
    );
    if (!isDirectory) invalidateCachedFileContent(sessionId, path);
    return response.data;
  } catch (error) {
    if (
      axios.isAxiosError(error) &&
      error.response?.data?.trashUnavailable === true
    ) {
      throw error;
    }
    handleApiError(error, "delete SSH item");
  }
}

export interface TrashItem {
  id: string;
  name: string;
  originalPath: string;
  isDirectory: boolean;
  deletedAt: string;
  size: number;
}

export async function getSSHTrash(sessionId: string): Promise<{
  items: TrashItem[];
  retentionDays: number;
  canManageRetention: boolean;
}> {
  try {
    const response = await getFileManagerApiForSession(sessionId).get(
      "/ssh/trash",
      { params: { sessionId } },
    );
    return response.data;
  } catch (error) {
    handleApiError(error, "list SSH trash");
  }
}

export async function restoreSSHTrashItem(sessionId: string, id: string) {
  try {
    const response = await getFileManagerApiForSession(sessionId).post(
      `/ssh/trash/${encodeURIComponent(id)}/restore`,
      { sessionId },
    );
    return response.data;
  } catch (error) {
    handleApiError(error, "restore SSH trash item");
  }
}

export async function permanentlyDeleteSSHTrashItem(
  sessionId: string,
  id: string,
) {
  try {
    await getFileManagerApiForSession(sessionId).delete(
      `/ssh/trash/${encodeURIComponent(id)}`,
      { data: { sessionId } },
    );
  } catch (error) {
    handleApiError(error, "permanently delete SSH trash item");
  }
}

export async function emptySSHTrash(sessionId: string) {
  try {
    await getFileManagerApiForSession(sessionId).delete("/ssh/trash", {
      data: { sessionId },
    });
  } catch (error) {
    handleApiError(error, "empty SSH trash");
  }
}

export async function updateSSHTrashRetention(
  sessionId: string,
  retentionDays: number,
) {
  try {
    await getFileManagerApiForSession(sessionId).put("/ssh/trash-retention", {
      retentionDays,
    });
  } catch (error) {
    handleApiError(error, "update SSH trash retention");
  }
}

export async function setSudoPassword(
  sessionId: string,
  password: string,
): Promise<void> {
  try {
    await getFileManagerApiForSession(sessionId).post("/sudo-password", {
      sessionId,
      password,
    });
  } catch (error) {
    handleApiError(error, "set sudo password");
  }
}

export interface CopySSHItemResult {
  message?: string;
  /** Set when the copy was renamed to avoid clobbering an existing entry. */
  uniqueName?: string;
  targetPath?: string;
}

export async function copySSHItem(
  sessionId: string,
  sourcePath: string,
  targetDir: string,
  hostId?: number,
  userId?: string,
): Promise<CopySSHItemResult> {
  try {
    const response = await getFileManagerApiForSession(sessionId).post(
      "/ssh/copyItem",
      {
        sessionId,
        sourcePath,
        targetDir,
        hostId,
        userId,
      },
      {
        timeout: 60000,
      },
    );
    return response.data;
  } catch (error) {
    handleApiError(error, "copy SSH item");
    throw error;
  }
}

export async function renameSSHItem(
  sessionId: string,
  oldPath: string,
  newName: string,
  hostId?: number,
  userId?: string,
): Promise<Record<string, unknown>> {
  try {
    const response = await getFileManagerApiForSession(sessionId).put(
      "/ssh/renameItem",
      { sessionId, oldPath, newName, hostId, userId },
    );
    invalidateCachedFileContent(sessionId, oldPath);
    const separator = oldPath.lastIndexOf("/");
    const newPath = `${oldPath.slice(0, separator + 1)}${newName}`;
    invalidateCachedFileContent(sessionId, newPath);
    return response.data;
  } catch (error) {
    handleApiError(error, "rename SSH item");
    throw error;
  }
}

export async function moveSSHItem(
  sessionId: string,
  oldPath: string,
  newPath: string,
  hostId?: number,
  userId?: string,
): Promise<Record<string, unknown>> {
  try {
    const response = await getFileManagerApiForSession(sessionId).put(
      "/ssh/moveItem",
      {
        sessionId,
        oldPath,
        newPath,
        hostId,
        userId,
      },
      {
        timeout: 60000,
      },
    );
    invalidateCachedFileContent(sessionId, oldPath);
    invalidateCachedFileContent(sessionId, newPath);
    return response.data;
  } catch (error) {
    handleApiError(error, "move SSH item");
    throw error;
  }
}

export async function changeSSHPermissions(
  sessionId: string,
  path: string,
  permissions: string,
  hostId?: number,
  userId?: string,
): Promise<{ success: boolean; message: string }> {
  try {
    fileLogger.info("Changing SSH file permissions", {
      operation: "change_permissions",
      sessionId,
      path,
      permissions,
      hostId,
      userId,
    });

    const response = await getFileManagerApiForSession(sessionId).post(
      "/ssh/changePermissions",
      { sessionId, path, permissions, hostId, userId },
    );

    fileLogger.success("SSH file permissions changed successfully", {
      operation: "change_permissions",
      sessionId,
      path,
      permissions,
    });

    return response.data;
  } catch (error) {
    fileLogger.error("Failed to change SSH file permissions", error, {
      operation: "change_permissions",
      sessionId,
      path,
      permissions,
    });
    handleApiError(error, "change SSH permissions");
    throw error;
  }
}

export async function extractSSHArchive(
  sessionId: string,
  archivePath: string,
  extractPath?: string,
  hostId?: number,
  userId?: string,
): Promise<{ success: boolean; message: string; extractPath: string }> {
  try {
    fileLogger.info("Extracting archive", {
      operation: "extract_archive",
      sessionId,
      archivePath,
      extractPath,
      hostId,
      userId,
    });

    const response = await getFileManagerApiForSession(sessionId).post(
      "/ssh/extractArchive",
      { sessionId, archivePath, extractPath, hostId, userId },
    );

    fileLogger.success("Archive extracted successfully", {
      operation: "extract_archive",
      sessionId,
      archivePath,
      extractPath: response.data.extractPath,
    });

    return response.data;
  } catch (error) {
    fileLogger.error("Failed to extract archive", error, {
      operation: "extract_archive",
      sessionId,
      archivePath,
      extractPath,
    });
    handleApiError(error, "extract archive");
    throw error;
  }
}

export async function compressSSHFiles(
  sessionId: string,
  paths: string[],
  archiveName: string,
  format?: string,
  hostId?: number,
  userId?: string,
): Promise<{ success: boolean; message: string; archivePath: string }> {
  try {
    fileLogger.info("Compressing files", {
      operation: "compress_files",
      sessionId,
      paths,
      archiveName,
      format,
      hostId,
      userId,
    });

    const response = await getFileManagerApiForSession(sessionId).post(
      "/ssh/compressFiles",
      {
        sessionId,
        paths,
        archiveName,
        format: format || "zip",
        hostId,
        userId,
      },
    );

    fileLogger.success("Files compressed successfully", {
      operation: "compress_files",
      sessionId,
      paths,
      archivePath: response.data.archivePath,
    });

    return response.data;
  } catch (error) {
    fileLogger.error("Failed to compress files", error, {
      operation: "compress_files",
      sessionId,
      paths,
      archiveName,
      format,
    });
    handleApiError(error, "compress files");
    throw error;
  }
}

// ============================================================================

export type HostConnectionState =
  "disconnected" | "connecting" | "ready" | "auth_required" | "error";

export interface EnsureSSHSessionResult {
  state: HostConnectionState;
  sessionId?: string;
  error?: string;
}

export async function ensureSSHSessionForHost(
  host: SSHHost,
): Promise<EnsureSSHSessionResult> {
  const sessionId = host.id.toString();
  const origin = await resolveConnectionOrigin({
    connectionType: host.connectionType,
    connectionOrigin: host.connectionOrigin,
  });
  setSessionOrigin(sessionId, origin);

  try {
    const status = await getSSHStatus(sessionId);
    if (status?.connected) {
      return { state: "ready", sessionId };
    }
  } catch {
    // not connected — fall through to connect
  }

  try {
    const result = await connectSSH(sessionId, {
      hostId: host.id,
      syncId: host.syncId ?? null,
      ip: host.ip,
      port: host.port,
      username: host.username,
      password: host.password,
      sshKey: host.key,
      keyPassword: host.keyPassword,
      authType: host.authType,
      credentialId: host.credentialId,
      userId: host.userId,
      forceKeyboardInteractive: host.forceKeyboardInteractive,
      jumpHosts: host.jumpHosts,
      useSocks5: host.useSocks5,
      socks5Host: host.socks5Host,
      socks5Port: host.socks5Port,
      socks5Username: host.socks5Username,
      socks5Password: host.socks5Password,
      socks5ProxyChain: host.socks5ProxyChain,
    });

    if (
      result?.requires_totp ||
      result?.requires_warpgate ||
      result?.status === "auth_required"
    ) {
      return { state: "auth_required", sessionId };
    }

    return { state: "ready", sessionId };
  } catch (err) {
    const message = getErrorMessage(err, "Connection failed");
    return { state: "error", error: message };
  }
}

export interface BrowseSSHDirectoryResult {
  status: "ok" | "not_found" | "error";
  path: string;
  files: Array<{ name: string; type: "file" | "directory" | "link" }>;
}

export async function browseSSHDirectory(
  sessionId: string,
  path: string,
): Promise<BrowseSSHDirectoryResult> {
  try {
    const result = await listSSHFiles(sessionId, path);
    return {
      status: "ok",
      path: result.path,
      files: result.files as Array<{
        name: string;
        type: "file" | "directory" | "link";
      }>,
    };
  } catch (err) {
    const status =
      (err as { response?: { status?: number } })?.response?.status === 404
        ? "not_found"
        : "error";
    return { status, path, files: [] };
  }
}
