import anime from 'animejs';
import barba from "@barba/core";
import Utils from './utils/Utils';
import WindowUtils from './utils/WindowUtils';

const WU = new WindowUtils();

class PageTransition {
    constructor(callback, createScroll) {
        this.callback = callback;
        this.createScroll = createScroll;
        this.scroll = this.createScroll(document);
        this.animationDuration = 1000;
        this.loadingDuration = 1000;
        this.DOM = {
            container: document.querySelector('.loadingScreen'),
            inner: document.querySelector('.loadingScreen_inner'),
            progress: document.querySelector('.loadingScreen_progress'),
            pct: document.querySelector('.loadingScreen_pct_value')
        };

        this.medias = [];

        this.init();
    }

    init () {
        let that = this;

        that.preloadImages(document.body.innerHTML).then(() => {
            that.callback();
            that.scrollTop();

            const TL = anime.timeline({
                easing: 'easeInOutExpo',
                duration: that.animationDuration,
                delay: 250,
                begin: () => {},
                complete: () => {
                    that.setProgress(0);
                }
            });

            TL.add({ targets: that.DOM.container, translateY: '-100%' }, 0);
            TL.add({ targets: that.DOM.inner,     translateY: '100%' }, 0);
        });

        barba.init({
            timeout: 10000,
            transitions: [{
                once({ next }) {
                    // init LocomotiveScroll on page load
                    that.scroll = this.createScroll(next.container);
                },
                beforeEnter({ next }) {
                    that.scrollTop();

                    if (!WU.isXS()) {
                        // destroy the previous scroll
                        that.scroll.destroy();
                
                        // init LocomotiveScroll regarding the next page
                        setTimeout(() => {
                            that.scroll = that.createScroll(next.container);
                        }, 1000);
                    }
                },
                leave () {
                    return new Promise(resolve => {
                        anime.set(that.DOM.container, { translateY: '100%' });
                        anime.set(that.DOM.inner, { translateY: '-100%' });

                        const TL = anime.timeline({
                            easing: 'easeInOutExpo',
                            duration: that.animationDuration,
                            complete: resolve
                        });

                        TL.add({ targets: that.DOM.container, translateY: '0%' }, 0);
                        TL.add({ targets: that.DOM.inner,     translateY: '0%' }, 0);
                    });
                },
                enter ({ next }) {
                    let done = this.async();
                    that.setNewAttrs(next.html);
                    that.preloadImages(next.html).then(() => {
                        done();

                        const TL = anime.timeline({
                            easing: 'easeInOutExpo',
                            duration: that.animationDuration,
                            delay: 250,
                            begin: () => {
                                that.callback();
                            },
                            complete: () => {
                                that.setProgress(0);
                            }
                        });

                        TL.add({ targets: that.DOM.container, translateY: '-100%' }, 0);
                        TL.add({ targets: that.DOM.inner,     translateY: '100%' }, 0);
                    });
                }
            }]
        });
    }

    scrollTop () {
        this.scroll.scrollTo(0);
    }

    setProgress (value, duration = 0) {
        anime.remove(this.DOM.progress);
        anime.set(this.DOM.progress, { scaleX: value });
        this.DOM.pct.innerHTML = Math.ceil(value*100);
    }

    animateProgress () {
        let nbMedias = Math.max(this.medias.length, Utils.randomInt(6,11));
        let duration = this.loadingDuration / nbMedias;
        var TL = anime.timeline({
            duration: duration,
            easing: 'easeOutCubic'
        });
        
        for (let index = 1; index <= nbMedias; index++) {
            let value = index / nbMedias;

            TL.add({
                targets: this.DOM.progress,
                scaleX: value,
                begin: () => {
                    this.DOM.pct.innerHTML = Math.ceil(value*100);
                }
            });
        }

        return TL.finished;
    }

    detectImages (html) {
        let allImgs = [], imgs = [], m;
        const srcRegex = /<img[^>]+src="([^">]+)/g
        while (m = srcRegex.exec(html)) {
            allImgs.push(m[1]);
        }
        imgs = [...new Set(allImgs)];
        this.medias = [];
        imgs.map((imgSrc) => {
            this.medias.push({
                src: imgSrc,
                promise: Utils.loadImage(imgSrc)
            })
        });
    }

    preloadImages (html) {
        let that = this;
        this.detectImages(html);

        if (!this.medias || this.medias.length === 0) {
            that.setProgress(1);
            return Promise.all([]);
        }

        return this.animateProgress();
    }

    setNewAttrs (html) {
        const classRegex = /data-bodyclass="(.[^"]+)"/g;
        const newBodyClass = classRegex.exec(html);
        if (newBodyClass) {
            document.body.className = newBodyClass[1];
        }
    };

 }

export default PageTransition;