import {makeArray, Expander} from '../../../themes/springernature/js/helpers';

class EdsCAccordion {

	constructor(selector = 'data-eds-c-accordion', options = {}){
		this.triggersSelector = `[${selector}]`;
		this.options = {
			showMoreHeight: 300,
			...options
		};
	}

	findTarget(headerElement, selector){
		if (selector) {
			return document.querySelector(selector);
		}
		return null;
	}

	initShowMore() {
		const contentWrappers = document.querySelectorAll('[data-eds-c-accordion-expandable]');
		
		if (contentWrappers.length === 0) {
			return;
		}

		makeArray(contentWrappers).forEach(contentWrapper => {
			const heightThreshold = this.getHeightThreshold(contentWrapper);
			
			// Only apply show more/less if content exceeds the height threshold
			if (contentWrapper.scrollHeight <= heightThreshold) {
				return;
			}

			const focusableElements = this.getFocusableElements(contentWrapper);
			
			// Add class to enable height restriction CSS
			contentWrapper.classList.add('eds-c-accordion__content--has-show-more');
			
			// Initially hide elements beyond the threshold from keyboard navigation
			this.setFocusabilityForCollapsedState(contentWrapper, focusableElements, heightThreshold);

			// Create and insert the toggle button
			const button = this.createShowMoreButton(contentWrapper);
			contentWrapper.parentNode.insertBefore(button, contentWrapper.nextSibling);

			// Handle expand/collapse toggle
			button.addEventListener('click', () => {
				this.toggleExpandedState(button, contentWrapper, focusableElements, heightThreshold);
			});
		});
	}

	getHeightThreshold(contentWrapper) {
		// Priority: HTML data attribute > JS constructor option > default 300px
		const dataAttribute = contentWrapper.getAttribute('data-show-more-height');
		const configuredHeight = dataAttribute || this.options.showMoreHeight || '300';
		return parseInt(configuredHeight, 10);
	}

	getFocusableElements(container) {
		const selector = 'a, button, input, textarea, select, [tabindex]:not([tabindex="-1"])';
		return container.querySelectorAll(selector);
	}

	setFocusabilityForCollapsedState(contentWrapper, focusableElements, heightThreshold) {
		const wrapperRect = contentWrapper.getBoundingClientRect();
		
		makeArray(focusableElements).forEach(element => {
			const elementRect = element.getBoundingClientRect();
			const elementPositionFromTop = elementRect.top - wrapperRect.top;
			
			// Remove from tab order if element is beyond visible threshold
			if (elementPositionFromTop >= heightThreshold) {
				element.setAttribute('tabindex', '-1');
			}
		});
	}

	setFocusabilityForExpandedState(focusableElements) {
		// Restore normal tab order for all elements
		makeArray(focusableElements).forEach(element => {
			element.removeAttribute('tabindex');
		});
	}

	createShowMoreButton(contentWrapper) {
		const showMoreText = contentWrapper.getAttribute('data-show-more-text') || 'Show more';
		const showLessText = contentWrapper.getAttribute('data-show-less-text') || 'Show less';
		const iconURL = contentWrapper.getAttribute('data-icon-url');

		const button = document.createElement('button');
		button.type = 'button';
		button.className = 'eds-c-accordion__btn-show-more';
		button.setAttribute('data-eds-c-accordion-toggle', '');
		button.setAttribute('aria-expanded', 'false');

		button.innerHTML = `
			${iconURL ? `<svg class="eds-c-accordion__btn-show-more-icon" aria-hidden="true" focusable="false"><use xlink:href="${iconURL}"></use></svg>` : ''}
			<span class="eds-c-accordion__btn-show-more-text">${showMoreText}</span>
			<span class="eds-c-accordion__btn-show-less-text">${showLessText}</span>
		`;

		return button;
	}

	toggleExpandedState(button, contentWrapper, focusableElements, heightThreshold) {
		const isCurrentlyExpanded = button.getAttribute('aria-expanded') === 'true';
		
		if (isCurrentlyExpanded) {
			// Collapse
			contentWrapper.classList.remove('is-expanded');
			button.setAttribute('aria-expanded', 'false');
			this.setFocusabilityForCollapsedState(contentWrapper, focusableElements, heightThreshold);
		} else {
			// Expand
			contentWrapper.classList.add('is-expanded');
			button.setAttribute('aria-expanded', 'true');
			this.setFocusabilityForExpandedState(focusableElements);
		}
	}

	syncHeadingWrapperState(trigger) {
		const headingWrapper = trigger.closest('.eds-c-accordion__heading-wrapper');
		if (!headingWrapper) {
			return;
		}

		// Mirror the button's is-open class to the heading wrapper for CSS styling
		const syncClass = () => {
			headingWrapper.classList.toggle('is-open', trigger.classList.contains('is-open'));
		};

		// Set initial state
		syncClass();

		// Keep wrapper in sync when button state changes
		const observer = new MutationObserver(syncClass);
		observer.observe(trigger, {
			attributes: true,
			attributeFilter: ['class']
		});
	}

	init() {
		const triggerElements = document.querySelectorAll(this.triggersSelector);
		if (triggerElements.length === 0) {
			return;
		}

		makeArray(triggerElements).forEach(trigger => {
			const targetElementSelector = trigger.getAttribute('aria-controls');
			if (!targetElementSelector) {
				return;
			}
			const targetElement = document.querySelector(`#${targetElementSelector}`);
			if (!targetElement) {
				return;
			}

			const defaultOpen = trigger.getAttribute('aria-expanded');

			const expander = new Expander(trigger, targetElement, {
				AUTOFOCUS: 'firstTabbable',
				DEFAULT_OPEN: defaultOpen === 'true',
				CLOSE_ON_DOCUMENT_CLICK: false,
				CLOSE_ON_FOCUS_OUT: false
			});
			expander.init();

			this.syncHeadingWrapperState(trigger);

			return expander;
		});

		this.initShowMore();
	}
}

export default EdsCAccordion;
