/* eslint indent: ["off"] */
import $ from 'dom7';
import Utils from '../../utils/utils';
import Framework7Class from '../../utils/class';

class PhotoBrowser extends Framework7Class {
  constructor(app, params = {}) {
    super(params, [app]);

    const pb = this;
    pb.app = app;

    const defaults = Utils.extend({
      on: {},
    }, app.params.photoBrowser);

    // Extend defaults with modules params
    pb.useModulesParams(defaults);

    pb.params = Utils.extend(defaults, params);

    Utils.extend(pb, {
      exposed: false,
      opened: false,
      activeIndex: pb.params.swiper.initialSlide,
      url: pb.params.url,
      view: pb.params.view || app.views.main,
      swipeToClose: {
        allow: true,
        isTouched: false,
        diff: undefined,
        start: undefined,
        current: undefined,
        started: false,
        activeSlide: undefined,
        timeStart: undefined,
      },
    });

    // Install Modules
    pb.useModules();

    // Init
    pb.init();
  }

  onSlideChange(swiper) {
    const pb = this;
    pb.activeIndex = swiper.activeIndex;

    let current = swiper.activeIndex + 1;
    let total = pb.params.virtualSlides ? pb.params.photos.length : swiper.slides.length;
    if (swiper.params.loop) {
      total -= 2;
      current -= swiper.loopedSlides;
      if (current < 1) current = total + current;
      if (current > total) current -= total;
    }

    const $activeSlideEl = pb.params.virtualSlides
      ? swiper.$wrapperEl.find(`.swiper-slide[data-swiper-slide-index="${swiper.activeIndex}"]`)
      : swiper.slides.eq(swiper.activeIndex);
    const $previousSlideEl = pb.params.virtualSlides
      ? swiper.$wrapperEl.find(`.swiper-slide[data-swiper-slide-index="${swiper.previousIndex}"]`)
      : swiper.slides.eq(swiper.previousIndex);

    let $currentEl = pb.$el.find('.photo-browser-current');
    let $totalEl = pb.$el.find('.photo-browser-total');
    if (pb.params.type === 'page' && pb.params.navbar && $currentEl.length === 0 && pb.app.theme === 'ios') {
      const navbarEl = pb.app.navbar.getElByPage(pb.$el);
      if (navbarEl) {
        $currentEl = $(navbarEl).find('.photo-browser-current');
        $totalEl = $(navbarEl).find('.photo-browser-total');
      }
    }
    $currentEl.text(current);
    $totalEl.text(total);

    // Update captions
    if (pb.captions.length > 0) {
      const captionIndex = swiper.params.loop ? $activeSlideEl.attr('data-swiper-slide-index') : pb.activeIndex;
      pb.$captionsContainerEl.find('.photo-browser-caption-active').removeClass('photo-browser-caption-active');
      pb.$captionsContainerEl.find(`[data-caption-index="${captionIndex}"]`).addClass('photo-browser-caption-active');
    }

    // Stop Video
    const previousSlideVideo = $previousSlideEl.find('video');
    if (previousSlideVideo.length > 0) {
      if ('pause' in previousSlideVideo[0]) previousSlideVideo[0].pause();
    }
  }

  onTouchStart() {
    const pb = this;
    const swipeToClose = pb.swipeToClose;
    if (!swipeToClose.allow) return;
    swipeToClose.isTouched = true;
  }

  onTouchMove(e) {
    const pb = this;
    const swipeToClose = pb.swipeToClose;

    if (!swipeToClose.isTouched) return;
    if (!swipeToClose.started) {
      swipeToClose.started = true;
      swipeToClose.start = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
      if (pb.params.virtualSlides) {
        swipeToClose.activeSlide = pb.swiper.$wrapperEl.children('.swiper-slide-active');
      } else {
        swipeToClose.activeSlide = pb.swiper.slides.eq(pb.swiper.activeIndex);
      }
      swipeToClose.timeStart = Utils.now();
    }
    e.preventDefault();
    swipeToClose.current = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
    swipeToClose.diff = swipeToClose.start - swipeToClose.current;
    const opacity = 1 - (Math.abs(swipeToClose.diff) / 300);
    const color = pb.exposed || pb.params.theme === 'dark' ? 0 : 255;
    swipeToClose.activeSlide.transform(`translate3d(0,${-swipeToClose.diff}px,0)`);
    pb.swiper.$el.css('background-color', `rgba(${color}, ${color}, ${color}, ${opacity})`).transition(0);
  }

