import jQuery from 'jquery';

( function ( $, window ) {
	'use strict';

	const wdevsCoeElements = {
		settings: {
			variables: [],
			menuSelector: '#wdevs-coe-variable-menu',
			inputSelector: '.wdevs_coe_file_name',
		},

		init( options ) {
			this.settings.variables = this.getVariables();
			this.settings = $.extend( {}, this.settings, options );
			this.setMenu();
			this.setupEventHandlers();
		},

		getVariables() {
			const formatted = [];
			if ( typeof window.wdceoData === 'undefined' ) {
				return formatted;
			}

			if ( ! window.wdceoData.variables ) {
				return formatted;
			}

			const variables = window.wdceoData.variables;

			for ( const [ key, data ] of Object.entries( variables ) ) {
				formatted.push( {
					key: `{{${ key }}}`,
					label: data.label,
				} );
			}

			return formatted;
		},

		setMenu() {
			if ( $( this.settings.menuSelector ).length > 0 ) {
				return;
			}

			const $menu = $( '<div>', {
				id: 'wdevs-coe-variable-menu',
				css: {
					display: 'none',
					position: 'absolute',
					zIndex: 9999,
				},
			} );

			const $ul = $( '<ul>' );
			this.settings.variables.forEach( ( variable ) => {
				$( '<li>', {
					text: variable.label,
					'data-variable': variable.key,
					class: 'wdevs-coe-variable-menu-item',
				} ).appendTo( $ul );
			} );

			$menu.append( $ul );
			$( 'body' ).append( $menu );
		},

		setupEventHandlers() {
			$( document ).on(
				'mouseup keyup',
				this.settings.inputSelector,
				this.saveCaretPosition.bind( this )
			);

			$( document ).on(
				'click',
				'.wdevs-coe-variables-button',
				this.handleVariableButtonClick.bind( this )
			);

			$( document ).on( 'click', this.handleOutsideClick.bind( this ) );

			const $menu = $( this.settings.menuSelector );
			if ( $menu.length ) {
				$menu.on(
					'click',
					'li',
					this.handleVariableSelection.bind( this )
				);
			}
		},

		saveCaretPosition( e ) {
			const input = e.currentTarget;
			this.currentInput = input;
			this.lastCaretPos = input.selectionStart;
		},

		handleVariableButtonClick( e ) {
			e.preventDefault();
			const $menu = $( this.settings.menuSelector );
			this.showElementAtCaret( $menu, e );

			return false;
		},

		handleVariableSelection( e ) {
			const $li = $( e.currentTarget );
			this.insertVariable( $li.data( 'variable' ) );
			this.hideMenu();
		},

		insertVariable( variable ) {
			const input = this.currentInput;
			if ( ! input ) {
				return;
			}

			const currentValue = input.value;

			const newValue =
				currentValue.substring( 0, this.lastCaretPos ) +
				variable +
				currentValue.substring( this.lastCaretPos );

			input.value = newValue;

			const newCaretPos = this.lastCaretPos + variable.length;
			input.setSelectionRange( newCaretPos, newCaretPos );
			input.focus();
			$( input ).trigger( 'input' );
		},

		handleOutsideClick( e ) {
			const $target = $( e.target );
			const isMenuClick =
				$target.closest( this.settings.menuSelector ).length > 0;

			const isTriggerClick =
				$target.closest( '.wdevs-coe-variables-button' ).length > 0;

			if ( ! isMenuClick && ! isTriggerClick ) {
				this.hideMenu();

				const isInputClick =
					$target.closest( this.settings.inputSelector ).length > 0;
				if ( ! isInputClick ) {
					this.lastCaretPos = null;
					this.currentInput = null;
				}
			}
		},

		hideMenu() {
			const $menu = $( this.settings.menuSelector );
			if ( $menu.length ) {
				$menu.hide();
			}
		},

		showElementAtCaret( $element, e ) {
			let input = this.currentInput;

			const $btn = $( e.currentTarget );
			const closestInput =
				$btn.closest( 'td' ).find( this.settings.inputSelector )[ 0 ] ||
				$btn.closest( this.settings.inputSelector )[ 0 ];

			if ( closestInput && input !== closestInput ) {
				input = closestInput;
				this.currentInput = input;
				this.lastCaretPos = null;
			}

			if (
				this.lastCaretPos === null ||
				typeof this.lastCaretPos === 'undefined'
			) {
				input.focus();
				const val = input.value;
				input.value = '';
				input.value = val;
				this.lastCaretPos = input.selectionStart;
			}
			const caretPos = this.lastCaretPos;

			const textBeforeCaret = input.value.substring( 0, caretPos );

			const span = document.createElement( 'span' );
			span.textContent = textBeforeCaret || '.';
			span.style.whiteSpace = 'pre';

			const computedStyle = window.getComputedStyle( input );
			span.style.fontFamily = computedStyle.fontFamily;
			span.style.fontSize = computedStyle.fontSize;
			span.style.fontWeight = computedStyle.fontWeight;
			span.style.letterSpacing = computedStyle.letterSpacing;
			span.style.padding = computedStyle.paddingLeft;
			span.style.border = computedStyle.border;
			span.style.position = 'absolute';
			span.style.visibility = 'hidden';

			const div = document.createElement( 'div' );
			div.style.position = 'absolute';
			div.style.left = '-9999px'; // offscreen
			div.appendChild( span );
			document.body.appendChild( div );

			const textWidth = span.offsetWidth;
			const inputRect = input.getBoundingClientRect();

			let left = inputRect.left + textWidth;
			const top = inputRect.bottom;

			document.body.removeChild( div );

			const menuWidth = $element.outerWidth();
			const windowWidth = window.innerWidth;

			if ( left + menuWidth > windowWidth ) {
				left = windowWidth - menuWidth - 5;
			}

			$element.css( {
				display: 'block',
				left: left + window.pageXOffset,
				top: top + window.pageYOffset,
			} );
		},
	};

	$( function () {
		wdevsCoeElements.init();
	} );
} )( jQuery, window );
