import Resizer from "react-image-file-resizer";
import Axios from "axios";
import {
  UnsupportedFileTypeError,
  FileTooLargeError,
  uploadImage,
  uploadVideo,
  ImageTooSmallError,
} from "../utils/photo";
import { addCacheBusterParameter } from "./image";

export const getFileSizeWithUrl = (url: string): Promise<number> =>
  new Promise(async (resolve, reject) => {
    try {
      const file = await Axios.get(url);
      if (file) {
        resolve(Number(file.headers["content-length"]) || 0);
      }
    } catch (e) {
      console.log("getFileSizeWithUrl error:", e);
      reject(e);
    }
  });

export const getExtension = (filename: string) => {
  if (!filename) return;
  const parts = filename.split(".");
  return parts[parts.length - 1];
};

export const isImage = (filename: string) => {
  const ext = getExtension(filename);
  if (!ext) return;

  switch (ext.toLowerCase()) {
    case "jpg":
    case "jpeg":
    case "gif":
    case "bmp":
    case "png":
    case "webp":
      //etc
      return true;
  }
  return false;
};

export const isVideo = (filename: string) => {
  const ext = getExtension(filename);
  if (!ext) return;

  switch (ext.toLowerCase()) {
    case "m4v":
    case "avi":
    case "mpg":
    case "mp4":
    case "mov":
    case "quicktime":
      // etc
      return true;
  }
  return false;
};

export const isDocumentFile = (filename: string) => {
  const ext = getExtension(filename);
  if (!ext) return;

  switch (ext.toLowerCase()) {
    case "pdf":
      // etc
      return true;
  }
  return false;
};

export const isSoundFile = (filename: string) => {
  const ext = getExtension(filename);
  if (!ext) return;

  switch (ext.toLowerCase()) {
    case "mp3":
      // etc
      return true;
  }
  return false;
};

export const resizeFile = (file: any) =>
  new Promise<any>((resolve) => {
    Resizer.imageFileResizer(
      file,
      1440,
      1440,
      "JPEG",
      90,
      0,
      (uri) => {
        resolve(uri);
      },
      "blob"
    );
  });

export const humanFileSize = (bytes: any) => {
  if (bytes === 0) {
    return "0.00 B";
  }
  const e = Math.floor(Math.log(bytes) / Math.log(1024));
  return (
    (bytes / Math.pow(1024, e)).toFixed(2) + " " + " KMGTP".charAt(e) + "B"
  );
};
function validateDownloadSpeedParams(baseUrl: string, fileSizeInBytes: number) {
  if (typeof baseUrl !== "string") {
    throw new Error("baseUrl must be a string");
  }
  if (typeof fileSizeInBytes !== "number") {
    throw new Error("fileSizeInBytes must be a number");
  }
  return;
}

export function checkDownloadSpeed(baseUrl: string, fileSizeInBytes: number) {
  validateDownloadSpeedParams(baseUrl, fileSizeInBytes);
  return new Promise((resolve, reject) => {
    const download = new Image();
    download.onload = function () {
      const endTime = new Date().getTime();
      const duration = (endTime - startTime) / 1000;
      // Convert bytes into bits by multiplying with 8
      const bitsLoaded = fileSizeInBytes * 8;
      const bps: number = parseFloat((bitsLoaded / duration).toFixed(2));
      const kbps = parseFloat((bps / 1024).toFixed(2));
      const mbps = parseFloat((kbps / 1024).toFixed(2));
      resolve({ bps, kbps, mbps });
    };
    download.onerror = function (err, msg) {
      reject(null);
    };

    const startTime = new Date().getTime();
    const cacheBuster = "?nnn=" + startTime;
    download.src = baseUrl + cacheBuster;
  }).catch((error) => {
    throw new Error(error);
  });
}

export type MediaUploadedOutput = {
  src: string;
  originalFilename: string;
  thumbnailSrc?: string;
};

export async function uploadMedia(file: File): Promise<MediaUploadedOutput> {
  if (isVideo(file.name)) {
    const { thumbnail, playback } = await uploadVideo(file);

    return {
      thumbnailSrc: thumbnail,
      src: playback.iframe,
      originalFilename: file.name,
    };
  }

  if (isImage(file.name)) {
    const uploadedUrl = await uploadImage(file);

    return {
      src: uploadedUrl,
      originalFilename: file.name,
    };
  }

  throw new UnsupportedFileTypeError("Unsupported file type");
}

export const loadFileFromURL = async (
  url: string | Promise<string>,
  name: string
) => {
  try {
    const response = await fetch(addCacheBusterParameter(await url));
    const data = await response.blob();

    return new File([data], name, {
      type: data.type || "image/jpeg",
    });
  } catch (e) {
    console.error(e);
  }

  return undefined;
};

export const validateFile = async ({
  file,
  maxSizeInMB,
  minImageSize,
  validTypes,
}: {
  file: File;
  maxSizeInMB: number;
  minImageSize?: number;
  validTypes?: string[];
}) => {
  if (file.size > maxSizeInMB * 1024 * 1024) {
    throw new FileTooLargeError("File is too large");
  }

  if (validTypes && !validTypes.includes(file.type)) {
    throw new UnsupportedFileTypeError("Unsupported file type");
  }

  if (minImageSize && file.type.startsWith("image/")) {
    const image = await createImageBitmap(file);
    if (image.width < minImageSize || image.height < minImageSize) {
      throw new ImageTooSmallError(
        `Image dimensions must be at least ${minImageSize}x${minImageSize} pixels`
      );
    }
  }

  return file;
};
