import { set } from "lodash";
import loading from "@/components/Provider/Loading";
import { message } from "ant-design-vue";
export class UploadController {
  request: any;
  blobURLMaps = new Map<string, any>();
  constructor(request: any) {
    this.request = request;
  }
  getBlobURLName(url: string) {
    return this.blobURLMaps.get(url)?.name;
  }
  createObjectURL(obj: Blob): string {
    const url = URL.createObjectURL(obj);
    this.blobURLMaps.set(url, obj);
    return url;
  }
  revokeObjectURL(url: string) {
    URL.revokeObjectURL(url);
    this.blobURLMaps.delete(url);
  }
  selectFile(opts?: { accept?: string; multiple?: boolean }): Promise<File[]> {
    return new Promise((resolve, reject) => {
      const fileInput = document.createElement("input");
      fileInput.type = "file";
      fileInput.accept = opts?.accept || "images/*";
      fileInput.multiple = opts?.multiple || false;

      fileInput.onchange = function (this: any) {
        resolve([...this.files]);
      };

      window.addEventListener(
        "focus",
        () => {
          setTimeout(() => {
            reject(console.warn("select file cancel"));
          }, 300);
        },
        { once: true }
      );

      fileInput.click();
    });
  }
  async uploadBlobImages(data: object) {
    const todoMap = new Map<string, string>();
    addBlobToList(data);
    const todoList = todoMap.entries();

    let err = "";

    for (const item of todoList) {
      const [blobUrl, path] = item;
      const file = this.blobURLMaps.get(blobUrl);
      if (file) {
        const paths = path.split(",");
        loading.show("上传中");
        const ret = await this.uploadImage(file);
        if (ret.url) {
          paths.forEach((p) => {
            set(data, p, ret.url);
          });
          this.revokeObjectURL(blobUrl);
        } else {
          err = ret.error || `上传文件失败[${path}]`;
          break;
        }
      } else {
        err = `上传文件为空[${path}]`;
      }
    }
    loading.hidden();
    if (err) {
      message.error(err);
      throw err;
    }
    function addBlobToList(data: any, path = "") {
      if (data instanceof Object) {
        if (data instanceof Array) {
          data.forEach((item, i) => {
            addBlobToList(item, path ? path + "." + i : i.toString());
          });
        } else {
          Object.entries(data).forEach(([key, value]) => {
            addBlobToList(value, path ? path + "." + key : key);
          });
        }
      }
      if (typeof data === "string" && /^blob:/.test(data)) {
        if (todoMap.has(data)) {
          path = todoMap.get(data) + "," + path;
        }
        todoMap.set(data, path);
      }
    }
  }
  async uploadImage(file: File): Promise<{ url?: string; error?: string }> {
    const fromData = new FormData();
    fromData.append("image", file);
    try {
      const ret = await this.request("/upload/image", {
        method: "POST",
        data: fromData,
        headers: {
          "Content-Type": "multipart/form-data",
        },
      });
      if (ret.errorNo != 200) {
        return { error: "上传失败!" };
      }
      const url = ret.result.url;
      return { url };
    } catch (e) {
      return { error: "上传失败!" };
    }
  }
  async uploadFile(file: File): Promise<{ url?: string; error?: string }> {
    const fromData = new FormData();
    fromData.append("file", file);
    try {
      const ret = await this.request("/upload/file", {
        method: "POST",
        data: fromData,
        headers: {
          "Content-Type": "multipart/form-data",
        },
      });
      if (ret.errorNo != 200) {
        return { error: "上传失败!" };
      }
      const url = ret.result.url;
      return { url };
    } catch (e) {
      return { error: "上传失败!" };
    }
  }
  getFileExt(file: File) {
    let ext: any = "unkown";
    if (file) {
      const exp = /^.+\.(.+)$/;
      if (file.name && exp.test(file.name)) {
        ext = (exp.exec(file.name) as any)[1];
      } else if (file.type) {
        ext = file.type.split("/").pop();
      }
      return ext.toLowerCase();
    } else {
      return ext;
    }
  }
}
