import { ReactiveCache } from '/imports/reactiveCache';
import { ObjectID } from 'bson';
import DOMPurify from 'dompurify';

const filesize = require('filesize');
const prettyMilliseconds = require('pretty-ms');

// We store current card ID and the ID of currently opened attachment in a
// global var. This is used so that we know what's the next attachment to open
// when the user clicks on the prev/next button in the attachment viewer.
let cardId = null;
let openAttachmentId = null;


// Stores link to the attachment for which attachment actions popup was opened
attachmentActionsLink = null;

Template.attachmentGallery.events({
  'click .open-preview'(event) {

    openAttachmentId = $(event.currentTarget).attr("data-attachment-id");
    cardId = $(event.currentTarget).attr("data-card-id");

    openAttachmentViewer(openAttachmentId);
  },
  'click .js-add-attachment': Popup.open('cardAttachments'),
  // If we let this event bubble, FlowRouter will handle it and empty the page
  // content, see #101.
  'click .js-download'(event) {
    event.stopPropagation();
  },
  'click .js-open-attachment-menu': Popup.open('attachmentActions'),
  'mouseover .js-open-attachment-menu'(event) { // For some reason I cannot combine handlers for "click .js-open-attachment-menu" and "mouseover .js-open-attachment-menu" events so this is a quick workaround.
    attachmentActionsLink = event.currentTarget.getAttribute("data-attachment-link");
  },
  'click .js-rename': Popup.open('attachmentRename'),
  'click .js-confirm-delete': Popup.afterConfirm('attachmentDelete', function() {
    Attachments.remove(this._id);
    Popup.back(2);
  }),
});

function getNextAttachmentId(currentAttachmentId) {
    const attachments = ReactiveCache.getAttachments({'meta.cardId': cardId});

    let i = 0;
    for (; i < attachments.length; i++) {
      if (attachments[i]._id === currentAttachmentId) {
        break;
      }
    }
    return attachments[(i + 1 + attachments.length) % attachments.length]._id;
}

function getPrevAttachmentId(currentAttachmentId) {
  const attachments = ReactiveCache.getAttachments({'meta.cardId': cardId});

  let i = 0;
  for (; i < attachments.length; i++) {
    if (attachments[i]._id === currentAttachmentId) {
      break;
    }
  }
  return attachments[(i - 1 + attachments.length) % attachments.length]._id;
}

function openAttachmentViewer(attachmentId){

    const attachment = ReactiveCache.getAttachment(attachmentId);

    $("#attachment-name").text(attachment.name);

    // IMPORTANT: if you ever add a new viewer, make sure you also implement
    // cleanup in the closeAttachmentViewer() function
    switch(true){
      case (attachment.isImage):
        $("#image-viewer").attr("src", attachment.link());
        $("#image-viewer").removeClass("hidden");
        break;
      case (attachment.isPDF):
        $("#pdf-viewer").attr("data", attachment.link());
        $("#pdf-viewer").removeClass("hidden");
        break;
      case (attachment.isVideo):
        // We have to create a new <source> DOM element and append it to the video
        // element, otherwise the video won't load
        let videoSource = document.createElement('source');
        videoSource.setAttribute('src', attachment.link());
        $("#video-viewer").append(videoSource);

        $("#video-viewer").removeClass("hidden");
        break;
      case (attachment.isAudio):
        // We have to create a new <source> DOM element and append it to the audio
        // element, otherwise the audio won't load
        let audioSource = document.createElement('source');
        audioSource.setAttribute('src', attachment.link());
        $("#audio-viewer").append(audioSource);

        $("#audio-viewer").removeClass("hidden");
        break;
      case (attachment.isText):
      case (attachment.isJSON):
        $("#txt-viewer").attr("data", attachment.link());
        $("#txt-viewer").removeClass("hidden");
        break;
    }

    $("#viewer-overlay").removeClass("hidden");
}