  onTouchEnd() {
    const pb = this;
    const swipeToClose = pb.swipeToClose;
    swipeToClose.isTouched = false;
    if (!swipeToClose.started) {
      swipeToClose.started = false;
      return;
    }
    swipeToClose.started = false;
    swipeToClose.allow = false;
    const diff = Math.abs(swipeToClose.diff);
    const timeDiff = (new Date()).getTime() - swipeToClose.timeStart;
    if ((timeDiff < 300 && diff > 20) || (timeDiff >= 300 && diff > 100)) {
      Utils.nextTick(() => {
        if (pb.$el) {
          if (swipeToClose.diff < 0) pb.$el.addClass('swipe-close-to-bottom');
          else pb.$el.addClass('swipe-close-to-top');
        }
        pb.emit('local::swipeToClose', pb);
        pb.close();
        swipeToClose.allow = true;
      });
      return;
    }
    if (diff !== 0) {
      swipeToClose.activeSlide.addClass('photo-browser-transitioning').transitionEnd(() => {
        swipeToClose.allow = true;
        swipeToClose.activeSlide.removeClass('photo-browser-transitioning');
      });
    } else {
      swipeToClose.allow = true;
    }
    pb.swiper.$el.transition('').css('background-color', '');
    swipeToClose.activeSlide.transform('');
  }

  // Render Functions
  renderNavbar() {
    const pb = this;
    if (pb.params.renderNavbar) return pb.params.renderNavbar.call(pb);

    let iconsColor = pb.params.iconsColor;
    if (!pb.params.iconsColor && pb.params.theme === 'dark') iconsColor = 'white';

    const backLinkText = (pb.app.theme === 'ios' || pb.app.theme === 'aurora') && pb.params.backLinkText ? pb.params.backLinkText : '';

    const isPopup = pb.params.type !== 'page';
    const navbarHtml = `
      <div class="navbar">
        <div class="navbar-inner sliding">
          <div class="left">
            <a class="link ${isPopup ? 'popup-close' : ''} ${!backLinkText ? 'icon-only' : ''} ${!isPopup ? 'back' : ''}" ${isPopup ? 'data-popup=".photo-browser-popup"' : ''}>
              <i class="icon icon-back ${iconsColor ? `color-${iconsColor}` : ''}"></i>
              ${backLinkText ? `<span>${backLinkText}</span>` : ''}
            </a>
          </div>
          <div class="title">
            <span class="photo-browser-current"></span>
            <span class="photo-browser-of">${pb.params.navbarOfText}</span>
            <span class="photo-browser-total"></span>
          </div>
          <div class="right"></div>
        </div>
      </div>
    `.trim();
    return navbarHtml;
  }

  renderToolbar() {
    const pb = this;
    if (pb.params.renderToolbar) return pb.params.renderToolbar.call(pb);

    let iconsColor = pb.params.iconsColor;
    if (!pb.params.iconsColor && pb.params.theme === 'dark') iconsColor = 'white';

    const toolbarHtml = `
      <div class="toolbar toolbar-bottom tabbar">
        <div class="toolbar-inner">
          <a class="link photo-browser-prev">
            <i class="icon icon-back ${iconsColor ? `color-${iconsColor}` : ''}"></i>
          </a>
          <a class="link photo-browser-next">
            <i class="icon icon-forward ${iconsColor ? `color-${iconsColor}` : ''}"></i>
          </a>
        </div>
      </div>
    `.trim();
    return toolbarHtml;
  }

  renderCaption(caption, index) {
    const pb = this;
    if (pb.params.renderCaption) return pb.params.renderCaption.call(pb, caption, index);
    const captionHtml = `
      <div class="photo-browser-caption" data-caption-index="${index}">
        ${caption}
      </div>
    `.trim();
    return captionHtml;
  }

  renderObject(photo, index) {
    const pb = this;
    if (pb.params.renderObject) return pb.params.renderObject.call(pb, photo, index);
    const objHtml = `
      <div class="photo-browser-slide photo-browser-object-slide swiper-slide" data-swiper-slide-index="${index}">${photo.html ? photo.html : photo}</div>
    `;
    return objHtml;
  }

