/**
 * @license Copyright (c) 2017-2025, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md.
 */

import { BaseComponent } from '../components/base-component';
import { toggleHeight } from '../helpers/toggle-height';
import { getParentsUntil } from '../helpers/get-parents-until';

const SIDEBAR_LOCAL_STORAGE_KEY = 'foldersState';

export class NavTree extends BaseComponent {
	/**
	 * Creates a navigation tree component.
	 *
	 * @param element - The navigation tree element.
	 */
	constructor( element ) {
		super( {
			foldersState: JSON.parse( localStorage.getItem( SIDEBAR_LOCAL_STORAGE_KEY ) ) || {}
		} );

		this.elements = {
			navTree: element,
			sidebarSubLists: element.querySelectorAll( '.c-nav-tree__nested-list' )
		};
	}

	/**
	 * Initializes navigation tree component on the page.
	 */
	static attach() {
		const navTrees = document.querySelectorAll( '.js-nav-tree' );

		navTrees.forEach( navTree => {
			new NavTree( navTree ).init();
		} );
	}

	/**
	 * Initializes the navigation tree component with event listeners.
	 */
	init() {
		const { navTree } = this.elements;

		navTree?.addEventListener( 'click', async event => {
			const button = event.target.closest( 'button' );

			if ( !button ) {
				return;
			}

			const isExpanded = button.getAttribute( 'aria-expanded' ) === 'true';
			const nextSibling = button.nextElementSibling;

			if ( !nextSibling ) {
				return;
			}

			const toggleState = await toggleHeight( nextSibling, 'c-nav-tree__nested-list--hidden' );

			// Update ARIA attributes for accessibility
			nextSibling.setAttribute( 'aria-hidden', !isExpanded );
			button.setAttribute( 'aria-expanded', isExpanded );

			this.saveFolderState( nextSibling.getAttribute( 'data-id' ), toggleState == 'visible' ? false : true );
		} );

		this.initialApplyFolderState();
		this.expandWhereYouAre();
		this.render();
	}

	render() {
		// No specific rendering logic for the navigation tree component.
	}

	/**
	 * Applies the initial state of the folders in the sidebar.
	 */
	initialApplyFolderState() {
		const { sidebarSubLists } = this.elements;
		const { foldersState } = this.state;

		if ( Object.keys( foldersState ).length === 0 ) {
			this.dispatchInitialFolderStateDoneEvent();

			return;
		}

		sidebarSubLists.forEach( element => {
			const id = element.getAttribute( 'data-id' );
			const isFolded = foldersState[ id ];
			const hasKey = Object.prototype.hasOwnProperty.call( foldersState, id );

			if ( hasKey ) {
				const button = element.previousElementSibling;

				if ( isFolded ) {
					element.classList.add( 'c-nav-tree__nested-list--hidden' );
					element.style.height = '0px';
					button?.setAttribute( 'aria-expanded', 'false' );
				} else {
					element.classList.remove( 'c-nav-tree__nested-list--hidden' );
					element.style.height = '';
					button?.setAttribute( 'aria-expanded', 'true' );
				}
			}
		} );

		this.dispatchInitialFolderStateDoneEvent();
	}

	/**
	 * Saves the state of the folder in local storage.
	 *
	 * @param id - The ID of the folder.
	 * @param state - The state of the folder (true for folded, false for unfolded).
	 */
	saveFolderState( id, state ) {
		const { foldersState } = this.state;

		foldersState[ id ] = state;
		window.localStorage.setItem( SIDEBAR_LOCAL_STORAGE_KEY, JSON.stringify( foldersState ) );
	}

	/**
	 * Dispatches an event indicating that the initial folder state has been applied.
	 */
	dispatchInitialFolderStateDoneEvent() {
		const folderStateDoneEvent = new CustomEvent( 'sidebar-folderstate:done', {
			bubbles: true,
			detail: { text: () => 'Sidebar folderstate has been initialized.' }
		} );

		document.dispatchEvent( folderStateDoneEvent );
	}

	/**
	 * Expands the navigation tree to show the current page's location.
	 */
	expandWhereYouAre() {
		const activeLink = this.elements.navTree.querySelector( '.c-nav-tree__link--active' );

		if ( !activeLink ) {
			return;
		}

		const ancestors = getParentsUntil( activeLink, '.js-nav-tree' );
		const nestedLists = ancestors.filter( ancestor => ancestor.classList.contains( 'c-nav-tree__nested-list' ) );

		nestedLists.forEach( list => {
			const id = list.getAttribute( 'data-id' );
			const button = list.previousElementSibling;

			if ( button ) {
				list.classList.remove( 'c-nav-tree__nested-list--hidden' );
				list.style.height = '';
				button.setAttribute( 'aria-expanded', 'true' );
				this.saveFolderState( id, false );
			}
		} );
	}
}
