jQuery( function ( $ ) {
	var timezone = jstz.determine();

	// Display the timezone for date changes
	$( '#wcs-timezone' ).text( timezone.name() );

	// Display times in client's timezone (based on UTC)
	$( '.woocommerce-subscriptions.date-picker' ).each( function () {
		var $date_input = $( this ),
			date_type = $date_input.attr( 'id' ),
			$hour_input = $( '#' + date_type + '_hour' ),
			$minute_input = $( '#' + date_type + '_minute' ),
			time = $( '#' + date_type + '_timestamp_utc' ).val(),
			date = moment.unix( time );

		if ( time > 0 ) {
			date.local();
			$date_input.val(
				date.year() +
					'-' +
					zeroise( date.months() + 1 ) +
					'-' +
					date.format( 'DD' )
			);
			$hour_input.val( date.format( 'HH' ) );
			$minute_input.val( date.format( 'mm' ) );
		}
	} );

	// Make sure start date picker is in the past
	$( '.woocommerce-subscriptions.date-picker#start' ).datepicker(
		'option',
		'maxDate',
		moment().toDate()
	);

	// Validate date when hour/minute inputs change
	$( '[name$="_hour"], [name$="_minute"]' ).on( 'change', function () {
		$(
			'#' +
				$( this )
					.attr( 'name' )
					.replace( '_hour', '' )
					.replace( '_minute', '' )
		).trigger( 'change' );
	} );

	// Validate entire date
	$( '.woocommerce-subscriptions.date-picker' ).on( 'change', function () {
		// The date was deleted, clear hour/minute inputs values and set the UTC timestamp to 0
		if ( '' == $( this ).val() ) {
			$( '#' + $( this ).attr( 'id' ) + '_hour' ).val( '' );
			$( '#' + $( this ).attr( 'id' ) + '_minute' ).val( '' );
			$( '#' + $( this ).attr( 'id' ) + '_timestamp_utc' ).val( 0 );
			return;
		}

		var time_now = moment(),
			one_hour_from_now = moment().add( 1, 'hours' ),
			minimum_date = wcs_admin_meta_boxes.is_duplicate_site
				? moment().add( 2, 'minutes' )
				: one_hour_from_now,
			$date_input = $( this ),
			date_type = $date_input.attr( 'id' ),
			original_timestamp = $( '#' + date_type + '_timestamp_utc' ).val(),
			original_date = original_timestamp > 0 ? moment.unix( original_timestamp ).local() : null,
			date_pieces = $date_input.val().split( '-' ),
			$hour_input = $( '#' + date_type + '_hour' ),
			$minute_input = $( '#' + date_type + '_minute' ),
			chosen_hour =
				0 == $hour_input.val().length
					? one_hour_from_now.format( 'HH' )
					: $hour_input.val(),
			chosen_minute =
				0 == $minute_input.val().length
					? one_hour_from_now.format( 'mm' )
					: $minute_input.val(),
			chosen_date = moment( {
				years: date_pieces[ 0 ],
				months: date_pieces[ 1 ] - 1,
				date: date_pieces[ 2 ],
				hours: chosen_hour,
				minutes: chosen_minute,
				seconds: one_hour_from_now.format( 'ss' ),
			} );

		// Make sure start date is before now.
		if (
			'start' == date_type &&
			false === chosen_date.isBefore( time_now )
		) {
			alert( wcs_admin_meta_boxes.i18n_start_date_notice );
			$date_input.val(
				time_now.year() +
					'-' +
					zeroise( time_now.months() + 1 ) +
					'-' +
					time_now.format( 'DD' )
			);
			$hour_input.val( time_now.format( 'HH' ) );
			$minute_input.val( time_now.format( 'mm' ) );
		}

		// Make sure trial end and next payment are after start date
		if (
			( 'trial_end' == date_type || 'next_payment' == date_type ) &&
			'' != $( '#start_timestamp_utc' ).val()
		) {
			var change_date = false,
				start = moment.unix( $( '#start_timestamp_utc' ).val() );

			// Make sure trial end is after start date
			if (
				'trial_end' == date_type &&
				chosen_date.isBefore( start, 'minute' )
			) {
				if ( 'trial_end' == date_type ) {
					alert( wcs_admin_meta_boxes.i18n_trial_end_start_notice );
				} else if ( 'next_payment' == date_type ) {
					alert(
						wcs_admin_meta_boxes.i18n_next_payment_start_notice
					);
				}

				// Change the date
				$date_input.val(
					start.year() +
						'-' +
						zeroise( start.months() + 1 ) +
						'-' +
						start.format( 'DD' )
				);
				$hour_input.val( start.format( 'HH' ) );
				$minute_input.val( start.format( 'mm' ) );
			}
		}

		// Make sure next payment is after trial end
		if (
			'next_payment' == date_type &&
			'' != $( '#trial_end_timestamp_utc' ).val()
		) {
			var trial_end = moment.unix(
				$( '#trial_end_timestamp_utc' ).val()
			);

			if ( chosen_date.isBefore( trial_end, 'minute' ) ) {
				alert( wcs_admin_meta_boxes.i18n_next_payment_trial_notice );
				$date_input.val(
					trial_end.year() +
						'-' +
						zeroise( trial_end.months() + 1 ) +
						'-' +
						trial_end.format( 'DD' )
				);
				$hour_input.val( trial_end.format( 'HH' ) );
				$minute_input.val( trial_end.format( 'mm' ) );
			}
		}

		// Make sure trial end is before next payment and expiration is after next payment date
		else if (
			( 'trial_end' == date_type || 'end' == date_type ) &&
			'' != $( '#next_payment' ).val()
		) {
			var change_date = false,
				next_payment = moment.unix(
					$( '#next_payment_timestamp_utc' ).val()
				);

			// Make sure trial end is before or equal to next payment
			if (
				'trial_end' == date_type &&
				next_payment.isBefore( chosen_date, 'minute' )
			) {
				alert( wcs_admin_meta_boxes.i18n_trial_end_next_notice );
				change_date = true;
			}
			// Make sure end date is after next payment date
			else if (
				'end' == date_type &&
				chosen_date.isBefore( next_payment, 'minute' )
			) {
				alert( wcs_admin_meta_boxes.i18n_end_date_notice );
				change_date = true;
			}

			if ( true === change_date ) {
				$date_input.val(
					next_payment.year() +
						'-' +
						zeroise( next_payment.months() + 1 ) +
						'-' +
						next_payment.format( 'DD' )
				);
				$hour_input.val( next_payment.format( 'HH' ) );
				$minute_input.val( next_payment.format( 'mm' ) );
			}
		}

		// Make sure the date is more than an hour in the future
		if (
			'trial_end' != date_type &&
			'start' != date_type &&
			chosen_date.unix() < minimum_date.unix()
		) {
			alert( wcs_admin_meta_boxes.i18n_past_date_notice );

			// Restore the previous value if available, otherwise fall back to one hour from now.
			var restore_date = original_date || one_hour_from_now;

			$date_input.val(
				restore_date.year() +
					'-' +
					zeroise( restore_date.months() + 1 ) +
					'-' +
					restore_date.format( 'DD' )
			);
			$hour_input.val( restore_date.format( 'HH' ) );
			$minute_input.val( restore_date.format( 'mm' ) );
		}

		if ( 0 == $hour_input.val().length ) {
			$hour_input.val( one_hour_from_now.format( 'HH' ) );
		}

		if ( 0 == $minute_input.val().length ) {
			$minute_input.val( one_hour_from_now.format( 'mm' ) );
		}

		// Update the UTC timestamp sent to the server
		date_pieces = $date_input.val().split( '-' );

		var newTimeStampValue = moment( {
			years: date_pieces[ 0 ],
			months: date_pieces[ 1 ] - 1,
			date: date_pieces[ 2 ],
			hours: $hour_input.val(),
			minutes: $minute_input.val(),
			seconds: one_hour_from_now.format( 'ss' ),
		} )
			.utc()
			.unix();


		// Moment will return NaN if the date is invalid, that's why we need to check for NaN only.
		if ( isNaN( newTimeStampValue ) ) {
			wcsShowDateFieldError( date_type );
		} else {
			wcsHideDateFieldError( date_type );
		}

		// Intentionally do not prevent timestamp updates if the date is invalid.
		// This way it's easier to catch invalid fields during submit event if attempted without editing invalid values.
		$( '#' + date_type + '_timestamp_utc' ).val(
			newTimeStampValue
		);

		$( 'body' ).trigger( 'wcs-updated-date', date_type );
	} );

	function wcsShowDateFieldError( date_type ) {
		var $fieldContainer = $( '#subscription-' + date_type + '-date' );
		$fieldContainer.addClass( 'has-error' );
		var $messageContainer = $fieldContainer.find( '.message' );
		var $messageContent = $messageContainer.find( '.message-content' );
		
		// Clear and set content before showing to ensure screen readers announce the new message
		$messageContent.text('');
		$messageContainer.show();
		
		// Use setTimeout to ensure DOM update occurs before adding new text
		setTimeout(function() {
			// If the focus switched to the next field voice over skips announcing the error message.
			// This is a workaround to ensure the error message is announced.
			$fieldContainer
				.find( `input#${date_type}` )
				.trigger( 'focus' )
				.trigger( 'blur' );
			$messageContent.text( wcs_admin_meta_boxes.i18n_invalid_date_notice );
		}, 100);
	}

	function wcsHideDateFieldError( date_type ) {
		var $fieldContainer = $( '#subscription-' + date_type + '-date' );
		$fieldContainer.removeClass( 'has-error' );
		var $messageContainer = $fieldContainer.find( '.message' );
		var $messageContent = $messageContainer.find( '.message-content' );
		
		$messageContainer.hide();
		$messageContent.text('');
	}

	function zeroise( val ) {
		return val > 9 ? val : '0' + val;
	}

	if ( $( '#parent-order-id' ).is( 'select' ) ) {
		wcs_update_parent_order_options();

		$( '#customer_user' ).on( 'change', wcs_update_parent_order_options );
	}

	function wcs_update_parent_order_options() {
		// Get user ID to load orders for
		var user_id = $( '#customer_user' ).val();

		if ( ! user_id ) {
			return false;
		}

		var data = {
			user_id: user_id,
			action: 'wcs_get_customer_orders',
			security: wcs_admin_meta_boxes.get_customer_orders_nonce,
		};

		$( '#parent-order-id' )
			.siblings( '.select2-container' )
			.block( {
				message: null,
				overlayCSS: {
					background: '#fff',
					opacity: 0.6,
				},
			} );

		$.ajax( {
			url: WCSubscriptions.ajaxUrl,
			data: data,
			type: 'POST',
			success: function ( response ) {
				if ( response ) {
					var $orderlist = $( '#parent-order-id' );

					$( '#parent-order-id' ).select2( 'val', '' );

					$orderlist.empty(); // remove old options

					$orderlist.append(
						$( '<option></option>' )
							.attr( 'value', '' )
							.text( 'Select an order' )
					);

					$.each( response, function ( order_id, order_number ) {
						$orderlist.append(
							$( '<option></option>' )
								.attr( 'value', order_id )
								.text( order_number )
						);
					} );

					$( '#parent-order-id' )
						.siblings( '.select2-container' )
						.unblock();
				}
			},
		} );
		return false;
	}

	$( 'body.post-type-shop_subscription #post, body.woocommerce_page_wc-orders--shop_subscription #order' ).on( 'submit', function ( evt ) {
		var invalid_dates = [];
		$( '.woocommerce-subscriptions.date-picker' ).each( function () {
			var $date_input = $( this );
			var date_type = $date_input.attr( 'id' );
			var timestamp = $( '#' + date_type + '_timestamp_utc' ).val();
			// At this point, timestamp is a string, not a number.
			// We check for NaN only because everything else should be a valid timestamp set during the change event.
			if ( timestamp === 'NaN' ) {
				invalid_dates.push( date_type );
			}
		} );
		
		if ( invalid_dates.length > 0 ) {
			// Focus the first invalid date to make it noticeable.
			$( '#subscription-' + invalid_dates[0] + '-date' ).find( '.wcs-date-input input' ).first().trigger( 'focus' );
			return false;
		}
	} )

	$( 'body.post-type-shop_subscription #post, body.woocommerce_page_wc-orders--shop_subscription #order' ).on( 'submit', function () {
		if (
			'wcs_process_renewal' ==
			$(
				'body.post-type-shop_subscription select[name="wc_order_action"], body.woocommerce_page_wc-orders--shop_subscription select[name="wc_order_action"]'
			).val()
		) {
			return confirm(
				wcs_admin_meta_boxes.process_renewal_action_warning
			);
		}
	} );

	$( 'body.post-type-shop_subscription #post, body.woocommerce_page_wc-orders--shop_subscription #order' ).on( 'submit', function () {
		if (
			typeof wcs_admin_meta_boxes.change_payment_method_warning !=
				'undefined' &&
			wcs_admin_meta_boxes.payment_method != $( '#_payment_method' ).val()
		) {
			return confirm(
				wcs_admin_meta_boxes.change_payment_method_warning
			);
		}
	} );

	/**
	 * When the auto-renewal is toggled on or off, show or hide the chosen payment methods meta fields.
	 */
	$( '#wc-subscription-auto-renew' ).on( 'change', function() {
		var $payment_method_meta_elements = $( '#wcs_' + $( '#_payment_method' ).val() + '_fields' );

		if ( $( this ).is( ':checked' ) ) {
			$payment_method_meta_elements.fadeIn();
		} else {
			$payment_method_meta_elements.fadeOut();
		}
	} );
} );
