(function() {
  var activeUploads = {};

  function normalizeUrl(url) {
    url = (url || '').trim();
    if (url && !/^[a-z][a-z0-9+.-]*:\/\//i.test(url)) {
      url = 'https://' + url;
    }
    return url;
  }

  function isMp3File(file) {
    if (!file) {
      return false;
    }
    var name = (file.name || '').toLowerCase();
    return file.type === 'audio/mpeg' || file.type === 'audio/mp3' || /\.mp3$/i.test(name);
  }

  function getMaxSize(root) {
    var maxSize = parseInt(root.getAttribute('data-max-size'), 10);
    if (!maxSize || isNaN(maxSize)) {
      maxSize = 45 * 1024 * 1024;
    }
    if (typeof post_max_size !== 'undefined' && post_max_size) {
      var serverMax = post_max_size * 1024 * 1024;
      if (serverMax < maxSize) {
        maxSize = serverMax;
      }
    }
    return maxSize;
  }

  function MusicHTMLUploader(root) {
    this.root = root;
    this.input = root.querySelector('.music-upload-input');
    this.fileList = root.querySelector('#uploaded-file-list');
    this.hiddenIds = root.querySelector('#fancyuploadfileids');
    this.dropzone = root.querySelector('.music-upload-dropzone');
    this.urlInput = root.querySelector('[data-music-upload-url]');
    this.urlSubmit = root.querySelector('[data-music-upload-url-submit]');
    this.uploadSong = root.getAttribute('data-upload-song') === '1';
    this.maxSize = getMaxSize(root);
    this.uploadedIds = {};
    this.dragCounter = 0;
    this.bindEvents();
  }

  MusicHTMLUploader.prototype.bindEvents = function() {
    var self = this;

    this.root.querySelectorAll('[data-music-upload-trigger]').forEach(function(trigger) {
      trigger.addEventListener('click', function(event) {
        event.preventDefault();
        self.input.click();
      });
    });

    this.input.addEventListener('change', function() {
      self.queueFiles(self.input.files);
      self.input.value = '';
    });

    this.input.addEventListener('click', function() {
      this.value = '';
    });

    if (this.urlSubmit && this.urlInput) {
      this.urlSubmit.addEventListener('click', function(event) {
        event.preventDefault();
        self.uploadFromUrl();
      });
      this.urlInput.addEventListener('keydown', function(event) {
        if (event.key === 'Enter') {
          event.preventDefault();
          self.uploadFromUrl();
        }
      });
    }

    if (this.dropzone) {
      this.dropzone.addEventListener('click', function(event) {
        if (self.isInteractiveTarget(event.target)) {
          return;
        }
        self.input.click();
      });

      this.dropzone.addEventListener('dragenter', function(event) {
        event.preventDefault();
        self.dragCounter++;
        self.root.classList.add('is-dragover');
      });

      this.dropzone.addEventListener('dragover', function(event) {
        event.preventDefault();
        self.root.classList.add('is-dragover');
      });

      this.dropzone.addEventListener('dragleave', function(event) {
        event.preventDefault();
        self.dragCounter--;
        if (self.dragCounter <= 0) {
          self.root.classList.remove('is-dragover');
          self.dragCounter = 0;
        }
      });

      this.dropzone.addEventListener('drop', function(event) {
        event.preventDefault();
        self.dragCounter = 0;
        self.root.classList.remove('is-dragover');
        if (event.dataTransfer && event.dataTransfer.files) {
          self.queueFiles(event.dataTransfer.files);
        }
      });
    }
  };

  MusicHTMLUploader.prototype.isInteractiveTarget = function(target) {
    while (target && target !== this.dropzone) {
      if (target.tagName && /^(A|BUTTON|INPUT|TEXTAREA|SELECT|LABEL)$/i.test(target.tagName)) {
        return true;
      }
      target = target.parentNode;
    }
    return false;
  };

  MusicHTMLUploader.prototype.queueFiles = function(files) {
    if (!files || !files.length) {
      return;
    }
    for (var i = 0; i < files.length; i++) {
      if (this.uploadSong && this.fileList.querySelectorAll('li.file').length >= 1) {
        break;
      }
      this.uploadFile(files[i]);
    }
  };

  MusicHTMLUploader.prototype.validateFile = function(file) {
    if (!isMp3File(file)) {
      return en4.core.language.translate('Only mp3 files are allowed.');
    }
    if (file.size > this.maxSize) {
      var limitMb = Math.round(this.maxSize / (1024 * 1024));
      return en4.core.language.translate('File is too large. Maximum size is ') + limitMb + 'MB.';
    }
    return null;
  };

  MusicHTMLUploader.prototype.uploadFromUrl = function() {
    var url = normalizeUrl(this.urlInput ? this.urlInput.value : '');
    if (!url) {
      return;
    }
    var validationError = this.validateUrl(url);
    if (validationError) {
      alert(validationError);
      return;
    }
    this.startUrlUpload(url);
  };

  MusicHTMLUploader.prototype.validateUrl = function(url) {
    try {
      var parsed = new URL(url);
      if (!/\.mp3($|\?)/i.test(parsed.pathname + parsed.search)) {
        return en4.core.language.translate('URL must point to an mp3 file.');
      }
    } catch (e) {
      return en4.core.language.translate('Please enter a valid URL.');
    }
    return null;
  };

  MusicHTMLUploader.prototype.createListItem = function(uploadKey, fileName) {
    var li = document.createElement('li');
    li.className = 'file file-uploading';
    li.setAttribute('data-upload-key', uploadKey);
    li.innerHTML =
      '<span class="music_upload_item_icon"><i class="fi fi-rr-music-alt"></i></span>' +
      '<div class="music-upload-item-body">' +
        '<div class="music-upload-item-row">' +
          '<a href="javascript:void(0);" class="file-name file-name-link">' + this.escapeHtml(fileName) + '</a>' +
          '<a href="javascript:void(0);" class="music-upload-cancel" title="' + en4.core.language.translate('Cancel') + '"><i class="fa fa-times"></i></a>' +
        '</div>' +
        '<div class="music-upload-progress-row">' +
          '<div class="music-upload-progress"><span class="music-upload-progress-bar"></span></div>' +
          '<span class="music-upload-percent">0%</span>' +
        '</div>' +
      '</div>';
    this.fileList.appendChild(li);
    this.fileList.style.display = 'block';
    return li;
  };

  MusicHTMLUploader.prototype.escapeHtml = function(text) {
    return String(text)
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;');
  };

  MusicHTMLUploader.prototype.markSuccess = function(li, response) {
    li.className = 'file file-success';
    li.id = response.id ? ('file_' + response.id) : '';
    li.setAttribute('data-file_id', response.id);
    li.innerHTML =
      '<span class="music_upload_item_icon"><i class="fi fi-rr-music-alt"></i></span>' +
      '<div class="music-upload-item-body">' +
        '<div class="music-upload-item-row">' +
          '<span class="file-name ui-sortable-handle">' + this.escapeHtml(response.fileName || '') + '</span>' +
          '<a href="javascript:void(0);" class="file-remove" data-file_id="' + response.id + '" title="' + en4.core.language.translate('Remove') + '"><i class="fi fi-rr-trash"></i></a>' +
        '</div>' +
      '</div>';

    var self = this;
    li.querySelector('.file-remove').addEventListener('click', function() {
      self.removeFile(response.id, li);
    });

    this.appendFileId(response.id);
    this.showSubmitButton();
    if (this.uploadSong) {
      this.root.classList.add('has-uploaded-song');
    }
  };

  MusicHTMLUploader.prototype.markError = function(li, message) {
    if (li && li.parentNode) {
      li.parentNode.removeChild(li);
    }
    alert(message || en4.core.language.translate('Upload failed.'));
    this.toggleEmptyState();
  };

  MusicHTMLUploader.prototype.updateProgress = function(li, percent) {
    var bar = li.querySelector('.music-upload-progress-bar');
    var label = li.querySelector('.music-upload-percent');
    if (bar) {
      bar.style.width = percent + '%';
    }
    if (label) {
      label.textContent = Math.round(percent) + '%';
    }
  };

  MusicHTMLUploader.prototype.uploadFile = function(file) {
    var validationError = this.validateFile(file);
    if (validationError) {
      alert(validationError);
      return;
    }

    var uploadKey = 'upload_' + Date.now() + '_' + Math.floor(Math.random() * 100000);
    var li = this.createListItem(uploadKey, file.name);
    var self = this;
    var xhr = new XMLHttpRequest();
    var fd = new FormData();
    var url = this.input.getAttribute('data-url');

    activeUploads[uploadKey] = xhr;

    li.querySelector('.music-upload-cancel').addEventListener('click', function() {
      if (activeUploads[uploadKey]) {
        activeUploads[uploadKey].abort();
        delete activeUploads[uploadKey];
      }
      if (li.parentNode) {
        li.parentNode.removeChild(li);
      }
      self.toggleEmptyState();
    });

    xhr.open('POST', url, true);
    xhr.upload.addEventListener('progress', function(event) {
      if (event.lengthComputable) {
        self.updateProgress(li, (event.loaded / event.total) * 100);
      }
    });

    xhr.onreadystatechange = function() {
      if (xhr.readyState !== 4) {
        return;
      }
      delete activeUploads[uploadKey];
      if (xhr.status !== 200) {
        //self.markError(li, en4.core.language.translate('An error occurred.'));
        return;
      }
      try {
        var response = JSON.parse(xhr.responseText);
        if (response.error) {
          self.markError(li, response.error);
          return;
        }
        self.markSuccess(li, response);
      } catch (e) {
        self.markError(li, en4.core.language.translate('An error occurred.'));
      }
    };

    fd.append('ajax-upload', 'true');
    fd.append(this.input.getAttribute('name'), file);
    xhr.send(fd);
  };

  MusicHTMLUploader.prototype.startUrlUpload = function(url) {
    var fileName = url.split('/').pop().split('?')[0] || 'song.mp3';
    var uploadKey = 'upload_' + Date.now() + '_' + Math.floor(Math.random() * 100000);
    var li = this.createListItem(uploadKey, fileName);
    var self = this;
    var xhr = new XMLHttpRequest();
    var fd = new FormData();
    var endpoint = this.input.getAttribute('data-url');

    activeUploads[uploadKey] = xhr;

    li.querySelector('.music-upload-cancel').addEventListener('click', function() {
      if (activeUploads[uploadKey]) {
        activeUploads[uploadKey].abort();
        delete activeUploads[uploadKey];
      }
      if (li.parentNode) {
        li.parentNode.removeChild(li);
      }
      self.toggleEmptyState();
    });

    xhr.open('POST', endpoint, true);
    xhr.upload.addEventListener('progress', function(event) {
      if (event.lengthComputable) {
        self.updateProgress(li, (event.loaded / event.total) * 100);
      } else {
        self.updateProgress(li, 50);
      }
    });

    xhr.onreadystatechange = function() {
      if (xhr.readyState !== 4) {
        return;
      }
      delete activeUploads[uploadKey];
      if (xhr.status !== 200) {
        self.markError(li, en4.core.language.translate('An error occurred.'));
        return;
      }
      try {
        var response = JSON.parse(xhr.responseText);
        if (response.error) {
          self.markError(li, response.error);
          return;
        }
        self.markSuccess(li, response);
        if (self.urlInput) {
          self.urlInput.value = '';
        }
      } catch (e) {
        self.markError(li, en4.core.language.translate('An error occurred.'));
      }
    };

    fd.append('ajax-upload', 'true');
    fd.append('file_url', url);
    xhr.send(fd);
  };

  MusicHTMLUploader.prototype.appendFileId = function(fileId) {
    if (!fileId || this.uploadedIds[fileId]) {
      return;
    }
    this.uploadedIds[fileId] = true;
    var current = this.hiddenIds.value || '';
    this.hiddenIds.value = current + fileId + ' ';
  };

  MusicHTMLUploader.prototype.removeFile = function(fileId, li) {
    delete this.uploadedIds[fileId];
    var current = (this.hiddenIds.value || '').replace(fileId + ' ', '');
    this.hiddenIds.value = current;

    if (typeof deleteFile !== 'undefined') {
      deleteFile(scriptJquery(li.querySelector('.file-remove')));
    }

    if (li && li.parentNode) {
      li.parentNode.removeChild(li);
    }

    this.toggleEmptyState();
    this.root.classList.remove('has-uploaded-song');
  };

  MusicHTMLUploader.prototype.showSubmitButton = function() {
    var submitWrapper = document.getElementById('submit-wrapper');
    if (submitWrapper) {
      //submitWrapper.style.display = 'block';
    }
  };

  MusicHTMLUploader.prototype.toggleEmptyState = function() {
    if (!this.fileList.querySelector('li.file')) {
      this.fileList.style.display = 'none';
      var submitWrapper = document.getElementById('submit-wrapper');
      if (submitWrapper) {
        //submitWrapper.style.display = 'none';
      }
    }
  };

  window.MusicHTMLUploader = {
    init: function(root) {
      if (!root || root.getAttribute('data-music-upload-ready') === '1') {
        return null;
      }
      root.setAttribute('data-music-upload-ready', '1');
      return new MusicHTMLUploader(root);
    },
    initAll: function(container) {
      var scope = container || document;
      var instances = [];
      scope.querySelectorAll('[data-music-html-upload]').forEach(function(root) {
        var instance = window.MusicHTMLUploader.init(root);
        if (instance) {
          instances.push(instance);
        }
      });
      return instances;
    }
  };
})();
