export function isExecutableFile(
  permissions: string,
  fileName: string,
): boolean {
  const hasExecutePermission =
    permissions[3] === "x" || permissions[6] === "x" || permissions[9] === "x";

  const scriptExtensions = [
    ".sh",
    ".py",
    ".pl",
    ".rb",
    ".js",
    ".php",
    ".bash",
    ".zsh",
    ".fish",
  ];
  const hasScriptExtension = scriptExtensions.some((ext) =>
    fileName.toLowerCase().endsWith(ext),
  );

  const executableExtensions = [".bin", ".exe", ".out"];
  const hasExecutableExtension = executableExtensions.some((ext) =>
    fileName.toLowerCase().endsWith(ext),
  );

  const hasNoExtension = !fileName.includes(".") && hasExecutePermission;

  return (
    hasExecutePermission &&
    (hasScriptExtension || hasExecutableExtension || hasNoExtension)
  );
}

export function modeToPermissions(mode: number): string {
  const S_IFDIR = 0o040000;
  const S_IFLNK = 0o120000;
  const S_IFMT = 0o170000;

  const type = mode & S_IFMT;
  const prefix = type === S_IFDIR ? "d" : type === S_IFLNK ? "l" : "-";

  const perms = [
    mode & 0o400 ? "r" : "-",
    mode & 0o200 ? "w" : "-",
    mode & 0o100 ? "x" : "-",
    mode & 0o040 ? "r" : "-",
    mode & 0o020 ? "w" : "-",
    mode & 0o010 ? "x" : "-",
    mode & 0o004 ? "r" : "-",
    mode & 0o002 ? "w" : "-",
    mode & 0o001 ? "x" : "-",
  ].join("");

  return prefix + perms;
}

export function parseLsDateToTimestamp(dateStr: string): number {
  const parts = dateStr.trim().split(/\s+/);
  if (parts.length < 3) return 0;

  const [month, day, timeOrYear] = parts;
  const monthIndex = [
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec",
  ].indexOf(month);
  if (monthIndex === -1) return 0;

  const dayNum = parseInt(day, 10);
  const now = new Date();

  if (timeOrYear.includes(":")) {
    const [hours, minutes] = timeOrYear.split(":").map(Number);
    let year = now.getFullYear();
    const candidate = new Date(year, monthIndex, dayNum, hours, minutes);
    if (candidate > now) year -= 1;
    return new Date(year, monthIndex, dayNum, hours, minutes).getTime() / 1000;
  }

  const year = parseInt(timeOrYear, 10);
  if (isNaN(year)) return 0;
  return new Date(year, monthIndex, dayNum).getTime() / 1000;
}

export function formatMtime(mtime: number): string {
  const date = new Date(mtime * 1000);
  const months = [
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec",
  ];
  const month = months[date.getMonth()];
  const day = date.getDate().toString().padStart(2, " ");
  const now = new Date();
  const sixMonthsAgo = new Date(now.getTime() - 180 * 24 * 60 * 60 * 1000);

  if (date > sixMonthsAgo) {
    const hours = date.getHours().toString().padStart(2, "0");
    const minutes = date.getMinutes().toString().padStart(2, "0");
    return `${month} ${day} ${hours}:${minutes}`;
  }
  return `${month} ${day}  ${date.getFullYear()}`;
}

export function getMimeType(fileName: string): string {
  const ext = fileName.split(".").pop()?.toLowerCase();
  const mimeTypes: Record<string, string> = {
    txt: "text/plain",
    json: "application/json",
    js: "text/javascript",
    html: "text/html",
    css: "text/css",
    png: "image/png",
    jpg: "image/jpeg",
    jpeg: "image/jpeg",
    gif: "image/gif",
    pdf: "application/pdf",
    zip: "application/zip",
    tar: "application/x-tar",
    gz: "application/gzip",
  };
  return mimeTypes[ext || ""] || "application/octet-stream";
}

export function detectBinary(buffer: Buffer): boolean {
  if (buffer.length === 0) return false;

  const sampleSize = Math.min(buffer.length, 8192);
  let nullBytes = 0;

  for (let i = 0; i < sampleSize; i++) {
    const byte = buffer[i];

    if (byte === 0) {
      nullBytes++;
    }

    if (byte < 32 && byte !== 9 && byte !== 10 && byte !== 13) {
      if (++nullBytes > 1) return true;
    }
  }

  return nullBytes / sampleSize > 0.01;
}
