import { Host, h } from "@stencil/core";
export class SpwTocNavigation {
    constructor() {
        /** Variante d'affichage : 'progress' (avec barre de progression) ou 'simple' (sans barre) */
        this.variant = 'progress';
        this.items = [];
        this.currentItemIndex = -1;
        this.currentH2Index = -1;
        this.h2ProgressPercents = new Map();
        this.clickedH2Index = -1;
        this.h2Distances = new Map();
    }
    async componentDidLoad() {
        await this.loadItems();
        this.setupIntersectionObserver();
        this.setupScrollHandler();
    }
    componentDidRender() {
        this.recalculateH2Distances();
    }
    recalculateH2Distances() {
        const h2Items = this.items.filter(item => item.level === 2);
        const h2Indices = this.items.map((item, idx) => (item.level === 2 ? idx : -1)).filter(idx => idx !== -1);
        const newDistances = new Map();
        h2Items.forEach((h2Item, h2ListIndex) => {
            const currentIndex = h2Indices[h2ListIndex];
            if (h2ListIndex < h2Items.length - 1) {
                const nextH2Item = h2Items[h2ListIndex + 1];
                const currentLi = this.el.querySelector(`li:has(a[href="#${h2Item.id}"])`);
                const nextLi = this.el.querySelector(`li:has(a[href="#${nextH2Item.id}"])`);
                if (currentLi && nextLi) {
                    const distance = nextLi.offsetTop - currentLi.offsetTop;
                    newDistances.set(currentIndex, distance);
                }
            }
        });
        let changed = newDistances.size !== this.h2Distances.size;
        if (!changed) {
            for (const [key, val] of newDistances) {
                if (this.h2Distances.get(key) !== val) {
                    changed = true;
                    break;
                }
            }
        }
        if (changed) {
            this.h2Distances = newDistances;
        }
    }
    disconnectedCallback() {
        if (this.observer) {
            this.observer.disconnect();
        }
        if (this.scrollHandler) {
            window.removeEventListener('scroll', this.scrollHandler);
        }
    }
    async loadItems() {
        const tocWrapper = this.el.closest('spw-toc');
        if (!tocWrapper)
            return;
        const container = tocWrapper.querySelector('spw-toc-container');
        if (!container)
            return;
        await new Promise(resolve => setTimeout(resolve, 100));
        try {
            if (container.getItems) {
                const items = await container.getItems();
                this.items = items;
            }
        }
        catch (e) {
            console.error('Error loading TOC items:', e);
        }
    }
    setupScrollHandler() {
        let rafId = null;
        this.scrollHandler = () => {
            if (rafId !== null)
                return;
            rafId = requestAnimationFrame(() => {
                this.calculateH2Progress();
                this.clickedH2Index = -1;
                rafId = null;
            });
        };
        window.addEventListener('scroll', this.scrollHandler, { passive: true });
    }
    calculateH2Progress() {
        const h2Items = this.items.filter(item => item.level === 2);
        const newProgressMap = new Map();
        const scrollPosition = window.scrollY + 32;
        h2Items.forEach((h2Item, h2Index) => {
            const h2Element = document.getElementById(h2Item.id);
            if (!h2Element) {
                newProgressMap.set(h2Index, 0);
                return;
            }
            const nextH2Item = h2Items[h2Index + 1];
            const nextH2Element = nextH2Item ? document.getElementById(nextH2Item.id) : null;
            const h2Top = h2Element.offsetTop;
            const nextH2Top = nextH2Element ? nextH2Element.offsetTop : document.body.scrollHeight;
            const sectionHeight = nextH2Top - h2Top;
            if (scrollPosition < h2Top) {
                newProgressMap.set(h2Index, 0);
            }
            else if (scrollPosition >= nextH2Top) {
                newProgressMap.set(h2Index, 100);
            }
            else {
                const progress = ((scrollPosition - h2Top) / sectionHeight) * 100;
                newProgressMap.set(h2Index, Math.min(Math.max(progress, 0), 100));
            }
        });
        this.h2ProgressPercents = newProgressMap;
    }
    handleTocItemsChanged(event) {
        const tocWrapper = this.el.closest('spw-toc');
        const container = event.target;
        const containerWrapper = container.closest('spw-toc');
        if (tocWrapper === containerWrapper) {
            this.items = event.detail;
            if (this.observer) {
                this.observer.disconnect();
            }
            this.setupIntersectionObserver();
        }
    }
    setupIntersectionObserver() {
        const options = {
            rootMargin: '-32px 0px -66%',
            threshold: 0,
        };
        this.observer = new IntersectionObserver(entries => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    const id = entry.target.id;
                    const index = this.items.findIndex(item => item.id === id);
                    if (index !== -1) {
                        this.currentItemIndex = index;
                        const item = this.items[index];
                        if (item.level === 2) {
                            const h2Items = this.items.filter(i => i.level === 2);
                            this.currentH2Index = h2Items.findIndex(i => i.id === id);
                        }
                        else {
                            const h2Items = this.items.filter(i => i.level === 2);
                            for (let i = index; i >= 0; i--) {
                                if (this.items[i].level === 2) {
                                    this.currentH2Index = h2Items.findIndex(h2 => h2.id === this.items[i].id);
                                    break;
                                }
                            }
                        }
                    }
                }
            });
        }, options);
        this.items.forEach(item => {
            const element = document.getElementById(item.id);
            if (element) {
                this.observer.observe(element);
            }
        });
    }
    handleItemClick(event, id, index) {
        event.preventDefault();
        const targetElement = document.getElementById(id);
        if (targetElement) {
            const elementPosition = targetElement.getBoundingClientRect().top;
            const offsetPosition = elementPosition + window.scrollY - 32;
            window.scrollTo({
                top: offsetPosition + 1,
                behavior: 'smooth',
            });
            this.currentItemIndex = index;
            const item = this.items[index];
            if (item.level === 2) {
                const h2Items = this.items.filter(i => i.level === 2);
                const h2Index = h2Items.findIndex(i => i.id === id);
                this.currentH2Index = h2Index;
                this.clickedH2Index = h2Index;
            }
            else {
                const h2Items = this.items.filter(i => i.level === 2);
                for (let i = index; i >= 0; i--) {
                    if (this.items[i].level === 2) {
                        const h2Index = h2Items.findIndex(h2 => h2.id === this.items[i].id);
                        this.currentH2Index = h2Index;
                        this.clickedH2Index = h2Index;
                        break;
                    }
                }
            }
            this.calculateH2ProgressWithTargetScroll(offsetPosition + 1);
            const url = new URL(window.location.href);
            url.hash = id;
            window.history.pushState({}, '', url);
        }
    }
    calculateH2ProgressWithTargetScroll(targetScrollY) {
        const h2Items = this.items.filter(item => item.level === 2);
        const newProgressMap = new Map();
        const scrollPosition = targetScrollY + 32;
        h2Items.forEach((h2Item, h2Index) => {
            const h2Element = document.getElementById(h2Item.id);
            if (!h2Element) {
                newProgressMap.set(h2Index, 0);
                return;
            }
            const nextH2Item = h2Items[h2Index + 1];
            const nextH2Element = nextH2Item ? document.getElementById(nextH2Item.id) : null;
            const h2Top = h2Element.offsetTop;
            const nextH2Top = nextH2Element ? nextH2Element.offsetTop : document.body.scrollHeight;
            const sectionHeight = nextH2Top - h2Top;
            if (scrollPosition < h2Top) {
                newProgressMap.set(h2Index, 0);
            }
            else if (scrollPosition >= nextH2Top) {
                newProgressMap.set(h2Index, 100);
            }
            else {
                const progress = ((scrollPosition - h2Top) / sectionHeight) * 100;
                newProgressMap.set(h2Index, Math.min(Math.max(progress, 0), 100));
            }
        });
        this.h2ProgressPercents = new Map(newProgressMap);
    }
    isItemActive(index, item) {
        if (this.variant === 'simple') {
            return this.currentItemIndex === index;
        }
        let h2IndexForItem = -1;
        if (item.level === 2) {
            const h2Items = this.items.filter(i => i.level === 2);
            h2IndexForItem = h2Items.findIndex(h2 => h2.id === item.id);
        }
        else {
            const h2Items = this.items.filter(i => i.level === 2);
            for (let i = index; i >= 0; i--) {
                if (this.items[i].level === 2) {
                    h2IndexForItem = h2Items.findIndex(h2 => h2.id === this.items[i].id);
                    break;
                }
            }
        }
        if (this.clickedH2Index >= 0 && h2IndexForItem === this.clickedH2Index) {
            return true;
        }
        const progress = h2IndexForItem >= 0 ? this.getH2Progress(h2IndexForItem) : 0;
        return progress > 0;
    }
    getH2Progress(h2Index) {
        return this.h2ProgressPercents.get(h2Index) || 0;
    }
    getH2BarStatus(progress) {
        if (progress >= 100) {
            return 'completed';
        }
        else if (progress > 0) {
            return 'active';
        }
        else {
            return 'pending';
        }
    }
    render() {
        if (this.items.length === 0) {
            return null;
        }
        const isProgress = this.variant === 'progress';
        const h2Items = this.items.filter(item => item.level === 2);
        return (h(Host, null, h("nav", { class: {
                'spw-toc': true,
                'spw-toc--progress': isProgress,
                'spw-toc--simple': !isProgress,
            } }, h("ul", null, this.items.map((item, index) => {
            var _a;
            let h2IndexForItem = -1;
            if (item.level === 2) {
                h2IndexForItem = h2Items.findIndex(h2 => h2.id === item.id);
            }
            else {
                for (let i = index; i >= 0; i--) {
                    if (this.items[i].level === 2) {
                        h2IndexForItem = h2Items.findIndex(h2 => h2.id === this.items[i].id);
                        break;
                    }
                }
            }
            const progress = isProgress && h2IndexForItem >= 0 ? this.getH2Progress(h2IndexForItem) : 0;
            const barStatus = isProgress ? this.getH2BarStatus(progress) : 'pending';
            let distanceToNextH2 = 0;
            if (isProgress && item.level === 2) {
                distanceToNextH2 = (_a = this.h2Distances.get(index)) !== null && _a !== void 0 ? _a : 0;
            }
            const styleVars = {};
            if (isProgress && item.level === 2) {
                styleVars['--progress'] = `${progress}`;
                if (distanceToNextH2 > 0) {
                    styleVars['--distance-to-next-h2'] = `${distanceToNextH2}px`;
                }
            }
            return (h("li", { key: item.id, class: {
                    [`--toc-is-level-${item.level}`]: true,
                    '--toc-active': isProgress && this.isItemActive(index, item),
                    '--toc-bar-completed': isProgress && barStatus === 'completed',
                    '--toc-bar-active': isProgress && barStatus === 'active',
                    '--toc-bar-pending': isProgress && barStatus === 'pending',
                    '--toc-is-h2': item.level === 2,
                }, style: styleVars }, isProgress && item.level === 2 && h("span", { class: "spw-toc__progress-dot" }), h("a", { href: `#${item.id}`, onClick: e => this.handleItemClick(e, item.id, index) }, item.text)));
        })))));
    }
    static get is() { return "spw-toc-navigation"; }
    static get originalStyleUrls() {
        return {
            "$": ["spw-toc-navigation.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["spw-toc-navigation.css"]
        };
    }
    static get properties() {
        return {
            "variant": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "'progress' | 'simple'",
                    "resolved": "\"progress\" | \"simple\"",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Variante d'affichage : 'progress' (avec barre de progression) ou 'simple' (sans barre)"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "variant",
                "defaultValue": "'progress'"
            }
        };
    }
    static get states() {
        return {
            "items": {},
            "currentItemIndex": {},
            "currentH2Index": {},
            "h2ProgressPercents": {},
            "clickedH2Index": {},
            "h2Distances": {}
        };
    }
    static get elementRef() { return "el"; }
    static get listeners() {
        return [{
                "name": "tocItemsChanged",
                "method": "handleTocItemsChanged",
                "target": "window",
                "capture": false,
                "passive": false
            }];
    }
}
