( function ( $, undefined ) {
	acf.newTooltip = function ( props ) {
		// ensure object
		if ( typeof props !== 'object' ) {
			props = { text: props };
		}

		// confirmRemove
		if ( props.confirmRemove !== undefined ) {
			props.textConfirm = acf.__( 'Remove' );
			props.textCancel = acf.__( 'Cancel' );
			return new TooltipConfirm( props );

			// confirm
		} else if ( props.confirm !== undefined ) {
			return new TooltipConfirm( props );

			// default
		} else {
			return new Tooltip( props );
		}
	};

	var Tooltip = acf.Model.extend( {
		data: {
			text: '',
			timeout: 0,
			target: null,
		},

		tmpl: function () {
			return '<div class="acf-tooltip"></div>';
		},

		setup: function ( props ) {
			$.extend( this.data, props );
			this.$el = $( this.tmpl() );
		},

		initialize: function () {
			// render
			this.render();

			// append
			this.show();

			// position
			this.position();

			// timeout
			var timeout = this.get( 'timeout' );
			if ( timeout ) {
				setTimeout( $.proxy( this.fade, this ), timeout );
			}
		},

		update: function ( props ) {
			$.extend( this.data, props );
			this.initialize();
		},

		render: function () {
			this.$el.text( this.get( 'text' ) );
		},

		show: function () {
			$( 'body' ).append( this.$el );
		},

		hide: function () {
			this.$el.remove();
		},

		fade: function () {
			// add class
			this.$el.addClass( 'acf-fade-up' );

			// remove
			this.setTimeout( function () {
				this.remove();
			}, 250 );
		},

		html: function ( html ) {
			this.$el.html( html );
		},

		position: function () {
			// vars
			var $tooltip = this.$el;
			var $target = this.get( 'target' );
			if ( ! $target ) return;

			// Reset position.
			$tooltip
				.removeClass( 'right left bottom top' )
				.css( { top: 0, left: 0 } );

			// Declare tolerance to edge of screen.
			var tolerance = 10;

			// Find target position.
			var targetWidth = $target.outerWidth();
			var targetHeight = $target.outerHeight();
			var targetTop = $target.offset().top;
			var targetLeft = $target.offset().left;

			// Find tooltip position.
			var tooltipWidth = $tooltip.outerWidth();
			var tooltipHeight = $tooltip.outerHeight();
			var tooltipTop = $tooltip.offset().top; // Should be 0, but WP media grid causes this to be 32 (toolbar padding).

			// Assume default top alignment.
			var top = targetTop - tooltipHeight - tooltipTop;
			var left = targetLeft + targetWidth / 2 - tooltipWidth / 2;

			// Check if too far left.
			if ( left < tolerance ) {
				$tooltip.addClass( 'right' );
				left = targetLeft + targetWidth;
				top =
					targetTop +
					targetHeight / 2 -
					tooltipHeight / 2 -
					tooltipTop;

				// Check if too far right.
			} else if (
				left + tooltipWidth + tolerance >
				$( window ).width()
			) {
				$tooltip.addClass( 'left' );
				left = targetLeft - tooltipWidth;
				top =
					targetTop +
					targetHeight / 2 -
					tooltipHeight / 2 -
					tooltipTop;

				// Check if too far up.
			} else if ( top - $( window ).scrollTop() < tolerance ) {
				$tooltip.addClass( 'bottom' );
				top = targetTop + targetHeight - tooltipTop;

				// No collision with edges.
			} else {
				$tooltip.addClass( 'top' );
			}

			// update css
			$tooltip.css( { top: top, left: left } );
		},
	} );

	var TooltipConfirm = Tooltip.extend( {
		data: {
			text: '',
			textConfirm: '',
			textCancel: '',
			target: null,
			targetConfirm: true,
			confirm: function () {},
			cancel: function () {},
			context: false,
		},

		events: {
			'click [data-event="cancel"]': 'onCancel',
			'click [data-event="confirm"]': 'onConfirm',
		},

		addEvents: function () {
			// add events
			acf.Model.prototype.addEvents.apply( this );

			// vars
			var $document = $( document );
			var $target = this.get( 'target' );

			// add global 'cancel' click event
			// - use timeout to avoid the current 'click' event triggering the onCancel function
			this.setTimeout( function () {
				this.on( $document, 'click', 'onCancel' );
			} );

			// add target 'confirm' click event
			// - allow setting to control this feature
			if ( this.get( 'targetConfirm' ) ) {
				this.on( $target, 'click', 'onConfirm' );
			}
		},

		removeEvents: function () {
			// remove events
			acf.Model.prototype.removeEvents.apply( this );

			// vars
			var $document = $( document );
			var $target = this.get( 'target' );

			// remove custom events
			this.off( $document, 'click' );
			this.off( $target, 'click' );
		},

		render: function () {
			// defaults
			var text = this.get( 'text' ) || acf.__( 'Are you sure?' );
			var textConfirm = this.get( 'textConfirm' ) || acf.__( 'Yes' );
			var textCancel = this.get( 'textCancel' ) || acf.__( 'No' );

			// html
			var html = [
				text,
				'<a href="#" data-event="confirm">' + textConfirm + '</a>',
				'<a href="#" data-event="cancel">' + textCancel + '</a>',
			].join( ' ' );

			// html
			this.html( html );

			// class
			this.$el.addClass( '-confirm' );
		},

		onCancel: function ( e, $el ) {
			// prevent default
			e.preventDefault();
			e.stopImmediatePropagation();

			// callback
			var callback = this.get( 'cancel' );
			var context = this.get( 'context' ) || this;
			callback.apply( context, arguments );

			//remove
			this.remove();
		},

		onConfirm: function ( e, $el ) {
			// Prevent event from propagating completely to allow "targetConfirm" to be clicked.
			e.preventDefault();
			e.stopImmediatePropagation();

			// callback
			var callback = this.get( 'confirm' );
			var context = this.get( 'context' ) || this;
			callback.apply( context, arguments );

			//remove
			this.remove();
		},
	} );

	// storage
	acf.models.Tooltip = Tooltip;
	acf.models.TooltipConfirm = TooltipConfirm;

	/**
	 *  tooltipManager
	 *
	 *  description
	 *
	 *  @date	17/4/18
	 *  @since	ACF 5.6.9
	 *
	 *  @param	type $var Description. Default.
	 *  @return	type Description.
	 */

	var tooltipHoverHelper = new acf.Model( {
		tooltip: false,

		events: {
			'mouseenter .acf-js-tooltip': 'showTitle',
			'mouseup .acf-js-tooltip': 'hideTitle',
			'mouseleave .acf-js-tooltip': 'hideTitle',
			'focus .acf-js-tooltip': 'showTitle',
			'blur .acf-js-tooltip': 'hideTitle',
			'keyup .acf-js-tooltip': 'onKeyUp',
		},

		showTitle: function ( e, $el ) {
			// vars
			let title = $el.attr( 'title' );

			// bail early if no title
			if ( ! title ) {
				return;
			}

			// clear title to avoid default browser tooltip
			$el.attr( 'title', '' );

			$el.data( 'acf-js-tooltip-title', title );
			title = acf.strEscape( title );

			// create
			if ( ! this.tooltip ) {
				this.tooltip = acf.newTooltip( {
					text: title,
					target: $el,
				} );

				// update
			} else {
				this.tooltip.update( {
					text: title,
					target: $el,
				} );
			}
		},

		hideTitle: function ( e, $el ) {
			// hide tooltip
			this.tooltip.hide();
			$el.attr( 'title', $el.data( 'acf-js-tooltip-title' ) );

			// restore title
			$el.removeData( 'acf-js-tooltip-title' );
		},

		onKeyUp: function ( e, $el ) {
			if ( 'Escape' === e.key ) {
				this.hideTitle( e, $el );
			}
		},
	} );
} )( jQuery );