  renderLazyPhoto(photo, index) {
    const pb = this;
    if (pb.params.renderLazyPhoto) return pb.params.renderLazyPhoto.call(pb, photo, index);
    const photoHtml = `
      <div class="photo-browser-slide photo-browser-slide-lazy swiper-slide" data-swiper-slide-index="${index}">
          <div class="preloader swiper-lazy-preloader ${pb.params.theme === 'dark' ? 'color-white' : ''}">${Utils[`${pb.app.theme}PreloaderContent`] || ''}</div>
          <span class="swiper-zoom-container">
              <img data-src="${photo.url ? photo.url : photo}" class="swiper-lazy">
          </span>
      </div>
    `.trim();
    return photoHtml;
  }

  renderPhoto(photo, index) {
    const pb = this;
    if (pb.params.renderPhoto) return pb.params.renderPhoto.call(pb, photo, index);
    const photoHtml = `
      <div class="photo-browser-slide swiper-slide" data-swiper-slide-index="${index}">
        <span class="swiper-zoom-container">
          <img src="${photo.url ? photo.url : photo}">
        </span>
      </div>
    `.trim();
    return photoHtml;
  }

  render() {
    const pb = this;
    if (pb.params.render) return pb.params.render.call(pb, pb.params);
    const html = `
      <div class="photo-browser photo-browser-${pb.params.theme}">
        <div class="view">
          <div class="page photo-browser-page photo-browser-page-${pb.params.theme} no-toolbar ${!pb.params.navbar ? 'no-navbar' : ''}" data-name="photo-browser-page">
            ${pb.params.navbar ? pb.renderNavbar() : ''}
            ${pb.params.toolbar ? pb.renderToolbar() : ''}
            <div class="photo-browser-captions photo-browser-captions-${pb.params.captionsTheme || pb.params.theme}">
              ${pb.params.photos.map((photo, index) => {
                if (photo.caption) return pb.renderCaption(photo.caption, index);
                return '';
              }).join(' ')}
            </div>
            <div class="photo-browser-swiper-container swiper-container">
              <div class="photo-browser-swiper-wrapper swiper-wrapper">
                ${pb.params.virtualSlides ? '' : pb.params.photos.map((photo, index) => {
                  if (photo.html || ((typeof photo === 'string' || photo instanceof String) && photo.indexOf('<') >= 0 && photo.indexOf('>') >= 0)) {
                    return pb.renderObject(photo, index);
                  }
                  if (pb.params.swiper.lazy === true || (pb.params.swiper.lazy && pb.params.swiper.lazy.enabled)) {
                    return pb.renderLazyPhoto(photo, index);
                  }
                  return pb.renderPhoto(photo, index);
                }).join(' ')}
              </div>
            </div>
          </div>
        </div>
      </div>
    `.trim();
    return html;
  }

  renderStandalone() {
    const pb = this;
    if (pb.params.renderStandalone) return pb.params.renderStandalone.call(pb);
    const standaloneHtml = `<div class="popup photo-browser-popup photo-browser-standalone popup-tablet-fullscreen">${pb.render()}</div>`;
    return standaloneHtml;
  }

  renderPage() {
    const pb = this;
    if (pb.params.renderPage) return pb.params.renderPage.call(pb);
    const pageHtml = pb.render();

    return pageHtml;
  }

  renderPopup() {
    const pb = this;
    if (pb.params.renderPopup) return pb.params.renderPopup.call(pb);
    const popupHtml = `<div class="popup photo-browser-popup">${pb.render()}</div>`;

    return popupHtml;
  }

