import JoomlaDialog from 'joomla.dialog';

/**
 * @copyright  (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */
if (!window.Joomla) {
  throw new Error('Joomla API is not properly initiated');
}

/**
 * Extract the extensions
 *
 * @param {*} path
 * @returns {string}
 */
const getExtension = path => {
  const parts = path.split(/[#]/);
  if (parts.length > 1) {
    return parts[1].split(/[?]/)[0].split('.').pop().trim();
  }
  return path.split(/[#?]/)[0].split('.').pop().trim();
};
class JoomlaFieldMedia extends HTMLElement {
  constructor() {
    super();
    this.show = this.show.bind(this);
    this.clearValue = this.clearValue.bind(this);
    this.modalClose = this.modalClose.bind(this);
    this.setValue = this.setValue.bind(this);
    this.updatePreview = this.updatePreview.bind(this);
    this.validateValue = this.validateValue.bind(this);
    this.markValid = this.markValid.bind(this);
    this.markInvalid = this.markInvalid.bind(this);
    this.mimeType = '';
  }
  static get observedAttributes() {
    return ['type', 'base-path', 'root-folder', 'url', 'modal-title', 'modal-width', 'modal-height', 'input', 'button-select', 'button-clear', 'preview', 'preview-width', 'preview-height'];
  }
  get type() {
    return this.getAttribute('type');
  }
  set type(value) {
    this.setAttribute('type', value);
  }
  get basePath() {
    return this.getAttribute('base-path');
  }
  set basePath(value) {
    this.setAttribute('base-path', value);
  }
  get url() {
    return this.getAttribute('url');
  }
  set url(value) {
    this.setAttribute('url', value);
  }
  get input() {
    return this.getAttribute('input');
  }
  set input(value) {
    this.setAttribute('input', value);
  }
  get buttonSelect() {
    return this.getAttribute('button-select');
  }
  set buttonSelect(value) {
    this.setAttribute('button-select', value);
  }
  get buttonClear() {
    return this.getAttribute('button-clear');
  }
  set buttonClear(value) {
    this.setAttribute('button-clear', value);
  }
  get modalWidth() {
    return this.getAttribute('modal-width');
  }
  set modalWidth(value) {
    this.setAttribute('modal-width', value);
  }
  get modalHeight() {
    return this.getAttribute('modal-height');
  }
  set modalHeight(value) {
    this.setAttribute('modal-height', value);
  }
  get modalTitle() {
    return this.getAttribute('modal-title');
  }
  set modalTitle(value) {
    this.setAttribute('modal-title', value);
  }
  get previewWidth() {
    return parseInt(this.getAttribute('preview-width'), 10);
  }
  set previewWidth(value) {
    this.setAttribute('preview-width', value);
  }
  get previewHeight() {
    return parseInt(this.getAttribute('preview-height'), 10);
  }
  set previewHeight(value) {
    this.setAttribute('preview-height', value);
  }
  get preview() {
    return this.getAttribute('preview');
  }
  set preview(value) {
    this.setAttribute('preview', value);
  }
  get previewContainer() {
    return this.getAttribute('preview-container');
  }
  connectedCallback() {
    this.button = this.querySelector(this.buttonSelect);
    this.inputElement = this.querySelector(this.input);
    this.buttonClearEl = this.querySelector(this.buttonClear);
    this.previewElement = this.querySelector('.field-media-preview');
    if (!this.button || !this.inputElement || !this.buttonClearEl) {
      throw new Error('Misconfiguaration...');
    }
    this.button.addEventListener('click', this.show);
    if (this.buttonClearEl) {
      this.buttonClearEl.addEventListener('click', this.clearValue);
    }
    this.supportedExtensions = Joomla.getOptions('media-picker', {});
    if (!Object.keys(this.supportedExtensions).length) {
      throw new Error('Joomla API is not properly initiated');
    }
    this.inputElement.removeAttribute('readonly');
    this.inputElement.addEventListener('change', this.validateValue);
    this.updatePreview();
  }
  disconnectedCallback() {
    if (this.button) {
      this.button.removeEventListener('click', this.show);
    }
    if (this.buttonClearEl) {
      this.buttonClearEl.removeEventListener('click', this.clearValue);
    }
    if (this.inputElement) {
      this.inputElement.removeEventListener('change', this.validateValue);
    }
    if (this.dialog) {
      this.dialog.close();
    }
  }
  show() {
    // Create and show the dialog
    const dialog = new JoomlaDialog({
      popupType: 'iframe',
      src: this.url,
      textHeader: this.modalTitle,
      width: this.modalWidth,
      height: this.modalHeight,
      popupButtons: [{
        label: Joomla.Text._('JSELECT'),
        className: 'button button-success btn btn-success',
        location: 'header',
        onClick: () => {
          this.modalClose();
        }
      }, {
        label: '',
        ariaLabel: Joomla.Text._('JCLOSE'),
        className: 'button-close btn-close',
        data: {
          buttonClose: '',
          dialogClose: ''
        },
        location: 'header'
      }]
    });
    dialog.classList.add('joomla-dialog-media-field');
    dialog.show();
    Joomla.Modal.setCurrent(dialog);
    dialog.addEventListener('joomla-dialog:close', () => {
      Joomla.Modal.setCurrent(null);
      dialog.destroy();
      this.dialog = null;
      Joomla.selectedMediaFile = {};
    });
    this.dialog = dialog;
  }
  async modalClose() {
    try {
      await Joomla.getMedia(Joomla.selectedMediaFile, this.inputElement, this);
    } catch (err) {
      Joomla.renderMessages({
        error: [Joomla.Text._('JLIB_APPLICATION_ERROR_SERVER')]
      });
    }
    Joomla.selectedMediaFile = {};
    this.dialog.close();
  }
  setValue(value) {
    this.inputElement.value = value;
    this.validatedUrl = value;
    this.mimeType = Joomla.selectedMediaFile.fileType;
    this.updatePreview();

    // trigger change event both on the input and on the custom element
    this.inputElement.dispatchEvent(new Event('change'));
    this.dispatchEvent(new CustomEvent('change', {
      detail: {
        value
      },
      bubbles: true
    }));
  }
  async validateValue(event) {
    let {
      value
    } = event.target;
    if (this.validatedUrl === value || value === '') return;
    if (/^(http(s)?:\/\/).+$/.test(value)) {
      try {
        fetch(value).then(response => {
          if (response.status === 200) {
            this.validatedUrl = value;
            this.markValid();
          } else {
            this.validatedUrl = value;
            this.markInvalid();
          }
        });
      } catch (err) {
        this.validatedUrl = value;
        this.markInvalid();
      }
    } else {
      if (/^\//.test(value)) {
        value = value.substring(1);
      }
      const hashedUrl = value.split('#');
      const urlParts = hashedUrl[0].split('/');
      const rest = urlParts.slice(1);
      fetch(`${Joomla.getOptions('system.paths').rootFull}/${value}`).then(response => response.blob()).then(blob => {
        if (blob.type.includes('image')) {
          const img = new Image();
          img.src = URL.createObjectURL(blob);
          img.onload = () => {
            this.inputElement.value = `${urlParts[0]}/${rest.join('/')}#joomlaImage://local-${urlParts[0]}/${rest.join('/')}?width=${img.width}&height=${img.height}`;
            this.validatedUrl = `${urlParts[0]}/${rest.join('/')}#joomlaImage://local-${urlParts[0]}/${rest.join('/')}?width=${img.width}&height=${img.height}`;
            this.markValid();
          };
        } else if (blob.type.includes('audio')) {
          this.mimeType = blob.type;
          this.inputElement.value = value;
          this.validatedUrl = value;
          this.markValid();
        } else if (blob.type.includes('video')) {
          this.mimeType = blob.type;
          this.inputElement.value = value;
          this.validatedUrl = value;
          this.markValid();
        } else if (blob.type.includes('application/pdf')) {
          this.mimeType = blob.type;
          this.inputElement.value = value;
          this.validatedUrl = value;
          this.markValid();
        } else {
          this.validatedUrl = value;
          this.markInvalid();
        }
      }).catch(() => {
        this.setValue(value);
        this.validatedUrl = value;
        this.markInvalid();
      });
    }
  }
  markValid() {
    this.inputElement.removeAttribute('required');
    this.inputElement.removeAttribute('pattern');
    if (document.formvalidator) {
      document.formvalidator.validate(this.inputElement);
    }
  }
  markInvalid() {
    this.inputElement.setAttribute('required', '');
    this.inputElement.setAttribute('pattern', '/^(http://INVALID/).+$/');
    if (document.formvalidator) {
      document.formvalidator.validate(this.inputElement);
    }
  }
  clearValue() {
    this.setValue('');
    this.validatedUrl = '';
    this.inputElement.removeAttribute('required');
    this.inputElement.removeAttribute('pattern');
    if (document.formvalidator) {
      document.formvalidator.validate(this.inputElement);
    }
  }
  updatePreview() {
    if (['true', 'static'].indexOf(this.preview) === -1 || this.preview === 'false' || !this.previewElement) {
      return;
    }

    // Reset preview
    if (this.preview) {
      const {
        value
      } = this.inputElement;
      const {
        supportedExtensions
      } = this;
      if (!value) {
        this.buttonClearEl.style.display = 'none';
        this.previewElement.innerHTML = Joomla.sanitizeHtml('<span class="field-media-preview-icon"></span>');
      } else {
        let type;
        this.buttonClearEl.style.display = '';
        this.previewElement.innerHTML = '';
        const ext = getExtension(value).toLowerCase();
        if (supportedExtensions.images.includes(ext)) type = 'images';
        if (supportedExtensions.audios.includes(ext)) type = 'audios';
        if (supportedExtensions.videos.includes(ext)) type = 'videos';
        if (supportedExtensions.documents.includes(ext)) type = 'documents';
        let previewElement;
        const mediaType = {
          images: () => {
            if (supportedExtensions.images.includes(ext)) {
              previewElement = new Image();
              previewElement.src = /http/.test(value) ? value : Joomla.getOptions('system.paths').rootFull + value;
              previewElement.setAttribute('alt', '');
            }
          },
          audios: () => {
            if (supportedExtensions.audios.includes(ext)) {
              previewElement = document.createElement('audio');
              previewElement.src = /http/.test(value) ? value : Joomla.getOptions('system.paths').rootFull + value;
              previewElement.setAttribute('controls', '');
            }
          },
          videos: () => {
            if (supportedExtensions.videos.includes(ext)) {
              previewElement = document.createElement('video');
              const previewElementSource = document.createElement('source');
              previewElementSource.src = /http/.test(value) ? value : Joomla.getOptions('system.paths').rootFull + value;
              previewElementSource.type = this.mimeType;
              previewElement.setAttribute('controls', '');
              previewElement.setAttribute('width', this.previewWidth);
              previewElement.setAttribute('height', this.previewHeight);
              previewElement.appendChild(previewElementSource);
            }
          },
          documents: () => {
            if (supportedExtensions.documents.includes(ext)) {
              previewElement = document.createElement('object');
              previewElement.data = /http/.test(value) ? value : Joomla.getOptions('system.paths').rootFull + value;
              previewElement.type = this.mimeType;
              previewElement.setAttribute('width', this.previewWidth);
              previewElement.setAttribute('height', this.previewHeight);
            }
          }
        };

        // @todo more checks
        if (this.givenType && ['images', 'audios', 'videos', 'documents'].includes(this.givenType)) {
          mediaType[this.givenType]();
        } else if (type && ['images', 'audios', 'videos', 'documents'].includes(type)) {
          mediaType[type]();
        } else {
          return;
        }
        this.previewElement.style.width = this.previewWidth;
        this.previewElement.appendChild(previewElement);
      }
    }
  }
}
customElements.define('joomla-field-media', JoomlaFieldMedia);
