import { isAppleDevice } from "discourse/lib/utilities";

function isGUID(value) {
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
    value
  );
}

export function markdownNameFromFileName(fileName) {
  let name = fileName.substr(0, fileName.lastIndexOf("."));

  if (isAppleDevice() && isGUID(name)) {
    name = I18n.t("upload_selector.default_image_alt_text");
  }

  return name.replace(/\[|\]|\|/g, "");
}

export function validateUploadedFiles(files, opts) {
  if (!files || files.length === 0) {
    return false;
  }

  if (files.length > 1) {
    bootbox.alert(I18n.t("post.errors.too_many_uploads"));
    return false;
  }

  const upload = files[0];

  // CHROME ONLY: if the image was pasted, sets its name to a default one
  if (typeof Blob !== "undefined" && typeof File !== "undefined") {
    if (
      upload instanceof Blob &&
      !(upload instanceof File) &&
      upload.type === "image/png"
    ) {
      upload.name = "image.png";
    }
  }

  opts = opts || {};
  opts.type = uploadTypeFromFileName(upload.name);

  return validateUploadedFile(upload, opts);
}

function validateUploadedFile(file, opts) {
  if (opts.skipValidation) return true;

  opts = opts || {};
  let user = opts.user;
  let staff = user && user.staff;

  if (!authorizesOneOrMoreExtensions(staff)) return false;

  const name = file && file.name;

  if (!name) {
    return false;
  }

  // check that the uploaded file is authorized
  if (opts.allowStaffToUploadAnyFileInPm && opts.isPrivateMessage) {
    if (staff) {
      return true;
    }
  }

  if (opts.imagesOnly) {
    if (!isImage(name) && !isAuthorizedImage(name, staff)) {
      bootbox.alert(
        I18n.t("post.errors.upload_not_authorized", {
          authorized_extensions: authorizedImagesExtensions(staff)
        })
      );
      return false;
    }
  } else if (opts.csvOnly) {
    if (!/\.csv$/i.test(name)) {
      bootbox.alert(I18n.t("user.invited.bulk_invite.error"));
      return false;
    }
  } else {
    if (!authorizesAllExtensions(staff) && !isAuthorizedFile(name, staff)) {
      bootbox.alert(
        I18n.t("post.errors.upload_not_authorized", {
          authorized_extensions: authorizedExtensions(staff)
        })
      );
      return false;
    }
  }

  if (!opts.bypassNewUserRestriction) {
    // ensures that new users can upload a file
    if (user && !user.isAllowedToUploadAFile(opts.type)) {
      bootbox.alert(
        I18n.t(`post.errors.${opts.type}_upload_not_allowed_for_new_user`)
      );
      return false;
    }
  }

  // everything went fine
  return true;
}

const IMAGES_EXTENSIONS_REGEX = /(png|jpe?g|gif|svg|ico)/i;

function extensionsToArray(exts) {
  return exts
    .toLowerCase()
    .replace(/[\s\.]+/g, "")
    .split("|")
    .filter(ext => ext.indexOf("*") === -1);
}

function extensions() {
  return extensionsToArray(Discourse.SiteSettings.authorized_extensions);
}

function staffExtensions() {
  return extensionsToArray(
    Discourse.SiteSettings.authorized_extensions_for_staff
  );
}

function imagesExtensions(staff) {
  let exts = extensions().filter(ext => IMAGES_EXTENSIONS_REGEX.test(ext));
  if (staff) {
    const staffExts = staffExtensions().filter(ext =>
      IMAGES_EXTENSIONS_REGEX.test(ext)
    );
    exts = _.union(exts, staffExts);
  }
  return exts;
}

function extensionsRegex() {
  return new RegExp("\\.(" + extensions().join("|") + ")$", "i");
}

function imagesExtensionsRegex(staff) {
  return new RegExp("\\.(" + imagesExtensions(staff).join("|") + ")$", "i");
}

function staffExtensionsRegex() {
  return new RegExp("\\.(" + staffExtensions().join("|") + ")$", "i");
}

function isAuthorizedFile(fileName, staff) {
  if (staff && staffExtensionsRegex().test(fileName)) {
    return true;
  }
  return extensionsRegex().test(fileName);
}

