/**
 * InhaltsverzeichnisScrollspy Web Component
 *
 * Manages dynamic show/hide of content in the Inhaltsverzeichnis based on:
 * 1. Page container visibility (>40% threshold)
 * 2. Single page viewer mode
 *
 * Features:
 * - Short mode: Hides continuation entries and multipart parts
 * - Full mode: Shows all content when page is prominently visible
 * - Self-contained with proper lifecycle management
 * - HTMX-safe cleanup
 */
export class InhaltsverzeichnisScrollspy extends HTMLElement {
    constructor() {
        super();
        this.pageObserver = null;
        this.pageContainers = new Map(); // pageNumber -> { container, entries, state }
        this.singlePageViewerActive = false;
        this.singlePageViewerCurrentPage = null; // Track which page is currently viewed in single page mode
        this.boundHandleSinglePageViewer = this.handleSinglePageViewer.bind(this);
        this.eventListenersAttached = false; // Track if global event listeners are attached
    }

    connectedCallback() {
        // Use requestAnimationFrame to ensure DOM is fully settled after HTMX content swap
        requestAnimationFrame(() => {
            this.setupScrollspy();
            this.setupSinglePageViewerDetection();
        });
    }

    disconnectedCallback() {
        this.cleanup();
    }

    setupScrollspy() {
        // Find all page containers in the newspaper layout
        const newspaperPageContainers = document.querySelectorAll('.newspaper-page-container[data-page-container]');

        if (newspaperPageContainers.length === 0) {
            // No page containers found initially - retry after a short delay for HTMX content
            setTimeout(() => {
                const retryContainers = document.querySelectorAll('.newspaper-page-container[data-page-container]');
                if (retryContainers.length > 0) {
                    this.initializeScrollspy(retryContainers);
                }
            }, 100);
            return;
        }

        this.initializeScrollspy(newspaperPageContainers);
    }

    initializeScrollspy(newspaperPageContainers) {

        // Clear existing state to prevent conflicts during HTMX navigation
        if (this.pageObserver) {
            this.pageObserver.disconnect();
        }
        this.pageContainers.clear();

        // Map page containers to their corresponding Inhaltsverzeichnis entries
        newspaperPageContainers.forEach(container => {
            const pageNumber = container.getAttribute('data-page-container');
            const isBeilage = container.hasAttribute('data-beilage');

            // Find corresponding Inhaltsverzeichnis entries
            const entries = this.findInhaltsEntriesForPage(pageNumber, isBeilage);

            if (entries.length > 0) {
                this.pageContainers.set(pageNumber, {
                    container,
                    entries,
                    state: 'short', // Default state
                    isBeilage
                });
            }
        });

        // Set up intersection observer with 50% threshold
        this.pageObserver = new IntersectionObserver((observerEntries) => {
            observerEntries.forEach(entry => {
                const pageNumber = entry.target.getAttribute('data-page-container');
                const pageData = this.pageContainers.get(pageNumber);

                if (pageData) {
                    // Use 50% visibility threshold for full mode
                    const shouldBeFullMode = entry.isIntersecting && entry.intersectionRatio >= 0.5;
                    const newState = shouldBeFullMode || this.singlePageViewerActive ? 'full' : 'short';

                    const stateChanged = pageData.state !== newState;
                    if (stateChanged) {
                        pageData.state = newState;
                        this.updateEntriesState(pageData);
                    } else if (newState === 'full' && entry.isIntersecting && entry.intersectionRatio >= 0.5) {
                        // Page is becoming visible and should be highlighted - trigger scroll even if state didn't change
                        this.scrollPageIntoInhaltsverzeichnis(pageData);
                    }
                }
            });
        }, {
            threshold: [0, 0.5, 1.0], // Watch for 50% threshold
            rootMargin: '0px'
        });

        // Observe all page containers
        this.pageContainers.forEach(({ container }) => {
            this.pageObserver.observe(container);
        });

        // Initialize all entries to short mode
        this.pageContainers.forEach(pageData => {
            this.updateEntriesState(pageData);
        });
    }

