import { StorageFolder } from "../interfaces/storage-fs";
import * as Minio from "minio";
import minioClient from "../minio";

/**
 * Replace illegal character eg. ? % < > / \ : | that can't be in path with other char with dash by default.
 * @param path - string to check and replace
 * @param replace - string to replace illegal character
 * @returns illegal character replaced path
 */
export function replaceIllegalChars(path: string, replace = "-") {
  return path.replace(/[/\\?%*:|"<>#]/g, replace).trim();
}

/**
 * Check if folder really exist by using ".keep" object.
 */
export async function pathExist(bucket: string, path: string): Promise<boolean> {
  return Boolean(
    await minioClient.statObject(bucket, `${path.replace(/^\/|\/$/g, "")}/.keep`).catch((e) => {
      if (e.code === "NotFound") return false;
      throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์");
    }),
  );
}

/**
 * Utility function to list folder by using .keep file with prefix in minio.
 * @param path - path to list
 * @return list of folder with metadata
 */
export async function listFolder(bucket: string, path?: string): Promise<StorageFolder[]> {
  if (path) path = `${path.replace(/^\/|\/$/g, "")}/`;

  const list = await new Promise<{ pathname: string; name: string }[]>((resolve, reject) => {
    const item: { pathname: string; name: string }[] = [];

    const stream = minioClient.listObjectsV2(bucket, path ?? "");
    stream.on("data", (v) => {
      if (v && v.prefix) {
        item.push({
          pathname: v.prefix,
          name: v.prefix.slice(path?.length).split("/")[0],
        });
      }
    });
    stream.on("end", () => resolve(item));
    stream.on("error", () => reject(new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์")));
  });

  const folder = await Promise.all(
    list.map(async (v) => {
      // Get stat from hidden object that used to mark as folder as minio doesn't really have folder
      const stat = await minioClient
        .statObject(bucket, `${v.pathname}.keep`)
        .catch((e) => console.error(`MinIO Error: ${e}`));

      if (!stat) return undefined;

      const { createdat, createdby } = stat.metaData;

      return {
        ...v,
        createdAt: createdat ?? "n/a",
        createdBy: createdby ?? "n/a",
      } satisfies StorageFolder;
    }),
  );

  return folder.filter((v: (typeof folder)[number]): v is StorageFolder => !!v);
}

export async function listItem(
  bucket: string,
  path: string,
  recursive = false,
): Promise<Minio.BucketItem[]> {
  return new Promise((resolve, reject) => {
    const stream = minioClient.listObjectsV2(bucket, path, recursive);
    const item: Minio.BucketItem[] = [];

    stream.on("data", (v) => {
      if (v && v.name) item.push(v);
    });
    stream.on("end", () => resolve(item));
    stream.on("error", () => reject(new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์")));
  });
}

export const copyCond = new Minio.CopyConditions();