  // Callbacks
  onOpen(type, el) {
    const pb = this;
    const app = pb.app;
    const $el = $(el);

    $el[0].f7PhotoBrowser = pb;

    pb.$el = $el;
    pb.el = $el[0];
    pb.openedIn = type;
    pb.opened = true;

    pb.$swiperContainerEl = pb.$el.find('.photo-browser-swiper-container');
    pb.$swiperWrapperEl = pb.$el.find('.photo-browser-swiper-wrapper');
    pb.slides = pb.$el.find('.photo-browser-slide');
    pb.$captionsContainerEl = pb.$el.find('.photo-browser-captions');
    pb.captions = pb.$el.find('.photo-browser-caption');

    // Init Swiper
    const swiperParams = Utils.extend({}, pb.params.swiper, {
      initialSlide: pb.activeIndex,
      on: {
        tap(e) {
          pb.emit('local::tap', e);
        },
        click(e) {
          if (pb.params.exposition) {
            pb.expositionToggle();
          }
          pb.emit('local::click', e);
        },
        doubleTap(e) {
          pb.emit('local::doubleTap', e);
        },
        slideChange(...args) {
          const swiper = this;
          pb.onSlideChange(swiper);
          pb.emit('local::slideChange', ...args);
        },
        transitionStart(...args) {
          pb.emit('local::transitionStart', ...args);
        },
        transitionEnd(...args) {
          pb.emit('local::transitionEnd', ...args);
        },
        slideChangeTransitionStart(...args) {
          pb.emit('local::slideChangeTransitionStart', ...args);
        },
        slideChangeTransitionEnd(...args) {
          pb.emit('local::slideChangeTransitionEnd', ...args);
        },
        lazyImageLoad(...args) {
          pb.emit('local::lazyImageLoad', ...args);
        },
        lazyImageReady(...args) {
          const slideEl = args[0];
          $(slideEl).removeClass('photo-browser-slide-lazy');
          pb.emit('local::lazyImageReady', ...args);
        },
      },
    });
    if (pb.params.swipeToClose && pb.params.type !== 'page') {
      Utils.extend(swiperParams.on, {
        touchStart(e) {
          pb.onTouchStart(e);
          pb.emit('local::touchStart', e);
        },
        touchMoveOpposite(e) {
          pb.onTouchMove(e);
          pb.emit('local::touchMoveOpposite', e);
        },
        touchEnd(e) {
          pb.onTouchEnd(e);
          pb.emit('local::touchEnd', e);
        },
      });
    }
    if (pb.params.virtualSlides) {
      Utils.extend(swiperParams, {
        virtual: {
          slides: pb.params.photos,
          renderSlide(photo, index) {
            if (photo.html || ((typeof photo === 'string' || photo instanceof String) && photo.indexOf('<') >= 0 && photo.indexOf('>') >= 0)) {
              return pb.renderObject(photo, index);
            }
            if (pb.params.swiper.lazy === true || (pb.params.swiper.lazy && pb.params.swiper.lazy.enabled)) {
              return pb.renderLazyPhoto(photo, index);
            }
            return pb.renderPhoto(photo, index);
          },
        },
      });
    }

    pb.swiper = app.swiper.create(pb.$swiperContainerEl, swiperParams);

    if (pb.activeIndex === 0) {
      pb.onSlideChange(pb.swiper);
    }
    if (pb.$el) {
      pb.$el.trigger('photobrowser:open');
    }
    pb.emit('local::open photoBrowserOpen', pb);
  }

  onOpened() {
    const pb = this;

    if (pb.$el) {
      pb.$el.trigger('photobrowser:opened');
    }
    pb.emit('local::opened photoBrowserOpened', pb);
  }

  onClose() {
    const pb = this;
    if (pb.destroyed) return;

    // Destroy Swiper
    if (pb.swiper && pb.swiper.destroy) {
      pb.swiper.destroy(true, false);
      pb.swiper = null;
      delete pb.swiper;
    }
    if (pb.$el) {
      pb.$el.trigger('photobrowser:close');
    }
    pb.emit('local::close photoBrowserClose', pb);
  }

  onClosed() {
    const pb = this;
    if (pb.destroyed) return;
    pb.opened = false;
    pb.$el = null;
    pb.el = null;
    delete pb.$el;
    delete pb.el;
    if (pb.$el) {
      pb.$el.trigger('photobrowser:closed');
    }
    pb.emit('local::closed photoBrowserClosed', pb);
  }

  // Open
  openPage() {
    const pb = this;
    if (pb.opened) return pb;

    const pageHtml = pb.renderPage();

    pb.view.router.navigate({
      url: pb.url,
      route: {
        content: pageHtml,
        path: pb.url,
        on: {
          pageBeforeIn(e, page) {
            pb.view.$el.addClass(`with-photo-browser-page with-photo-browser-page-${pb.params.theme}`);
            pb.onOpen('page', page.el);
          },
          pageAfterIn(e, page) {
            pb.onOpened('page', page.el);
          },
          pageBeforeOut(e, page) {
            pb.view.$el.removeClass(`with-photo-browser-page with-photo-browser-page-exposed with-photo-browser-page-${pb.params.theme}`);
            pb.onClose('page', page.el);
          },
          pageAfterOut(e, page) {
            pb.onClosed('page', page.el);
          },
        },
      },
    });
    return pb;
  }