function closeAttachmentViewer() {
  $("#viewer-overlay").addClass("hidden");

  // We need to reset the viewers to avoid showing previous attachments
  $("#image-viewer").attr("src", "");
  $("#image-viewer").addClass("hidden");

  $("#pdf-viewer").attr("data", "");
  $("#pdf-viewer").addClass("hidden");

  $("#txt-viewer").attr("data", "");
  $("#txt-viewer").addClass("hidden");

  $("#video-viewer").get(0).pause(); // Stop playback
  $("#video-viewer").get(0).currentTime = 0;
  $("#video-viewer").empty();
  $("#video-viewer").addClass("hidden");

  $("#audio-viewer").get(0).pause(); // Stop playback
  $("#audio-viewer").get(0).currentTime = 0;
  $("#audio-viewer").empty();
  $("#audio-viewer").addClass("hidden");
}

Template.attachmentViewer.events({
  'click #viewer-container'(event) {

    // Make sure the click was on #viewer-container and not on any of its children
    if(event.target !== event.currentTarget) return;

    closeAttachmentViewer();
  },
  'click #viewer-content'(event) {

    // Make sure the click was on #viewer-content and not on any of its children
    if(event.target !== event.currentTarget) return;

    closeAttachmentViewer();
  },
  'click #viewer-close'() {
    closeAttachmentViewer();
  },
  'click #next-attachment'(event) {
    closeAttachmentViewer()
    const id = getNextAttachmentId(openAttachmentId);
    openAttachmentId = id;
    openAttachmentViewer(id);
  },
  'click #prev-attachment'(event) {
    closeAttachmentViewer()
    const id = getPrevAttachmentId(openAttachmentId);
    openAttachmentId = id;
    openAttachmentViewer(id);
  }
});

Template.attachmentGallery.helpers({
  isBoardAdmin() {
    return ReactiveCache.getCurrentUser().isBoardAdmin();
  },
  fileSize(size) {
    const ret = filesize(size);
    return ret;
  },
  sanitize(value) {
    return DOMPurify.sanitize(value);
  },
});

Template.cardAttachmentsPopup.onCreated(function() {
  this.uploads = new ReactiveVar([]);
});

Template.cardAttachmentsPopup.helpers({
  getEstimateTime(upload) {
    const ret = prettyMilliseconds(upload.estimateTime.get());
    return ret;
  },
  getEstimateSpeed(upload) {
    const ret = filesize(upload.estimateSpeed.get(), {round: 0}) + "/s";
    return ret;
  },
  uploads() {
    return Template.instance().uploads.get();
  }
});

Template.cardAttachmentsPopup.events({
  'change .js-attach-file'(event, templateInstance) {
    const card = this;
    const files = event.currentTarget.files;
    if (files) {
      let uploads = [];
      for (const file of files) {
        const fileId = new ObjectID().toString();
        // If filename is not same as sanitized filename, has XSS, then cancel upload
        if (file.name !== DOMPurify.sanitize(file.name)) {
          return false;
        }
        const config = {
          file: file,
          fileId: fileId,
          meta: Utils.getCommonAttachmentMetaFrom(card),
          chunkSize: 'dynamic',
        };
        config.meta.fileId = fileId;
        const uploader = Attachments.insert(
          config,
          false,
        );
        uploader.on('start', function() {
          uploads.push(this);
          templateInstance.uploads.set(uploads);
        });
        uploader.on('uploaded', (error, fileRef) => {
          if (!error) {
            if (fileRef.isImage) {
              card.setCover(fileRef._id);
            }
          }
        });
        uploader.on('end', (error, fileRef) => {
          uploads = uploads.filter(_upload => _upload.config.fileId != fileRef._id);
          templateInstance.uploads.set(uploads);
          if (uploads.length == 0 ) {
            Popup.back();
          }
        });
        uploader.start();
      }
    }
  },
  'click .js-computer-upload'(event, templateInstance) {
    templateInstance.find('.js-attach-file').click();
    event.preventDefault();
  },
  'click .js-upload-clipboard-image': Popup.open('previewClipboardImage'),
});

const MAX_IMAGE_PIXEL = Utils.MAX_IMAGE_PIXEL;
const COMPRESS_RATIO = Utils.IMAGE_COMPRESS_RATIO;
let pastedResults = null;