    findInhaltsEntriesForPage(pageNumber, isBeilage = false) {
        // Look for page entries in the Inhaltsverzeichnis that match this page
        const selector = isBeilage
            ? `[data-page-container="${pageNumber}"][data-beilage="true"]`
            : `[data-page-container="${pageNumber}"]:not([data-beilage])`;

        const pageEntryContainer = this.querySelector(selector);

        if (!pageEntryContainer) {
            return [];
        }

        // Get all inhalts-entry elements within this page container
        return Array.from(pageEntryContainer.querySelectorAll('.inhalts-entry'));
    }

    updateEntriesState(pageData) {
        const { entries, state } = pageData;

        if (state === 'full') {
            // Page is expanded: show all entries and highlight page elements
            entries.forEach(entry => {
                entry.style.display = '';
            });
            this.highlightPageElements(pageData, true);
        } else {
            // Page is collapsed: hide continuation entries and remove highlighting
            entries.forEach(entry => {
                const isContinuation = entry.hasAttribute('data-is-continuation');
                entry.style.display = isContinuation ? 'none' : '';
            });
            this.highlightPageElements(pageData, false);
        }
    }

    highlightPageElements(pageData, highlight) {
        const pageNumber = pageData.container.getAttribute('data-page-container');

        // 1. Highlight in Inhaltsverzeichnis (page number + icon + border)
        const pageLink = this.querySelector(`[data-page-number="${pageNumber}"]`);
        const iconContainer = pageLink?.closest('.page-entry')?.querySelector('.icon-container');
        const pageEntryContainer = pageLink?.closest('.page-entry');

        // Keep page number and icons unchanged in Inhaltsverzeichnis

        if (pageEntryContainer) {
            if (highlight) {
                pageEntryContainer.classList.add('!border-l-red-500');
                pageEntryContainer.classList.remove('border-slate-300');
            } else {
                pageEntryContainer.classList.remove('!border-l-red-500');
                pageEntryContainer.classList.add('border-slate-300');
            }

            // Always scroll highlighted entry into view when it becomes active
            if (highlight) {
                this.scrollEntryIntoView(pageEntryContainer);
            }
        }

        // 2. Highlight in layout view (page indicator above image)
        const layoutPageIndicator = document.querySelector(`[data-page="${pageNumber}"].page-indicator`);

        if (layoutPageIndicator) {
            // Only highlight primary (non-greyed) icons in layout view too
            const layoutPrimaryIcons = layoutPageIndicator.querySelectorAll('i:not(.text-slate-400)');
            if (highlight) {
                layoutPageIndicator.classList.add('!bg-red-50', '!text-red-600');
                layoutPrimaryIcons.forEach(icon => icon.classList.add('!text-red-600'));
            } else {
                layoutPageIndicator.classList.remove('!bg-red-50', '!text-red-600');
                layoutPrimaryIcons.forEach(icon => icon.classList.remove('!text-red-600'));
            }
        }
    }

    scrollEntryIntoView(pageEntryContainer) {
        // Find the scrollable Inhaltsverzeichnis container
        const scrollableContainer = document.querySelector('.overflow-y-auto');

        if (!scrollableContainer || !pageEntryContainer) {
            return;
        }

        // Check if this is the first or last page entry to handle edge cases
        const allPageEntries = scrollableContainer.querySelectorAll('.page-entry');
        const isFirstPage = allPageEntries.length > 0 && allPageEntries[0] === pageEntryContainer;
        const isLastPage = allPageEntries.length > 0 && allPageEntries[allPageEntries.length - 1] === pageEntryContainer;

        if (isFirstPage) {
            // Scroll to the very top for the first page
            scrollableContainer.scrollTo({
                top: 0,
                behavior: 'smooth'
            });
            return;
        }

        if (isLastPage) {
            // Scroll to the very bottom for the last page
            scrollableContainer.scrollTo({
                top: scrollableContainer.scrollHeight,
                behavior: 'smooth'
            });
            return;
        }

        // Get container and element positions for middle pages
        const containerRect = scrollableContainer.getBoundingClientRect();
        const elementRect = pageEntryContainer.getBoundingClientRect();

        // Check if element is already fully visible
        const isVisible = elementRect.top >= containerRect.top &&
                         elementRect.bottom <= containerRect.bottom;

        if (!isVisible) {
            // Calculate the scroll position to center the element in the container
            const containerScrollTop = scrollableContainer.scrollTop;
            const elementTop = elementRect.top - containerRect.top + containerScrollTop;
            const containerHeight = containerRect.height;
            const elementHeight = elementRect.height;

            // Center the element in the container
            const scrollTo = elementTop - (containerHeight - elementHeight) / 2;

            scrollableContainer.scrollTo({
                top: Math.max(0, scrollTo),
                behavior: 'smooth'
            });
        }
    }

