import { ExecuteNextSettle } from "./helpers.js";
// ===========================
// AKTEURE/AUTHORS SCROLLSPY WEB COMPONENT
// ===========================

export class AkteureScrollspy extends HTMLElement {
	constructor() {
		super();
		this.scrollTimeout = null;
		this.clickHandlers = [];
		this.manualNavigation = false;
		this.handleScroll = this.handleScroll.bind(this);
	}

	handleScroll() {
		clearTimeout(this.scrollTimeout);
		this.scrollTimeout = setTimeout(() => {
			this.updateActiveLink();
			this.updateSidebarScrollToTopButton();
		}, 50);
	}

	connectedCallback() {
		// Use a simple timeout to ensure DOM is settled after the component is connected.
		// This is more reliable than the external settleQueue for popstate navigation.
		setTimeout(() => {
			this.initializeScrollspyAfterDelay();
		}, 50);

		// Handle page restoration from bfcache
		window.addEventListener("pageshow", (event) => {
			if (event.persisted) {
				// Page was restored from bfcache, re-initialize
				this.cleanup();
				this.initializeScrollspy();
			}
		});
	}

	initializeScrollspyAfterDelay() {
		// Find sections and nav links
		this.sections = document.querySelectorAll(".author-section");
		this.navLinks = document.querySelectorAll(".scrollspy-link");

		if (this.sections.length === 0 || this.navLinks.length === 0) {
			// Retry after a bit more time if elements not found
			setTimeout(() => {
				this.sections = document.querySelectorAll(".author-section");
				this.navLinks = document.querySelectorAll(".scrollspy-link");
				if (this.sections.length > 0 && this.navLinks.length > 0) {
					this.initializeScrollspy();
				}
			}, 500);
			return;
		}

		this.initializeScrollspy();
	}

	disconnectedCallback() {
		this.cleanup();
	}

	initializeScrollspy() {
		window.addEventListener("scroll", this.handleScroll);

		// Add smooth scroll on link click
		this.navLinks.forEach((link) => {
			const clickHandler = (e) => {
				e.preventDefault();
				const targetId = link.getAttribute("data-target");
				const target = document.getElementById(targetId);
				if (target) {
					// Immediately update the active link highlighting on click
					this.updateActiveLinkImmediate(targetId);

					// Temporarily disable automatic sidebar scrolling during manual navigation
					this.manualNavigation = true;

					target.scrollIntoView({
						behavior: "instant",
						block: "start",
					});

					// Re-enable automatic scrolling after navigation completes
					setTimeout(() => {
						this.manualNavigation = false;
						// Ensure the full marker is visible after scroll settles
						this.ensureMarkerVisibility();
					}, 1000);
				}
			};

			this.clickHandlers.push({ link, handler: clickHandler });
			link.addEventListener("click", clickHandler);
		});

		// Initial active link update - with small delay to ensure layout is settled
		setTimeout(() => {
			this.updateActiveLink();
		}, 300);

		// Initial scroll-to-top button update
		this.updateSidebarScrollToTopButton();
	}

	ensureMarkerVisibility() {
		const slider = document.getElementById("scrollspy-slider");
		const nav = document.getElementById("scrollspy-nav");

		if (!slider || !nav || slider.style.opacity === "0") {
			return;
		}

		const navRect = nav.getBoundingClientRect();
		const sliderTop = parseFloat(slider.style.top);
		const sliderHeight = parseFloat(slider.style.height);
		const sliderBottom = sliderTop + sliderHeight;

		// Check if the marker extends beyond the visible area
		const navScrollTop = nav.scrollTop;
		const navVisibleBottom = navScrollTop + navRect.height;

		if (sliderBottom > navVisibleBottom) {
			// Marker extends below visible area - scroll down to show the bottom
			const scrollTarget = sliderBottom - navRect.height + 20; // 20px padding
			nav.scrollTo({
				top: scrollTarget,
				behavior: "smooth",
			});
		} else if (sliderTop < navScrollTop) {
			// Marker extends above visible area - scroll up to show the top
			const scrollTarget = sliderTop - 20; // 20px padding
			nav.scrollTo({
				top: Math.max(0, scrollTarget),
				behavior: "smooth",
			});
		}
	}