  openStandalone() {
    const pb = this;
    if (pb.opened) return pb;

    const standaloneHtml = pb.renderStandalone();

    const popupParams = {
      backdrop: false,
      content: standaloneHtml,
      on: {
        popupOpen(popup) {
          pb.onOpen('popup', popup.el);
        },
        popupOpened(popup) {
          pb.onOpened('popup', popup.el);
        },
        popupClose(popup) {
          pb.onClose('popup', popup.el);
        },
        popupClosed(popup) {
          pb.onClosed('popup', popup.el);
        },
      },
    };

    if (pb.params.routableModals) {
      pb.view.router.navigate({
        url: pb.url,
        route: {
          path: pb.url,
          popup: popupParams,
        },
      });
    } else {
      pb.modal = pb.app.popup.create(popupParams).open();
    }
    return pb;
  }

  openPopup() {
    const pb = this;
    if (pb.opened) return pb;

    const popupHtml = pb.renderPopup();

    const popupParams = {
      content: popupHtml,
      on: {
        popupOpen(popup) {
          pb.onOpen('popup', popup.el);
        },
        popupOpened(popup) {
          pb.onOpened('popup', popup.el);
        },
        popupClose(popup) {
          pb.onClose('popup', popup.el);
        },
        popupClosed(popup) {
          pb.onClosed('popup', popup.el);
        },
      },
    };

    if (pb.params.routableModals) {
      pb.view.router.navigate({
        url: pb.url,
        route: {
          path: pb.url,
          popup: popupParams,
        },
      });
    } else {
      pb.modal = pb.app.popup.create(popupParams).open();
    }
    return pb;
  }

  // Exposition
  expositionEnable() {
    const pb = this;
    if (pb.params.type === 'page') {
      pb.view.$el.addClass('with-photo-browser-page-exposed');
    }
    if (pb.$el) pb.$el.addClass('photo-browser-exposed');
    if (pb.params.expositionHideCaptions) pb.$captionsContainerEl.addClass('photo-browser-captions-exposed');
    pb.exposed = true;
    return pb;
  }

  expositionDisable() {
    const pb = this;
    if (pb.params.type === 'page') {
      pb.view.$el.removeClass('with-photo-browser-page-exposed');
    }
    if (pb.$el) pb.$el.removeClass('photo-browser-exposed');
    if (pb.params.expositionHideCaptions) pb.$captionsContainerEl.removeClass('photo-browser-captions-exposed');
    pb.exposed = false;
    return pb;
  }

  expositionToggle() {
    const pb = this;
    if (pb.params.type === 'page') {
      pb.view.$el.toggleClass('with-photo-browser-page-exposed');
    }
    if (pb.$el) pb.$el.toggleClass('photo-browser-exposed');
    if (pb.params.expositionHideCaptions) pb.$captionsContainerEl.toggleClass('photo-browser-captions-exposed');
    pb.exposed = !pb.exposed;
    return pb;
  }

  open(index) {
    const pb = this;
    const type = pb.params.type;
    if (pb.opened) {
      if (pb.swiper && typeof index !== 'undefined') {
        pb.swiper.slideTo(parseInt(index, 10));
      }
      return pb;
    }
    if (typeof index !== 'undefined') {
      pb.activeIndex = index;
    }
    if (type === 'standalone') {
      pb.openStandalone();
    }
    if (type === 'page') {
      pb.openPage();
    }
    if (type === 'popup') {
      pb.openPopup();
    }
    return pb;
  }

  close() {
    const pb = this;
    if (!pb.opened) return pb;
    if (pb.params.routableModals || pb.openedIn === 'page') {
      if (pb.view) pb.view.router.back();
    } else {
      pb.modal.once('modalClosed', () => {
        Utils.nextTick(() => {
          pb.modal.destroy();
          delete pb.modal;
        });
      });
      pb.modal.close();
    }
    return pb;
  }
  // eslint-disable-next-line
  init() {}

  destroy() {
    let pb = this;
    pb.emit('local::beforeDestroy photoBrowserBeforeDestroy', pb);
    if (pb.$el) {
      pb.$el.trigger('photobrowser:beforedestroy');
      pb.$el[0].f7PhotoBrowser = null;
      delete pb.$el[0].f7PhotoBrowser;
    }
    Utils.deleteProps(pb);
    pb = null;
  }
}

export default PhotoBrowser;