    scrollPageIntoInhaltsverzeichnis(pageData) {
        const pageNumber = pageData.container.getAttribute('data-page-container');
        const pageLink = this.querySelector(`[data-page-number="${pageNumber}"]`);
        const pageEntryContainer = pageLink?.closest('.page-entry');

        if (pageEntryContainer) {
            this.scrollEntryIntoView(pageEntryContainer);
        }
    }

    setupSinglePageViewerDetection() {
        // Only attach event listeners if not already attached
        if (!this.eventListenersAttached) {
            document.addEventListener('singlepageviewer:opened', this.boundHandleSinglePageViewer);
            document.addEventListener('singlepageviewer:closed', this.boundHandleSinglePageViewer);
            document.addEventListener('singlepageviewer:pagechanged', this.boundHandleSinglePageViewer);
            this.eventListenersAttached = true;
        }

        // Check initial state
        this.checkSinglePageViewerState();
    }

    handleSinglePageViewer(event) {
        const wasActive = this.singlePageViewerActive;
        this.singlePageViewerActive = event.type === 'singlepageviewer:opened' ||
                                      (event.type === 'singlepageviewer:pagechanged' && this.singlePageViewerActive);

        // Track which page is currently being viewed in single page mode
        if ((this.singlePageViewerActive || event.type === 'singlepageviewer:pagechanged') && event.detail?.pageNumber) {
            this.singlePageViewerCurrentPage = event.detail.pageNumber.toString();
        } else if (event.type === 'singlepageviewer:closed') {
            this.singlePageViewerCurrentPage = null;
            this.singlePageViewerActive = false;
        }

        // Re-evaluate all page states
        this.pageContainers.forEach(pageData => {
            const pageNumber = pageData.container.getAttribute('data-page-container');
            let newState;

            if (this.singlePageViewerActive) {
                // In single page viewer: only expand and highlight the current page, collapse all others
                newState = pageNumber === this.singlePageViewerCurrentPage ? 'full' : 'short';
            } else {
                // Normal mode: based on scroll position
                newState = this.isPageContainerVisible(pageData.container) ? 'full' : 'short';
            }

            if (pageData.state !== newState) {
                pageData.state = newState;
                this.updateEntriesState(pageData);
            }
        });
    }

    checkSinglePageViewerState() {
        // Check if single page viewer is currently active
        const viewer = document.querySelector('single-page-viewer[active]');
        this.singlePageViewerActive = viewer !== null;
    }

    isPageContainerVisible(container) {
        const rect = container.getBoundingClientRect();
        const viewportHeight = window.innerHeight;

        const visibleTop = Math.max(rect.top, 0);
        const visibleBottom = Math.min(rect.bottom, viewportHeight);
        const visibleHeight = Math.max(0, visibleBottom - visibleTop);
        const containerHeight = rect.height;

        return (visibleHeight / containerHeight) >= 0.5;
    }

    cleanup() {
        if (this.pageObserver) {
            this.pageObserver.disconnect();
            this.pageObserver = null;
        }

        // Only remove event listeners if they were attached
        if (this.eventListenersAttached) {
            document.removeEventListener('singlepageviewer:opened', this.boundHandleSinglePageViewer);
            document.removeEventListener('singlepageviewer:closed', this.boundHandleSinglePageViewer);
            document.removeEventListener('singlepageviewer:pagechanged', this.boundHandleSinglePageViewer);
            this.eventListenersAttached = false;
        }

        this.pageContainers.clear();
    }
}

// Register the custom element
customElements.define('inhaltsverzeichnis-scrollspy', InhaltsverzeichnisScrollspy);