	updateActiveLink() {
		// Safety check: ensure DOM elements still exist
		if (!this.sections || !this.navLinks) {
			return;
		}

		const visibleSections = [];
		const viewportTop = window.scrollY;
		const viewportBottom = viewportTop + window.innerHeight;

		// Check which sections have any part of their Werke or Beiträge visible
		try {
			this.sections.forEach((section) => {
				if (!section || !section.getAttribute) return;
				const sectionId = section.getAttribute("id");

				// Find Werke and Beiträge sections within this author section
				const werkeSection = section.querySelector(".akteur-werke-section");
				const beitraegeSection = section.querySelector(".akteur-beitraege-section");

				let isVisible = false;

				// Check if any part of Werke section is visible
				if (werkeSection) {
					const werkeRect = werkeSection.getBoundingClientRect();
					const werkeTopVisible = werkeRect.top < window.innerHeight;
					const werkeBottomVisible = werkeRect.bottom > 0;
					if (werkeTopVisible && werkeBottomVisible) {
						isVisible = true;
					}
				}

				// Check if any part of Beiträge section is visible
				if (beitraegeSection && !isVisible) {
					const beitraegeRect = beitraegeSection.getBoundingClientRect();
					const beitraegeTopVisible = beitraegeRect.top < window.innerHeight;
					const beitraegeBottomVisible = beitraegeRect.bottom > 0;
					if (beitraegeTopVisible && beitraegeBottomVisible) {
						isVisible = true;
					}
				}

				// Fallback: if no Werke/Beiträge sections, check header visibility (for authors without content)
				if (!werkeSection && !beitraegeSection) {
					const headerElement = section.querySelector("div:first-child");
					if (headerElement) {
						const headerRect = headerElement.getBoundingClientRect();
						const headerTopVisible = headerRect.top >= 0;
						const headerBottomVisible = headerRect.bottom <= window.innerHeight;
						if (headerTopVisible && headerBottomVisible) {
							isVisible = true;
						}
					}
				}

				if (isVisible) {
					visibleSections.push(sectionId);
				}
			});
		} catch (e) {
			// Handle case where sections became stale during DOM manipulation
			return;
		}

		// Update highlighting with sliding background animation
		const activeLinks = [];
		const slider = document.getElementById("scrollspy-slider");

		// Reset all links to default state (no background, just font weight for active)
		this.navLinks.forEach((link) => {
			link.classList.remove("font-medium");

			const targetId = link.getAttribute("data-target");
			if (visibleSections.includes(targetId)) {
				link.classList.add("font-medium");
				activeLinks.push(link);
			}
		});

		// Calculate and animate the sliding background
		if (activeLinks.length > 0 && slider) {
			// Get the nav container for relative positioning
			const nav = document.getElementById("scrollspy-nav");
			const navRect = nav.getBoundingClientRect();

			// Calculate the combined area of all active links
			let minTop = Infinity;
			let maxBottom = -Infinity;

			activeLinks.forEach((link) => {
				const linkRect = link.getBoundingClientRect();
				const relativeTop = linkRect.top - navRect.top + nav.scrollTop;
				const relativeBottom = relativeTop + linkRect.height;

				minTop = Math.min(minTop, relativeTop);
				maxBottom = Math.max(maxBottom, relativeBottom);
			});

			// Handle gaps between non-consecutive active links
			let totalHeight = maxBottom - minTop;

			// Position and size the slider
			slider.style.top = `${minTop}px`;
			slider.style.height = `${totalHeight}px`;
			slider.style.opacity = "1";

			// Ensure the full marker is visible
			setTimeout(() => this.ensureMarkerVisibility(), 100);
		} else if (slider) {
			// Hide slider when no active links
			slider.style.opacity = "0";
		}

		// Implement proportional scrolling to keep active links visible
		if (activeLinks.length > 0) {
			this.updateSidebarScroll(activeLinks);
		}
	}

	updateActiveLinkImmediate(targetId) {
		// Safety check: ensure DOM elements still exist
		if (!this.navLinks) return;

		const slider = document.getElementById("scrollspy-slider");

		// Reset all links
		try {
			this.navLinks.forEach((link) => {
				if (link && link.classList) {
					link.classList.remove("font-medium");
				}
			});
		} catch (e) {
			// Handle case where navLinks became stale
			return;
		}

		// Highlight the clicked link
		const clickedLink = document.querySelector(`[data-target="${targetId}"]`);
		if (clickedLink) {
			clickedLink.classList.add("font-medium");

			// Update slider position for the single clicked link
			if (slider) {
				const nav = document.getElementById("scrollspy-nav");
				if (nav) {
					const navRect = nav.getBoundingClientRect();
					const linkRect = clickedLink.getBoundingClientRect();

					const relativeTop = linkRect.top - navRect.top + nav.scrollTop;
					slider.style.top = `${relativeTop}px`;
					slider.style.height = `${linkRect.height}px`;
					slider.style.opacity = "1";
				}
			}
		}
	}

