const getMenuCoordinates = (menu, pageX, pageY) => {
  const menuW = menu.width();
  const menuH = menu.height();
  const documentW = $(document).width();
  const documentH = $(document).height();
  const coordinates = {
    left: pageX,
    top: pageY
  };

  if((menuW + pageX) > documentW) coordinates.left = (documentW - menuW - 50);
  if((menuH + pageY) > documentH) coordinates.top = (documentH - menuH - 50);

  return coordinates;
}

const canEditFile = async (documentID) => {
  return new Promise(async resolve => {
    try {
      const {login, password} = Cons.creds;
      const auth = "Basic " + btoa(unescape(encodeURIComponent(`${login}:${password}`)));
      const url = `../Synergy/rest/api/storage/canEditFile?documentId=${documentID}`;
      const response = await fetch(url, {method: 'GET', headers: {"Authorization": auth}});

      if(!response.ok) throw new Error(await response.text());
      resolve(response.text());
    } catch (err) {
      console.log(`ERROR [ canEditFile ]: ${err.message}`);
      resolve(false);
    }
  });
}

this.DocumentAttachments = class {
  constructor(documentID, container, notEditable = false){
    this.documentID = documentID;
    this.container = container;
    this.notEditable = notEditable;
    this.attachmentFilesCount = 0;
    this.workFilesCount = 0;
    this.path = "ase:attachmentContainer";

    this.init();
  }

  tabTranslate(){
    const tabAttachName = `${i18n.tr("Приложения")} (${this.attachmentFilesCount})`;
    const tabWorkName = `${i18n.tr("Прочие")} (${this.workFilesCount})`;

    this.tabAttachmentContainer.find('a').text(tabAttachName);
    this.tabWorkContainer.find('a').text(tabWorkName);
  }

  getContextItemMenu(name, hoverColor, icon, handler) {
    return $(`<li><a style="--ic: ${hoverColor}" href="#"><span class="uk-margin-small-right" uk-icon="icon: ${icon}"></span>${i18n.tr(name)}</a></li>`)
    .on('click', e => {
      e.preventDefault();
      e.target.blur();
      handler();
    });
  }

  getContextMenu(li, item, type) {
    const {name, uuid} = item;
    const menu = $('<div>', {class: 'workflow-context-menu', style: `min-width: 200px;`});
    const ul = $('<ul class="uk-nav-default uk-nav-parent-icon" uk-nav>');

    const open = this.getContextItemMenu('Открыть', '#999', 'push', () => {
      this.container.trigger({type: 'file_context_open', eventParam: item});
    });

    const download = this.getContextItemMenu('Скачать', '#999', 'download', () => {
      Cons.showLoader();
      UTILS.fileDownload(name, uuid);
      Cons.hideLoader();
    });

    ul.append(open, download);

    if(!this.notEditable) {
      const del = this.getContextItemMenu('Удалить', '#ef2d35', 'trash', () => {
        UIkit.modal.confirm(i18n.tr('Вы действительно хотите удалить файл ${fileName}?').replace('${fileName}', `"${name}"`)).then(async () => {
          const deleteResult = await appAPI.deleteFile(uuid);
          if(deleteResult && deleteResult.errorCode == 0) {
            li.remove();
            if(type == "ase:attachmentContainer") {
              this.attachmentFilesCount--;
            } else {
              this.workFilesCount--;
            }
            this.tabTranslate();
          } else {
            showMessage(deleteResult.errorMessage, 'error');
          }
        }, () => null);
      });

      ul.append('<li class="uk-nav-divider"></li>', del);
    }

    menu.append(ul);

    return menu;
  }

  renderListFiles(files, listFiles){
    listFiles.empty();
    for(let i = 0; i < files.length; i++) {
      const file = files[i];
      const li = $(`<li class="uk-position-relative" index-file="${i}" title="${file.name}">${i+1}. ${file.name}</li>`);
      const delButton = $(`<a href="#" uk-icon="icon: trash" class="uk-position-center-right uk-hidden-hover"></a>`);
      li.append(delButton);
      listFiles.append(li);

      delButton.on('click', e => {
        files.splice(i, 1);
        li.remove();
        this.renderListFiles(files, listFiles);
      });
    }
  }

  async addFileButtonHandler(){
    let me = this;
    const content = $('<div>');
    const listFiles = $('<ul>', {class: 'uk-list uk-list-divider'});
    const {container, inputFile} = Components.createSelectFileMultiple(i18n.tr('Выбрать файлы'));
    let files = [];
    let uploadErrors = 0;
    let finishUpload = false;

    content.append(container, listFiles);

    inputFile.on('change', e => {
      files = [...inputFile[0].files];
      uploadErrors = 0;
      me.renderListFiles(files, listFiles);
    });

    const dialog = await UTILS.getModalDialog(i18n.tr('Добавить документ'), content, i18n.tr('Загрузить'), async () => {
      Cons.showLoader();
      try {
        if(!files.length) throw new Error('Необходимо прикрепить файл');

        dialog.find('.uk-button-primary').hide();
        container.hide();

        for(let i = 0; i < files.length; i++) {
          const file = files[i];
          const statusLable = listFiles.find(`[index-file="${i}"]`);
          const fileReader = new FileReader();

          statusLable.find('a').remove();

          if(file.size > 20971520) {
            statusLable.append(`<span style="color: orange;"> - ${i18n.tr('Размер файла не должен превышать 20 МБ')}</span>`);
            uploadErrors++;
          } else {
            Cons.showLoader();

            const filePath = await appAPI.startUpload();
            if(!filePath) {
              statusLable.append(`<span style="color: red;"> - ${i18n.tr('Ошибка создания временного файла')}</span>`);
              uploadErrors++;
            } else {

              fileReader.onload = async function (e) {
                Cons.showLoader();
                const b64encoded = btoa(new Uint8Array(e.target.result).reduce((data, byte) => data + String.fromCharCode(byte), ''));
                const data = new FormData();
                data.append('body', b64encoded);

                const uploadResult = await appAPI.uploadPart(filePath.file, data);
                if(!uploadResult) {
                  statusLable.append(`<span style="color: red;"> - ${i18n.tr('Ошибка загрузки файла')}</span>`);
                  uploadErrors++;
                } else {
                  if(uploadResult.errorCode != '0') {
                    statusLable.append(`<span style="color: red;"> - ${i18n.tr(uploadResult.errorMessage)}</span>`);
                    uploadErrors++;
                  } else {
                    Cons.showLoader();
                    const {errorCode, errorMessage} = await appAPI.addFileToDocument(me.documentID, file.name, filePath.file, me.path) || {};
                    if(errorCode && errorCode == '0') {
                      statusLable.append(`<span style="color: green;"> - ${i18n.tr('готово')}</span>`);
                    } else {
                      if(errorMessage.indexOf('This node already exists') != -1) {
                        statusLable.append(`<span style="color: red;"> - ${i18n.tr('Файл ${fileName} уже существует').replace('${fileName}', file.name)}</span>`);
                      } else {
                        statusLable.append(`<span style="color: red;"> - ${i18n.tr(errorMessage)}</span>`);
                      }
                      uploadErrors++;
                    }
                    Cons.hideLoader();
                  }
                }
                Cons.hideLoader();
                dialog.find('button.uk-modal-close').text('OK');
              }

              fileReader.readAsArrayBuffer(file);
            }
          }
        }

        Cons.hideLoader();
        if(uploadErrors > 0) showMessage(i18n.tr('При загрузке файлов возникли ошибки'), 'error');
        finishUpload = true;

      } catch (err) {
        Cons.hideLoader();
        showMessage(i18n.tr(err.message), 'error');
      }
    });
    UIkit.modal(dialog).show();
    dialog.on('hidden', () => {
      dialog.remove();
      if(finishUpload) me.init();
    });
  }

  renderApp(){
    this.container.empty();

    this.rootContainer = $('<div>', {style: "width: 100%; height: 100%;"});
    this.tabContainer = $('<div>', {class: "workflow-tab-container"});
    this.addFileButton = $('<a href="#" id="workflow_add_file_button" uk-icon="plus"></a>');

    this.workflowTabs = $('<ul class="uk-child-width-expand document-files-tabs">');
    this.tabAttachmentContainer = $(`<li class="tab active" path="ase:attachmentContainer"><a href="#"></a></li>`);
    this.tabWorkContainer = $(`<li class="tab" path="ase:workContainer"><a href="#"></a></li>`);
    this.workflowTabs.append(this.tabAttachmentContainer, this.tabWorkContainer);


    this.filesContainer = $('<ul>', {class: "uk-margin document-files-container"});
    this.filesAttachmentContainer = $('<li class="data uk-padding-small uk-padding-remove-vertical active" path="ase:attachmentContainer"></li>');
    this.filesWorkContainer = $('<li class="data uk-padding-small uk-padding-remove-vertical" path="ase:workContainer"></li>');
    this.filesContainer.append(this.filesAttachmentContainer, this.filesWorkContainer);


    if(this.notEditable) {
      this.tabContainer.append(this.workflowTabs);
    } else {
      this.tabContainer.append(this.addFileButton, this.workflowTabs);
    }

    if(this.canEdit == "false") this.addFileButton.addClass('uk-disabled');

    this.rootContainer.append(this.tabContainer, this.filesContainer);

    this.container.append(this.rootContainer);

    this.addFileButton.on('click', e => {
      e.preventDefault();
      e.target.blur();
      this.addFileButtonHandler();
    });

    this.addListenerTabs();
  }

  addListenerTabs(){
    this.tabAttachmentContainer.find('a').on('click', e => {
      e.preventDefault();
      e.target.blur();
      this.tabAttachmentContainer.addClass('active');
      this.filesAttachmentContainer.addClass('active');
      this.filesWorkContainer.removeClass('active');
      this.tabWorkContainer.removeClass('active');
      this.path = "ase:attachmentContainer";
      if(this.canEdit == "false") {
        this.addFileButton.addClass('uk-disabled');
      } else {
        this.addFileButton.removeClass('uk-disabled');
      }
    });

    this.tabWorkContainer.find('a').on('click', e => {
      e.preventDefault();
      e.target.blur();
      this.tabAttachmentContainer.removeClass('active');
      this.filesAttachmentContainer.removeClass('active');
      this.filesWorkContainer.addClass('active');
      this.tabWorkContainer.addClass('active');
      this.path = "ase:workContainer";
      this.addFileButton.removeClass('uk-disabled');
    });
  }

  addFileItemListeners(li, item, type) {
    const {name, uuid} = item;
    let timeoutId;

    li.on('click', e => {

      timeoutId = setTimeout(() => {
        if(!timeoutId) return;
        this.filesContainer.find('.document-file-item').removeClass('select');
        li.addClass('select');
        this.container.trigger({type: 'file_click', eventParam: item});
      }, 200);

    }).on('dblclick', e => {

      clearTimeout(timeoutId);
      timeoutId = null;
      e.preventDefault();
      this.filesContainer.find('.document-file-item').removeClass('select');
      li.addClass('select');
      this.container.trigger({type: 'file_dbl_click', eventParam: item});

    }).on('contextmenu', e => {
      $('.workflow-context-menu').remove();
      const contextmenu = this.getContextMenu(li, item, type);
      $('body').append(contextmenu);

      const {left, top} = getMenuCoordinates(contextmenu, event.pageX, event.pageY);
      contextmenu.css({
        'left': `${left}px`,
        'top': `${top}px`
      });

      contextmenu.show('fast');
      return false;
    });
  }

  getFileList(attachment, type) {
    const ul = $('<ul style="overflow: hidden;">');
    attachment = attachment.sort((a,b) => new Date(a.created) - new Date(b.created));

    attachment.forEach((item, i) => {
      const {name} = item;
      const li = $('<li>', {class: 'document-file-item'});
      li.append(`<a href="#" title="${name}" style="text-overflow: ellipsis; overflow: hidden;">${name}</a>`);
      if(type == 'ase:attachmentContainer' && i == 0) li.addClass('select');
      this.addFileItemListeners(li, item, type);
      ul.append(li);
    });

    return ul;
  }

  async init(){
    const res = await appAPI.getDocumentAttachments(this.documentID);
    this.canEdit = await canEditFile(this.documentID);

    this.renderApp();

    if(res) {
      this.attachmentFilesCount = res.attachments.length;
      this.workFilesCount = res.work_files.length;

      this.filesAttachmentContainer.append(this.getFileList(res.attachments, 'ase:attachmentContainer'));
      this.filesWorkContainer.append(this.getFileList(res.work_files));

    } else {
      this.attachmentFilesCount = 0;
      this.workFilesCount = 0;
    }

    this.tabTranslate();
  }
}