function isAuthorizedImage(fileName, staff) {
  return imagesExtensionsRegex(staff).test(fileName);
}

export function authorizedExtensions(staff) {
  const exts = staff ? [...extensions(), ...staffExtensions()] : extensions();
  return exts.filter(ext => ext.length > 0).join(", ");
}

function authorizedImagesExtensions(staff) {
  return authorizesAllExtensions(staff)
    ? "png, jpg, jpeg, gif, svg, ico"
    : imagesExtensions(staff).join(", ");
}

export function authorizesAllExtensions(staff) {
  return (
    Discourse.SiteSettings.authorized_extensions.indexOf("*") >= 0 ||
    (Discourse.SiteSettings.authorized_extensions_for_staff.indexOf("*") >= 0 &&
      staff)
  );
}

export function authorizesOneOrMoreExtensions(staff) {
  if (authorizesAllExtensions(staff)) return true;

  return (
    Discourse.SiteSettings.authorized_extensions.split("|").filter(ext => ext)
      .length > 0
  );
}

export function authorizesOneOrMoreImageExtensions(staff) {
  if (authorizesAllExtensions(staff)) return true;
  return imagesExtensions(staff).length > 0;
}

export function isImage(path) {
  return /\.(png|webp|jpe?g|gif|svg|ico)$/i.test(path);
}

export function isVideo(path) {
  return /\.(mov|mp4|webm|m4v|3gp|ogv|avi|mpeg|ogv)$/i.test(path);
}

export function isAudio(path) {
  return /\.(mp3|og[ga]|opus|wav|m4[abpr]|aac|flac)$/i.test(path);
}

function uploadTypeFromFileName(fileName) {
  return isImage(fileName) ? "image" : "attachment";
}

export function allowsImages(staff) {
  return (
    authorizesAllExtensions(staff) ||
    IMAGES_EXTENSIONS_REGEX.test(authorizedExtensions(staff))
  );
}

export function allowsAttachments(staff) {
  return (
    authorizesAllExtensions(staff) ||
    authorizedExtensions(staff).split(", ").length >
      imagesExtensions(staff).length
  );
}

export function uploadIcon(staff) {
  return allowsAttachments(staff) ? "upload" : "far-image";
}

function imageMarkdown(upload) {
  return `![${markdownNameFromFileName(upload.original_filename)}|${
    upload.thumbnail_width
  }x${upload.thumbnail_height}](${upload.short_url || upload.url})`;
}

function playableMediaMarkdown(upload, type) {
  return `![${markdownNameFromFileName(upload.original_filename)}|${type}](${
    upload.short_url
  })`;
}

function attachmentMarkdown(upload) {
  return `[${upload.original_filename}|attachment](${
    upload.short_url
  }) (${I18n.toHumanSize(upload.filesize)})`;
}

export function getUploadMarkdown(upload) {
  if (isImage(upload.original_filename)) {
    return imageMarkdown(upload);
  } else if (isAudio(upload.original_filename)) {
    return playableMediaMarkdown(upload, "audio");
  } else if (isVideo(upload.original_filename)) {
    return playableMediaMarkdown(upload, "video");
  } else {
    return attachmentMarkdown(upload);
  }
}

export function displayErrorForUpload(data) {
  if (data.jqXHR) {
    switch (data.jqXHR.status) {
      // cancelled by the user
      case 0:
        return;

      // entity too large, usually returned from the web server
      case 413:
        const type = uploadTypeFromFileName(data.files[0].name);
        const max_size_kb = Discourse.SiteSettings[`max_${type}_size_kb`];
        bootbox.alert(I18n.t("post.errors.file_too_large", { max_size_kb }));
        return;

      // the error message is provided by the server
      case 422:
        if (data.jqXHR.responseJSON.message) {
          bootbox.alert(data.jqXHR.responseJSON.message);
        } else {
          bootbox.alert(data.jqXHR.responseJSON.errors.join("\n"));
        }
        return;
    }
  } else if (data.errors && data.errors.length > 0) {
    bootbox.alert(data.errors.join("\n"));
    return;
  }
  // otherwise, display a generic error message
  bootbox.alert(I18n.t("post.errors.upload"));
}