	updateSidebarScroll(activeLinks) {
		// Skip automatic scrolling during manual navigation
		if (this.manualNavigation) return;

		const sidebar = document.getElementById("scrollspy-nav");
		if (!sidebar) return;

		// Get the first active link as reference
		const firstActiveLink = activeLinks[0];

		// Calculate the main content scroll progress
		const documentHeight = Math.max(
			document.body.scrollHeight,
			document.body.offsetHeight,
			document.documentElement.clientHeight,
			document.documentElement.scrollHeight,
			document.documentElement.offsetHeight,
		);
		const viewportHeight = window.innerHeight;
		const maxScroll = documentHeight - viewportHeight;
		const scrollProgress = maxScroll > 0 ? window.scrollY / maxScroll : 0;

		// Calculate sidebar scroll dimensions
		const sidebarHeight = sidebar.clientHeight;
		const sidebarScrollHeight = sidebar.scrollHeight;
		const maxSidebarScroll = sidebarScrollHeight - sidebarHeight;

		if (maxSidebarScroll > 0) {
			// Calculate proportional scroll position
			const targetSidebarScroll = scrollProgress * maxSidebarScroll;

			// Get the position of the first active link within the sidebar
			const linkRect = firstActiveLink.getBoundingClientRect();
			const sidebarRect = sidebar.getBoundingClientRect();
			const linkOffsetInSidebar = linkRect.top - sidebarRect.top + sidebar.scrollTop;

			// Calculate the desired position (center the active link in the sidebar viewport)
			const sidebarCenter = sidebarHeight / 2;
			const centeredPosition = linkOffsetInSidebar - sidebarCenter;

			// Use a blend of proportional scrolling and centering for smooth behavior
			const blendFactor = 0.7; // 70% proportional, 30% centering
			const finalScrollPosition =
				blendFactor * targetSidebarScroll + (1 - blendFactor) * centeredPosition;

			// Clamp to valid scroll range
			const clampedPosition = Math.max(0, Math.min(maxSidebarScroll, finalScrollPosition));

			// Apply smooth scrolling, but only if the difference is significant
			const currentScrollTop = sidebar.scrollTop;
			const scrollDifference = Math.abs(clampedPosition - currentScrollTop);

			if (scrollDifference > 10) {
				// Only scroll if more than 10px difference
				sidebar.scrollTo({
					top: clampedPosition,
					behavior: "smooth",
				});
			}
		}
	}

	updateSidebarScrollToTopButton() {
		const button = document.getElementById("sidebar-scroll-to-top");
		if (!button) return;

		const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
		const viewportHeight = window.innerHeight;
		const shouldShow = scrollTop > viewportHeight * 0.5; // Show after scrolling 50% of viewport

		if (shouldShow) {
			button.classList.remove("opacity-0");
			button.classList.add("opacity-100");
		} else {
			button.classList.remove("opacity-100");
			button.classList.add("opacity-0");
		}
	}

	cleanup() {
		// Remove scroll listener
		window.removeEventListener("scroll", this.handleScroll);

		// Clear timeout
		if (this.scrollTimeout) {
			clearTimeout(this.scrollTimeout);
			this.scrollTimeout = null;
		}

		// Remove click handlers
		if (this.clickHandlers && this.clickHandlers.length > 0) {
			this.clickHandlers.forEach(({ link, handler }) => {
				if (link && handler) {
					link.removeEventListener("click", handler);
				}
			});
		}

		// Reset slider
		const slider = document.getElementById("scrollspy-slider");
		if (slider) {
			slider.style.opacity = "0";
			slider.style.height = "0";
		}

		// Clear all references to DOM elements and state
		this.sections = null;
		this.navLinks = null;
		this.clickHandlers = [];
		this.manualNavigation = false;
	}
}

// Register the web component
customElements.define("akteure-scrollspy", AkteureScrollspy);
