/**  
 * @since Last modified: 2024-07-11 09:30:49
 * @class AnchorsElem
 * @description The custom element : ax-anchors .
 * @see {@link https://codepen.io/axui/pen/BaEGyXb|demo @ codepen}
 * @example
 * <ax-anchors>h2,h3</ax-anchors>;
 */
import preventDefault from '../../../../src/scripts/utils/preventDefault';
import { T_el, T_fn, T_obj } from '../../../types/ax';
import ax from '../ax';
import config from '../global/config';
import prefix from '../global/prefix';
import Observe from '../modules/Observe';
import attrJoinVal from '../utils/attrJoinVal';
import attrValBool from '../utils/attrValBool';
import createEl from '../utils/createEl';
import elState from '../utils/elState';
import extend from '../utils/extend';
import findItem from '../utils/findItem';
import getAttrBool from '../utils/getAttrBool';
import getBetweenEls from '../utils/getBetweenEls';
import getDataType from '../utils/getDataType';
import getEl from '../utils/getEl';
import getEls from '../utils/getEls';
import icons from '../utils/icons';
import preventDft from '../utils/preventDft';
import scrollTo from '../utils/scrollTo';
import tplToEl from '../utils/tplToEl';
import treeTools from '../utils/treeTools';
import valToArr from '../utils/valToArr';
import PlainElem from './PlainElem';
class AnchorsElem extends PlainElem {
    data: any;
    wrapEl: any;
    smoothEvent: any;
    interactIns: any;
    reset: any;
    constructor() {
        super();
        this.createObs();
        this.getRawData();
        this.createInteract();
        this.render(this.propsProxy);
    }
    static get observedAttributes() {
        return ['class', 'headings', 'parent', 'active', 'offset', 'smooth', 'collapsed'];
    }
    attributeChangedCallback(name: string, oldVal: string, newVal: string) {
        this.propsProxy[name] = (name === 'collapsed' || name === 'smooth') ? getAttrBool(newVal) : newVal;
        if (name === 'headings' || name === 'parent') {
            this.render(this.propsProxy);
        } else if (name === 'active') {
            this.active(newVal);
        } else if (name === 'offset') {
            this.data.forEach((k: any) => {
                k.target.style.scrollMarginTop = newVal;
            });
        } else if (name === 'smooth') {
            let bool = attrValBool(newVal);
            bool ? this.addSmooth() : this.removeSmooth();
        }
    }
    connectedCallback() {
    }
    disconnectedCallback() {
    }
    adoptedCallback() {
    }
    createInteract(): void {
        this.interactIns = new IntersectionObserver(entries => {
            entries.forEach((k: any) => {
                if (k.isIntersecting) {
                    if (k.intersectionRatio === 1) {
                        this.active(k.target, true, false);
                    }
                }
            });
        }, {
            threshold: [1],
        });
    }
    getRawData() {
        this.propsRaw = {
            headings: valToArr(this.getAttribute('headings') || this.textContent),
            parent: this.getAttribute('parent'),
            offset: this.getAttribute('offset'),
            smooth: getAttrBool(this.getAttribute('smooth')),
            collapsed: getAttrBool(this.getAttribute('collapsed')),
        }
        for (let k in this.propsRaw) {
            this.propsProxy[k] = this.propsRaw[k]
        }
    }
    getData(headings: string[]) {
        if (headings.length === 0) { return [] }
        let result: T_obj[] = [],
            getChildren = (index: number, els: T_el[], arr: any, pNext?: any) => {
                let keyNext = headings[index + 1];
                els.forEach((x: any, y) => {
                    let obj: T_obj = {
                        target: x,
                        label: x.textContent.replace('§', '')
                    };
                    let children = getBetweenEls({
                        selector: keyNext,
                        start: x,
                        end: els[y + 1] || pNext,
                        parent: this.propsProxy.parent,
                    });
                    if (children.length > 0) {
                        obj.children = []
                        getChildren(index + 1, children, obj.children, els[y + 1]);
                    }
                    arr.push(obj);
                });
            };
        getChildren(0, getEls(headings[0], this.propsProxy.parent), result);
        treeTools.addIdPath({ source: result });
        return result;
    }
    render(data: T_obj) {
        this.innerHTML = '';
        this.data = this.getData(valToArr(data.headings));
        let plantTree = (parent: T_el, data: T_obj[]) => {
            let ul = createEl('ul');
            data.forEach((k: any) => {
                k.wrapEl = createEl('li', { role: 'wrap' });
                k.labelEl = createEl('a', { role: 'label', href: `#${k.label}` }, k.label);
                k.headEl = createEl('div', { role: 'head', id: k.id }, k.labelEl);
                k.wrapEl.appendChild(k.headEl);
                k.labelEl.onclick = () => this.smoothToActive(k, false);
                k.target.id = k.label;
                let tmp = k.target.querySelector(`[href="#${k.label}"]`);
                if (tmp) { tmp.remove() }
                k.hashEl = createEl('a', { href: `#${k.label}` }, '§');
                k.hashEl.onclick = () => this.smoothToActive(k, false);
                k.target.appendChild(k.hashEl);
                this.interactIns.observe(k.target);
                if (k.hasOwnProperty('children')) {
                    k.bodyEl = plantTree(k.wrapEl, k.children);
                    k.bodyEl.setAttribute('role', 'body');
                }
                ul.appendChild(k.wrapEl);
            });
            parent.appendChild(ul);
            return ul;
        }
        plantTree(this, this.data);
        this.querySelector('ul')?.classList.add(`${prefix}reset`);
    }
    active(data: string | T_el, active: boolean = true, smooth: boolean = true) {
        if (!data) { return this }
        let flat = treeTools.toFlat(this.data),
            dataType = getDataType(data),
            tmp = Number(data),
            value = tmp === 0 || !!tmp ? tmp : data,
            item = dataType.includes('HTML') ? findItem(data, flat, 'target') : findItem(value, flat);
        if (item) {
            if (!item.active && active) {
                item.headEl.setAttribute('active', '');
                item.active = true;
                let others = flat.filter((k: T_obj) => k !== item && k.active);
                others.forEach((k: any) => {
                    k.headEl.removeAttribute('active');
                    Reflect.deleteProperty(k, 'active');
                });
            }
            if (smooth) {
                if (this.propsProxy.smooth) {
                    scrollTo(item.target, {
                        offset: this.propsProxy.offset,
                    });
                }
            }
        }
    }
    addSmooth() {
        let flat = treeTools.toFlat(this.data);
        flat.forEach((k: any) => {
            k.labelEl.onclick = () => this.smoothToActive(k, false);
            k.hashEl.onclick = () => this.smoothToActive(k, false);
        });
    }
    removeSmooth() {
        let flat = treeTools.toFlat(this.data);
        flat.forEach((k: any) => {
            k.labelEl.onclick = null;
            k.hashEl.onclick = null;
        });
    }
    smoothToActive(obj: any, active: boolean = true) {
        this.active(obj.target, active, this.propsProxy.smooth);
    }
}
window.customElements.define("ax-anchors", AnchorsElem);
export default AnchorsElem;
