import isEmpty from '../utils/isEmpty';
import createEl from '../utils/createEl';
import PubBase from './PubBase';
import PubListen from './PubListen';
import PubUpdate from './PubUpdate';
import PubCommon from './PubCommon';
import pipe from '../utils/pipe';
import optSwipe from '../options/optSwipe';
import throttle from '../utils/throttle';
import prefix from '../global/prefix';
import Spy from './Spy';
import extend from '../utils/extend';
import Scroll from './Scroll';
import getSlidersData from '../utils/getSlidersData';
class Swipe extends pipe(PubListen, PubUpdate, PubCommon)(PubBase) {
    constructor(elem, options, inital = true) {
        super();
        this.options = {};
        this.ready({
            options,
            maps: optSwipe,
            host: elem,
            component: true,
            spread: ['autoplay', 'total', 'tools', 'pagination', 'navigation']
        });
        if (this.options.scroll.axis === 'x') {
            this.propsMap = {
                position: 'left',
                gap: 'marginLeft',
                client: 'clientX',
                size: 'width',
                offset: 'offsetLeft',
                reverse: {
                    size: 'height',
                    gap: 'marginTop'
                }
            };
        }
        else if (this.options.scroll.axis === 'y') {
            this.propsMap = {
                position: 'top',
                gap: 'marginTop',
                client: 'clientY',
                size: 'height',
                offset: 'offsetTop',
                reverse: {
                    size: 'width',
                    gap: 'marginLeft'
                }
            };
        }
        this.delayScroll = () => {
            if (this.activeIndex >= this.bullets.at(-1).index) {
                this.stopPlay();
                this.toStart(() => {
                    this.startPlay();
                });
            }
            else {
                this.setCountdown();
                this.toNext();
            }
        };
        this.startClone = [];
        this.endClone = [];
        this.keyToSwipe = throttle((e) => {
            (e.code === 'ArrowLeft') ? this.toPrev() : (e.code === 'ArrowRight') ? this.toNext() : null;
        }, this.options.throttle, true);
        this.sliderTpl = { label: '', content: '', thumb: '', brief: '', slider: null, cb: null };
        super.listen({ name: 'ready' });
        if (inital) {
            if (this.options.lazy) {
                this.spyIns = new Spy(this.targetEl, {
                    repeat: false,
                    onShown: () => {
                        this.init();
                    }
                });
            }
            else {
                this.init();
            }
        }
    }
    async init(cb) {
        super.listen({ name: 'start' });
        this.sliders = [];
        this.bullets = [];
        this.activeIndex = this.options.active;
        this.pause = true;
        this.setAttrs();
        this.createWrap();
        this.useTpl();
        await this.getSliders(this.options.content, (resp) => {
            this.sliders = resp;
            this.appendSliders();
        });
        this.setScroll();
        this.setSpy();
        super.listen({ name: 'init', cb });
        return this;
    }
    /**
    * @callback fn_cb_init
    * @description Execute a function after destroy.
    * @returns null.
    */
    /**
    * @description Set attributes and styles to the target node after initialization.
    * @returns null
    */
    setAttrs() {
        this.targetEl.classList.add(`${prefix}swipe`);
    }
    setScroll() {
        this.scrollOpt = extend({
            target: {
                wrapper: this.wrapEl,
                axis: 'x',
                duration: this.options.duration,
            },
            source: this.options.scroll
        });
        if (this.options.grouped && this.options.cols > 1) {
        }
        if (this.options.cols >= 1) {
        }
        this.scrollIns = new Scroll(this.targetEl, this.scrollOpt);
    }
    setSpy() {
        this.spyIns = new Spy(this.targetEl, {
            threshold: [1],
            onShown: () => {
                this.options.keyboard ? window.addEventListener('keydown', this.keyToSwipe) : null;
            },
            onOut: () => {
                this.options.keyboard ? window.removeEventListener('keydown', this.keyToSwipe) : null;
            }
        });
    }
    async getSliders(data = this.options.content, cb) {
        let result = [];
        await getSlidersData.call(this, {
            content: data,
            contType: this.options.contType,
            contData: this.options.contData,
            ajax: this.options.ajax,
            hyphen: this.options.hyphen,
            parent: this.targetEl,
            wrap: this.wrapEl,
            lazy: this.options.lazy,
            tplStr: this.options.tplStr,
            tplEng: this.options.tplEng,
            cb: (resp) => {
                result = [...resp];
            }
        });
        cb && cb(result);
        return result;
    }
    appendSliders(data = this.sliders) {
        let fragment = document.createDocumentFragment();
        for (let k of data) {
            fragment.appendChild(k.slider);
        }
        this.wrapEl.appendChild(fragment);
    }
    createWrap() {
        let firstChild = this.targetEl.firstElementChild;
        if (firstChild) {
            firstChild.classList.add(`${prefix}swipe-wrap`);
            this.wrapEl = firstChild;
        }
        else {
            this.wrapEl = createEl('ul', { class: `${prefix}swipe-wrap ${prefix}reset` }, '');
            this.targetEl.appendChild(this.wrapEl);
        }
        if (this.targetEl.querySelector(`.${prefix}swipe-nav`)) {
            this.navEl = this.targetEl.querySelector(`.${prefix}swipe-nav`);
        }
        else if (this.options.integrated) {
            this.navEl = createEl('div', { class: `${prefix}swipe-nav` }, '');
            this.targetEl.appendChild(this.navEl);
        }
    }
    async add(data, cb) {
        if (this.destroyed || isEmpty(data))
            return this;
        let tmp;
        await this.getSliders(data, (resp) => {
            tmp = resp;
        });
        this.appendSliders(tmp);
        super.listen({ name: 'add', cb, params: [tmp] });
        return { ins: this, data: tmp };
    }
    destroy(cb) {
        if (this.destroyed)
            return this;
        for (let k of this.sliders) {
            k.spy && k.spy.destroy();
        }
        this.scrollIns.destroy();
        this.spyIns && this.spyIns.destroy();
        this.countdownIns && this.countdownIns.destroy();
        window.removeEventListener('keydown', this.keyToSwipe);
        this.bullets.forEach((k) => {
            k.el.onclick = null;
        });
        this.prevEl && (this.prevEl.onclick = null);
        this.nextEl && (this.nextEl.onclick = null);
        if (this.toolsEl) {
            this.options.tools.children.forEach((k) => {
                k.el.onclick = null;
            });
        }
        this.destroyed = true;
        super.listen({ name: 'destroy', cb });
        return this;
    }
    updateCont(text, cb) {
        if (this.destroyed) {
            return this;
        }
        this.options.content = text;
        this.init();
        super.updateCache({ content: this.content });
        super.listen({ name: 'updateCont', cb, params: [this.content] });
        return this;
    }
}
Swipe.hostType = 'el';
export default Swipe;
