/*
 * HSCollapse
 * @version: 4.2.0
 * @author: Preline Labs Ltd.
 * @license: Licensed under MIT and Preline UI Fair Use License (https://preline.co/docs/license.html)
 * Copyright 2024 Preline Labs Ltd.
 */

import { afterTransition, dispatch } from '../../utils';

import { ICollapse } from '../collapse/interfaces';

import HSBasePlugin from '../base-plugin';
import { ICollectionItem } from '../../interfaces';

class HSCollapse extends HSBasePlugin<{}> implements ICollapse {
	private readonly contentId: string | null;
	public content: HTMLElement | null;
	private animationInProcess: boolean;

	private onElementClickListener: () => void;

	constructor(el: HTMLElement, options?: {}, events?: {}) {
		super(el, options, events);

		this.contentId = this.el.dataset.hsCollapse;
		this.content = document.querySelector(this.contentId);
		this.animationInProcess = false;

		if (this.content) this.init();
	}

	private elementClick() {
		if (this.content.classList.contains('open')) {
			this.hide();
		} else {
			this.show();
		}
	}

	private init() {
		this.createCollection(window.$hsCollapseCollection, this);

		this.onElementClickListener = () => this.elementClick();

		if (this?.el?.ariaExpanded) {
			if (this.el.classList.contains('open')) this.el.ariaExpanded = 'true';
			else this.el.ariaExpanded = 'false';
		}

		this.el.addEventListener('click', this.onElementClickListener);
	}

	private hideAllMegaMenuItems() {
		this.content
			.querySelectorAll('.hs-mega-menu-content.block')
			.forEach((el) => {
				el.classList.remove('block');
				el.classList.add('hidden');
			});
	}

	// Public methods
	public show() {
		if (this.animationInProcess || this.el.classList.contains('open')) {
			return false;
		}

		this.animationInProcess = true;

		this.el.classList.add('open');
		if (this?.el?.ariaExpanded) this.el.ariaExpanded = 'true';
		this.content.classList.add('open');
		this.content.classList.remove('hidden');

		this.content.style.height = '0';
		setTimeout(() => {
			this.content.style.height = `${this.content.scrollHeight}px`;

			this.fireEvent('beforeOpen', this.el);
			dispatch('beforeOpen.hs.collapse', this.el, this.el);

			afterTransition(this.content, () => {
				this.content.style.height = '';

				this.fireEvent('open', this.el);
				dispatch('open.hs.collapse', this.el, this.el);

				this.animationInProcess = false;
			});
		});
	}

	public hide() {
		if (this.animationInProcess || !this.el.classList.contains('open')) {
			return false;
		}

		this.animationInProcess = true;

		this.el.classList.remove('open');
		if (this?.el?.ariaExpanded) this.el.ariaExpanded = 'false';

		this.content.style.height = `${this.content.scrollHeight}px`;
		setTimeout(() => {
			this.content.style.height = '0';
		});

		this.content.classList.remove('open');

		afterTransition(this.content, () => {
			this.content.classList.add('hidden');
			this.content.style.height = '';

			this.fireEvent('hide', this.el);
			dispatch('hide.hs.collapse', this.el, this.el);

			this.animationInProcess = false;
		});

		if (this.content.querySelectorAll('.hs-mega-menu-content.block').length) {
			this.hideAllMegaMenuItems();
		}
	}

	public destroy() {
		this.el.removeEventListener('click', this.onElementClickListener);

		this.content = null;
		this.animationInProcess = false;

		window.$hsCollapseCollection = window.$hsCollapseCollection.filter(
			({ element }) => element.el !== this.el,
		);
	}

	// Static methods
	private static findInCollection(
		target: HSCollapse | HTMLElement | string,
	): ICollectionItem<HSCollapse> | null {
		return (
			window.$hsCollapseCollection.find((el) => {
				if (target instanceof HSCollapse) return el.element.el === target.el;
				else if (typeof target === 'string') {
					return el.element.el === document.querySelector(target);
				} else return el.element.el === target;
			}) || null
		);
	}

	static getInstance(target: HTMLElement, isInstance = false) {
		const elInCollection = window.$hsCollapseCollection.find(
			(el) =>
				el.element.el ===
				(typeof target === 'string' ? document.querySelector(target) : target),
		);

		return elInCollection
			? isInstance
				? elInCollection
				: elInCollection.element.el
			: null;
	}

	static autoInit() {
		if (!window.$hsCollapseCollection) window.$hsCollapseCollection = [];

		if (window.$hsCollapseCollection) {
			window.$hsCollapseCollection = window.$hsCollapseCollection.filter(
				({ element }) => document.contains(element.el),
			);
		}

		document
			.querySelectorAll('.hs-collapse-toggle:not(.--prevent-on-load-init)')
			.forEach((el: HTMLElement) => {
				if (
					!window.$hsCollapseCollection.find(
						(elC) => (elC?.element?.el as HTMLElement) === el,
					)
				) {
					new HSCollapse(el);
				}
			});
	}

	static show(target: HSCollapse | HTMLElement | string) {
		const instance = HSCollapse.findInCollection(target);

		if (instance && instance.element.content.classList.contains('hidden'))
			instance.element.show();
	}

	static hide(target: HSCollapse | HTMLElement | string) {
		const instance = HSCollapse.findInCollection(target);

		if (instance && !instance.element.content.classList.contains('hidden'))
			instance.element.hide();
	}

	// Backward compatibility
	static on(
		evt: string,
		target: HSCollapse | HTMLElement | string,
		cb: Function,
	) {
		const instance = HSCollapse.findInCollection(target);

		if (instance) instance.element.events[evt] = cb;
	}
}

export default HSCollapse;
