/**  
 * @since Last modified: 2024-07-11 09:30:49
 * @class Autocomplete
 * @description Warnings and tips.
 * @param {getEl} elem - Target element.    
 * @param {object} [options] - Parameters 
 * @see {@link https://codepen.io/axui/pen/mdgyYwO|demo @ codepen}
 * @example
 * ax.Autocomplete('#id');
 */
import { T_autocomplete } from '../../../types/autocomplete';
import Popup from './Popup';
import { T_fn, T_obj, T_required, T_sel } from '../../../types/ax';
import PubListen from './PubListen';
import PubUpdate from './PubUpdate';
import PubCommon from './PubCommon';
import PubBase from './PubBase';
import pipe from '../utils/pipe';
import optAutocomplete from '../options/optAutocomplete';
import ax from '../ax';
import extend from '../utils/extend';
import Retrieval from './Retrieval';
import prefix from '../global/prefix';
class Autocomplete extends pipe(PubListen, PubUpdate, PubCommon)(PubBase) {
    targetEl: any;
    options: T_required<T_autocomplete<0>> | T_obj = {};
    destroyed: any;
    plans: any;
    storKeys: any;
    storObs: any;
    storTmp: any;
    dftOpts: any;
    rawOpts: any;
    mainEl: any;
    static hostType = 'el';
    constructor(elem: T_sel, options: T_autocomplete = {}, inital: boolean = ax.config.inital) {
        super();
        super.ready({
            options,
            host: elem,
            maps: optAutocomplete,
            component: false,
            spread: []
        });
        this.getInputEl();
        this.rendered = false;
        super.listen({ name: 'ready' });
        inital ? this.init() : null;
    }
    init(cb?: T_fn): any {
        super.listen({ name: 'start' });
        this.setEmpty();
        if (!this.inputEl) return this;
        this.createPopup();
        this.createRetrieval();
        this.setAttrs();
        super.listen({ name: 'init', cb });
        return this;
    }
    getInputEl() {
        let nodeName = this.targetEl.nodeName;
        if (['AX-INPUT', 'AX-TEXTAREA'].includes(nodeName)) {
            this.inputEl = this.targetEl.querySelector('input,textarea');
        } else if (['INPUT', 'TEXTAREA'].includes(nodeName)) {
            this.inputEl = this.targetEl;
        }
    }
    setValues(val: string) {
        let nodeName = this.targetEl.nodeName;
        if (['AX-INPUT', 'AX-TEXTAREA'].includes(nodeName)) {
            this.targetEl.setAttribute('value', val);
        } else if (['INPUT', 'TEXTAREA'].includes(nodeName)) {
            this.targetEl.value = val;
        }
    }
    setEmpty() {
        this.popupIns && this.popupIns.destroy();
        this.popupIns?.contEl && (this.popupIns.contEl.innerHTML = '');
        this.retrievalIns && this.retrievalIns.destroy();
    }
    setAttrs() {
        this.popupIns.mainEl.classList.add(`${prefix}autocomplete`);
    }
    createPopup() {
        this.popupIns = new Popup(this.targetEl, extend({
            target: {
                placement: 'bottom-start',
                tools: { enable: true, placement: 'outside' },
                pageClose: false,
                footer: false,
                trigger: 'input',
                content: '',
                padding: false,
                b4Show: () => {
                    return new Promise((resolve: any) => {
                        if (this.rendered) {
                            resolve();
                        } else {
                            this.popupIns.state = 'hidden';
                        }
                    });
                },
                onHide: () => {
                    this.rendered = false;
                }
            },
            source: this.options.popup
        }));
    }
    createRetrieval() {
        this.retrievalIns = new Retrieval(extend({
            target: {
                target: this.popupIns.contEl,
                editor: this.inputEl,
                content: this.options.content,
                contType: this.options.contType,
                contData: this.options.contData,
                ajax: this.options.ajax,
                tplStr: this.options.tplStr,
                tplEng: this.options.tplEng,
                status: true,
                highlight: true,
                nullHandle: 'clear',
                list: {
                    divisible: true,
                    hoverable: true,
                },
            },
            source: this.options.retrieval
        }));
        this.retrievalIns.on('render', (data: T_obj[]) => {
            data.forEach(k => {
                k.source.el.onclick = async () => {
                    let val = k.source[this.options.fill];
                    if (this.options.b4Fill) {
                        let resp = await this.options.b4Fill.call(this, k, this.inputEl);
                        resp && (val = resp);
                    }
                    this.setValues(val);
                    this.hide();
                }
            });
            if (this.retrievalIns.renderCount > 0) {
                this.rendered = true;
                this.retrievalIns.getInputVals().trim() && this.popupIns.show();
                 this.rendered = false;
            }
        });
    }
    reset2Show(cb?: any): any {
        if (this.destroyed) return this;
        this.retrievalIns.resetList();
        this.show();
        super.listen({ name: 'reset2Show', cb });
        return this;
    }
    clear(cb?: any): any {
        if (this.destroyed) return this;
        this.retrievalIns.clearList();
        this.hide();
        super.listen({ name: 'clear', cb });
        return this;
    }
    show(cb?: any): any {
        if (this.destroyed) return this;
        this.rendered = true;
        this.popupIns.show();
        super.listen({ name: 'show', cb });
        return this;
    }
    hide(cb?: any): any {
        if (this.destroyed) return this;
        this.popupIns.hide();
        super.listen({ name: 'hide', cb });
        return this;
    }
    updateCont(content: any, cb?: T_fn): any {
        if (this.destroyed) return this;
        this.retrievalIns.updateCont(content, (data: any) => {
            this.updateCache({ content });
            this.listen({ name: 'updateCont', cb, params: [data] });
        });
        return this;
    }
    destroy(cb?: any): any {
        this.retrievalIns.destroy();
        this.popupIns.destroy();
        this.contXhr ? this.contXhr.abort() : null;
        this.destroyed = true;
        super.listen({ name: 'destroy', cb });
        return this;
    }
}
export default Autocomplete;
