import { Tooltip } from 'bootstrap';
import { Prop, toNative } from 'vue-facing-decorator';
import TsxComponent, { Component } from '../../app/vuetsx';
import { isNullOrEmpty } from '../../common/utils/is-null-or-empty';
import { PortalUtils } from '../../common/utils/utils';

interface TooltipContainerArgs {
	renderAsSpan?: boolean;
	cssClass?: string;
	tooltipCssClass?: string;
	tooltip: string;
	isHtml?: boolean;
	trigger?: 'click' | 'hover' | 'focus' | 'manual' | 'click hover' | 'click focus' | 'hover focus' | 'click hover focus';
	textAlign?: 'left' | 'middle' | 'right';
	arrowPosition?: 'left' | 'middle' | 'right';
}

let counter = 0;

@Component
class TooltipContainerComponent extends TsxComponent<TooltipContainerArgs> implements TooltipContainerArgs {
	@Prop() renderAsSpan!: boolean;
	@Prop() cssClass!: string;
	@Prop() tooltipCssClass?: string;
	@Prop() tooltip: string;
	@Prop() isHtml?: boolean;
	@Prop() trigger?: 'click' | 'hover' | 'focus' | 'manual' | 'click hover' | 'click focus' | 'hover focus' | 'click hover focus';
	@Prop() textAlign?: 'left' | 'middle' | 'right';
	@Prop() arrowPosition: 'left' | 'middle' | 'right';
	uuid: string = null;

	mounted() {
		if (this.uuid == null) {
			this.uuid = `${PortalUtils.randomString(8)}-${counter++}`;
		}

		this.$nextTick(() => {
			this.ensureTooltip();
		});
	}

	updated() {
		this.$nextTick(() => {
			const el = this.$el as HTMLElement;
			el.setAttribute('data-original-title', this.tooltip);
			el.setAttribute('data-bs-original-title', this.tooltip);
		});
	}

	getInnerStyleAttribute(): string {
		if (!isNullOrEmpty(this.textAlign)) {
			return `style="text:align: ${this.textAlign} !important;"`;
		}

		return '';
	}

	ensureTooltip() {
		this.$nextTick(() => {
			const target = this.$el as HTMLElement;
			if (!target.classList.contains('tooltip-bound')) {
				target.classList.add('tooltip-bound');
				// Bootstrap's Tooltip registers itself on the element via its
				// constructor; we don't need to keep a reference around — the
				// element holds it via `_tooltip` and is reachable through
				// `Tooltip.getInstance(el)` if ever needed.
				// eslint-disable-next-line no-new
				new Tooltip(this.$el, {
					html: this.isHtml == true,
					trigger: this.trigger || 'hover',
					template: `<div class="tooltip ${this.arrowPosition != null ? `tt-${this.arrowPosition}-arrow` : ''} ${this.tooltipCssClass || ''}" role="tooltip"><div id="tt-uuid-${this.uuid}" class="tooltip-arrow"></div><div class="tooltip-inner" ${this.getInnerStyleAttribute()}></div></div>`,
				});
			}
		});
	}

	getCssClass(): string {
		return `tooltip-container ${this.cssClass || ''}`;
	}

	beforeUnmount() {
		const visibleTooltip = document.getElementById(`tt-uuid-${this.uuid}`);
		visibleTooltip?.parentElement?.remove();
	}

	render(h) {
		if (this.renderAsSpan != true) {
			return (
				<div class={this.getCssClass()} title={this.tooltip}>
					{this.$slots.default?.()}
				</div>
			);
		}

		return (
			<span class={this.getCssClass()} title={this.tooltip}>
				{this.$slots.default?.()}
			</span>
		);
	}
}

const TooltipContainer = toNative(TooltipContainerComponent);
export default TooltipContainer;