Template.previewClipboardImagePopup.onRendered(() => {
  // we can paste image from clipboard
  const handle = results => {
    if (results.dataURL.startsWith('data:image/')) {
      const direct = results => {
        $('img.preview-clipboard-image').attr('src', results.dataURL);
        pastedResults = results;
      };
      if (MAX_IMAGE_PIXEL) {
        // if has size limitation on image we shrink it before uploading
        Utils.shrinkImage({
          dataurl: results.dataURL,
          maxSize: MAX_IMAGE_PIXEL,
          ratio: COMPRESS_RATIO,
          callback(changed) {
            if (changed !== false && !!changed) {
              results.dataURL = changed;
            }
            direct(results);
          },
        });
      } else {
        direct(results);
      }
    }
  };

  $(document.body).pasteImageReader(handle);

  // we can also drag & drop image file to it
  $(document.body).dropImageReader(handle);
});

Template.previewClipboardImagePopup.events({
  'click .js-upload-pasted-image'() {
    const card = this;
    if (pastedResults && pastedResults.file) {
      const file = pastedResults.file;
      window.oPasted = pastedResults;
      const fileId = new ObjectID().toString();
      const config = {
        file,
        fileId: fileId,
        meta: Utils.getCommonAttachmentMetaFrom(card),
        fileName: file.name || file.type.replace('image/', 'clipboard.'),
        chunkSize: 'dynamic',
      };
      config.meta.fileId = fileId;
      const uploader = Attachments.insert(
        config,
        false,
      );
      uploader.on('uploaded', (error, fileRef) => {
        if (!error) {
          if (fileRef.isImage) {
            card.setCover(fileRef._id);
          }
        }
      });
      uploader.on('end', (error, fileRef) => {
        pastedResults = null;
        $(document.body).pasteImageReader(() => {});
        Popup.back();
      });
      uploader.start();
    }
  },
});

BlazeComponent.extendComponent({
  isCover() {
    const ret = ReactiveCache.getCard(this.data().meta.cardId).coverId == this.data()._id;
    return ret;
  },
  isBackgroundImage() {
    //const currentBoard = Utils.getCurrentBoard();
    //return currentBoard.backgroundImageURL === $(".attachment-thumbnail-img").attr("src");
    return false;
  },
  events() {
    return [
      {
        'click .js-add-cover'() {
          ReactiveCache.getCard(this.data().meta.cardId).setCover(this.data()._id);
          Popup.back();
        },
        'click .js-remove-cover'() {
          ReactiveCache.getCard(this.data().meta.cardId).unsetCover();
          Popup.back();
        },
        'click .js-add-background-image'() {
          const currentBoard = Utils.getCurrentBoard();
          currentBoard.setBackgroundImageURL(attachmentActionsLink);
          Utils.setBackgroundImage(attachmentActionsLink);
          Popup.back();
          event.preventDefault();
        },
        'click .js-remove-background-image'() {
          const currentBoard = Utils.getCurrentBoard();
          currentBoard.setBackgroundImageURL("");
          Utils.setBackgroundImage("");
          Popup.back();
          Utils.reload();
          event.preventDefault();
        },
        'click .js-move-storage-fs'() {
          Meteor.call('moveAttachmentToStorage', this.data()._id, "fs");
          Popup.back();
        },
        'click .js-move-storage-gridfs'() {
          Meteor.call('moveAttachmentToStorage', this.data()._id, "gridfs");
          Popup.back();
        },
        'click .js-move-storage-s3'() {
          Meteor.call('moveAttachmentToStorage', this.data()._id, "s3");
          Popup.back();
        },
      }
    ]
  }
}).register('attachmentActionsPopup');

BlazeComponent.extendComponent({
  getNameWithoutExtension() {
    const ret = this.data().name.replace(new RegExp("\." + this.data().extension + "$"), "");
    return ret;
  },
  events() {
    return [
      {
        'keydown input.js-edit-attachment-name'(evt) {
          // enter = save
          if (evt.keyCode === 13) {
            this.find('button[type=submit]').click();
          }
        },
        'click button.js-submit-edit-attachment-name'(event) {
          // save button pressed
          event.preventDefault();
          const name = this.$('.js-edit-attachment-name')[0]
            .value
            .trim() + this.data().extensionWithDot;
          if (name === DOMPurify.sanitize(name)) {
            Meteor.call('renameAttachment', this.data()._id, name);
          }
          Popup.back(2);
        },
      }
    ]
  }
}).register('attachmentRenamePopup');
