/**
 * File: Extension_ImageService_Plugin_Admin.js
 *
 * JavaScript for the Media Library list page.
 *
 * @since 2.2.0
 *
 * @global w3tcData Localized data.
 */

(function( $ ) {
	var isCheckingItems = false,
		$convertLinks = $( 'a.w3tc-convert, a.w3tc-convert-format' ),
		$unconvertLinks = $( '.w3tc-revert > a' ),
		$convertAllButton = $( 'th.w3tc-imageservice-all' ).parent().find( 'td button' ),
		$revertAllButton = $( 'th.w3tc-imageservice-revertall' ).parent().find( 'td button' ),
		$refreshStatsButton = $( 'input#w3tc-imageservice-refresh-counts.button' ),
		$refreshUsageButton = $( 'input#w3tc-imageservice-refresh-usage.button' );

	/* On page load. */

	// Start checking items that are in the processing status.
	startCheckItems();

	// Disable ineligible buttons.
	toggleButtons();

	/* Events. */

	// Clicked convert link.
	$convertLinks.on( 'click', convertItem );

	// Clicked revert link.
	$unconvertLinks.on( 'click', revertItem );

	// Clicked convert all images button.
	$convertAllButton.on( 'click', convertItems );

	// Clicked revert all converted images button.
	$revertAllButton.on( 'click', revertItems );

	// Clicked the refresh icon for statistics counts.
	$refreshStatsButton.on( 'click', refreshStats );

	// Clicked the refresh icon for API usage statistics.
	$refreshUsageButton.on( 'click', refreshUsage );

	/* Functions. */

	/**
	 * Check if a format is enabled in settings.
	 *
	 * @since 2.9.1
	 *
	 * @param string formatKey Format key (webp or avif).
	 * @return bool
	 */
	function isFormatEnabled( formatKey ) {
		var settings = w3tcData.settings || {};

		if ( 'webp' === formatKey ) {
			return typeof settings.webp === 'undefined' || true === settings.webp || '1' === settings.webp || 1 === settings.webp;
		}

		if ( 'avif' === formatKey ) {
			return ( typeof settings.avif === 'undefined' || true === settings.avif || '1' === settings.avif || 1 === settings.avif ) && w3tcData.isPro;
		}

		return false;
	}

	/**
	 * Ensure a convert link exists for a format.
	 *
	 * @since 2.9.1
	 *
	 * @param jQuery $itemTd Row cell.
	 * @param string formatKey Format key (webp or avif).
	 * @param string postId Attachment ID.
	 */
	function ensureConvertLink( $itemTd, formatKey, postId ) {
		var linkClass = 'avif' === formatKey ? 'w3tc-convert-avif' : 'w3tc-convert-webp',
			linkText = 'avif' === formatKey ? w3tcData.lang.convertToAvif : w3tcData.lang.convertToWebp;

		if ( $itemTd.find( '.' + linkClass + ' a' ).length ) {
			return;
		}

		$itemTd.append(
			'<span class="' + linkClass + '"> | <a class="w3tc-convert-format" data-post-id="' +
			postId + '" data-status="converted" data-format="' + formatKey + '" aria-disabled="false">' +
			linkText + '</a></span>'
		);

		$itemTd.find( 'a.w3tc-convert-format' ).off( 'click' ).on( 'click', convertItem );
	}

	/**
	 * Toggle buttons based on eligibility.
	 *
	 * @since 2.2.0
	 */
	function toggleButtons() {
		if ( $convertAllButton.length && $( '#w3tc-imageservice-unconverted' ).text() < 1 ) {
			$convertAllButton.prop( 'disabled', true ).prop( 'aria-disabled', 'true' ); // Disable button.
		}

		if ( $revertAllButton.length && $( '#w3tc-imageservice-converted' ).text() < 1 ) {
			$revertAllButton.prop( 'disabled', true ).prop( 'aria-disabled', 'true' ); // Disable button.
		}
	}

	/**
	 * Start checking items that are in the processing status.
	 *
	 * @since 2.2.0
	 *
	 * @see checkItemsProcessing()
	 */
	function startCheckItems() {
		if ( isCheckingItems ) {
			return;
		}

		isCheckingItems= true;

		// Check status and update every 5 seconds.
		checkitemsInterval = setInterval( checkItemsProcessing, 5000 );

		// Stop checking after 5 minutes.
		setTimeout(
			function() {
				clearInterval( checkitemsInterval );
				isCheckingItems = false;
			},
			60 * 5 * 1000
		);
	}

	/**
	 * Check processing items.
	 *
	 * @since 2.2.0
	 *
	 * @see checkItemProcessing()
	 */
	function checkItemsProcessing() {
		$convertLinks.each( checkItemProcessing );
	}

	/**
	 * Callback: Check processing item.
	 *
	 * @since 2.2.0
	 */
	 function checkItemProcessing() {
		var $this = $( this ),
			$itemTd = $this.closest( 'td' );

		// If marked as processing, then check for status change an update status on screen.
		if ( 'processing' === $this.data( 'status' ) ) {
			$.ajax({
				method: 'POST',
				url: ajaxurl,
				data: {
					_wpnonce: w3tcData.nonces.postmeta,
					action: 'w3tc_imageservice_postmeta',
					post_id: $this.data( 'post-id' )
				}
			})
				.done( function( response ) {
					var infoClass, downloadData, downloadHeaders, reducedPercent, filesizeIn, filesizeOut, formatKey, i;

					// Remove any previous optimization information and the revert link.
					$itemTd.find(
						'.w3tc-converted-reduced, .w3tc-converted-increased, .w3tc-notconverted, .w3tc-revert, .w3tc-converted-error'
					).remove();

					// Handle multiple formats (new structure).
					if ( 'notconverted' !== response.data.status && response.data.downloads && typeof response.data.downloads === 'object' ) {
						// Sort formats to maintain order: WEBP first, then AVIF.
						var sortedFormats = Object.keys( response.data.downloads ).sort( function( a, b ) {
							var order = { 'webp': 1, 'avif': 2 };
							var aOrder = order[ a ] || 99;
							var bOrder = order[ b ] || 99;
							return aOrder - bOrder;
						});

						// Iterate through all formats in reverse order since prepend() adds to the beginning.
						// This ensures WEBP appears first, then AVIF.
						for ( i = sortedFormats.length - 1; i >= 0; i-- ) {
							formatKey = sortedFormats[ i ];
							downloadData = response.data.downloads[ formatKey ];

							// Skip if it's an error string.
							if ( typeof downloadData === 'string' ) {
								// Show error message for failed formats.
								$itemTd.prepend(
									'<div class="w3tc-converted-error">' +
									formatKey.toUpperCase() + ': ' + downloadData +
									'</div>'
								);
								if ( isFormatEnabled( formatKey ) ) {
									ensureConvertLink( $itemTd, formatKey, $this.data( 'post-id' ) );
								}
								continue;
							}

							if ( typeof downloadData !== 'object' || ! downloadData ) {
								continue;
							}

							// Extract headers - handle both normalized format and old format.
							downloadHeaders = downloadData;
							if ( downloadData["\u0000*\u0000data"] ) {
								downloadHeaders = downloadData["\u0000*\u0000data"];
							}

							// Normalize header keys to lowercase for case-insensitive access.
							var normalizedHeaders = {};
							for ( var key in downloadHeaders ) {
								if ( downloadHeaders.hasOwnProperty( key ) && key.charAt( 0 ) !== '\u0000' ) {
									normalizedHeaders[ key.toLowerCase() ] = downloadHeaders[ key ];
								}
							}

							reducedPercent = normalizedHeaders['x-filesize-reduced'] || null;
							filesizeIn     = normalizedHeaders['x-filesize-in'] || null;
							filesizeOut    = normalizedHeaders['x-filesize-out'] || null;

							// Check if this format was actually converted (exists in post_children).
							var postChildren = response.data.post_children || {};
							var wasConverted = postChildren[ formatKey ] && postChildren[ formatKey ] !== null && postChildren[ formatKey ] !== '';

							// If not converted, show "not converted" message instead of statistics.
							if ( ! wasConverted ) {
								$itemTd.prepend(
									'<div class="w3tc-notconverted">' +
									formatKey.toUpperCase() + ': ' +
									w3tcData.lang.notConverted +
									'</div>'
								);
								continue;
							}

							// Display if we have the necessary data and the format was converted.
							if ( filesizeIn && filesizeOut && reducedPercent ) {
								var reducedNumeric = parseFloat( reducedPercent.toString().replace( '%', '' ) );
								infoClass = reducedNumeric >= 100 ? 'w3tc-converted-increased' : 'w3tc-converted-reduced';

								$itemTd.prepend(
									'<div class="' + infoClass + '">' +
									formatKey.toUpperCase() + ': ' +
									sizeFormat( filesizeIn ) +
									' &#8594; ' +
									sizeFormat( filesizeOut ) +
									' (' + reducedPercent + ')' +
									'</div>'
								);
							}
						}
					} else if ( 'notconverted' !== response.data.status && response.data.download && response.data.download["\u0000*\u0000data"] ) {
						// Handle single format (backward compatibility).
						downloadHeaders = response.data.download["\u0000*\u0000data"];
						reducedPercent  = downloadHeaders['x-filesize-reduced'] || null;
						filesizeIn      = downloadHeaders['x-filesize-in'] || null;
						filesizeOut     = downloadHeaders['x-filesize-out'] || null;

						if ( filesizeIn && filesizeOut && reducedPercent ) {
							var reducedNumeric = parseFloat( reducedPercent.toString().replace( '%', '' ) );
							infoClass = reducedNumeric > 100 ? 'w3tc-converted-increased' : 'w3tc-converted-reduced';

							$itemTd.prepend(
								'<div class="' + infoClass + '">' +
								sizeFormat( filesizeIn ) +
								' &#8594; ' +
								sizeFormat( filesizeOut ) +
								' (' + reducedPercent + ')' +
								'</div>'
							);
						}
					}

					if ( 'converted' === response.data.status ) {
						var clickedFormat = $this.data( 'format' );
						var $primaryLink = $itemTd.find( 'a.w3tc-convert' ).not( '[data-format]' ).first();

						// Determine which format(s) were converted.
						var convertedFormats = [];
						var postChildren = response.data.post_children || {};

						// Check new format (post_children).
						for ( var formatKey in postChildren ) {
							if ( postChildren.hasOwnProperty( formatKey ) && postChildren[ formatKey ] ) {
								convertedFormats.push( formatKey.toUpperCase() );
							}
						}

						// Check old format (post_child).
						if ( convertedFormats.length === 0 && response.data.post_child ) {
							// For old format, we can't determine the format from the response,
							// but typically it's WEBP. We'll show "Converted" as fallback.
							convertedFormats.push( 'WEBP' );
						}

						// Display format(s) or default to "Converted".
						var convertedText = convertedFormats.length > 0 ?
							convertedFormats.join( '/' ) + ' ' + w3tcData.lang.converted :
							w3tcData.lang.converted;

						// Always update the primary status link text.
						if ( $primaryLink.length ) {
							$primaryLink
								.text( convertedText )
								.data( 'status', 'converted' );
						} else {
							// Fallback: update whatever link is being checked.
							$this
								.text( convertedText )
								.data( 'status', 'converted' );
						}

						// If this was a secondary action link (Convert to AVIF/WebP), don't turn it into a status link.
						// Either remove it (if the requested format now exists) or restore its label.
						if ( clickedFormat ) {
							var requestedKey = clickedFormat.toString().toLowerCase();
							var hasRequested = postChildren[ requestedKey ] && postChildren[ requestedKey ] !== null && postChildren[ requestedKey ] !== '';

							if ( hasRequested ) {
								// Remove the secondary action link wrapper.
								$this.closest( 'span' ).remove();
							} else {
								// Restore the action label and clear processing state.
								if ( 'avif' === requestedKey ) {
									$this.text( w3tcData.lang.convertToAvif );
								} else if ( 'webp' === requestedKey ) {
									$this.text( w3tcData.lang.convertToWebp );
								} else {
									$this.text( w3tcData.lang.convert );
								}
								$this.data( 'status', 'converted' ).prop( 'aria-disabled', 'false' );
								$this.closest( 'span' ).removeClass( 'w3tc-disabled' );
							}
						}

						// Add revert link, if not already present.
						if ( ! $itemTd.find( '.w3tc-revert' ).length ) {
							$itemTd.append(
								'<span class="w3tc-revert"> | <a>' +
								w3tcData.lang.revert +
								'</a></span>'
							);

							// Update global revert link.
							$( '.w3tc-revert > a' ).unbind().on( 'click', revertItem );
						}
					} else if ( 'notconverted' === response.data.status ) {
						$this.data( 'status', 'notconverted' );

						$itemTd.prepend(
							'<div class="w3tc-notconverted">' +
							w3tcData.lang.notConvertedDesc +
							'</div>'
						);

						if ( 'lossless' === w3tcData.settings.compression ) {
							$this
								.text( w3tcData.lang.settings )
								.prop( 'aria-disabled' , 'false')
								.closest( 'span' ).removeClass( 'w3tc-disabled' );
						} else {
							$this.text( w3tcData.lang.notConverted );
						}
					} else if ( 'notfound' === response.data.status ) {
						$this
							.text( w3tcData.lang.convert )
							.data( 'status', 'notfound' )
							.prop( 'aria-disabled', 'false' )
							.closest( 'span' ).removeClass( 'w3tc-disabled' );
					}
				})
				.fail( function( response ) {
					var message;

					if (
						response && response.hasOwnProperty( 'responseJSON' ) &&
						response.responseJSON && response.responseJSON.hasOwnProperty( 'data' ) &&
						response.responseJSON.data.hasOwnProperty( 'error' )
					) {
						message = response.responseJSON.data.error;
					} else {
						message = w3tcData.lang.ajaxFail;
					}

					$this
						.text( w3tcData.lang.error )
						.data( 'status', null );
					$itemTd.find( '.w3tc-imageservice-error' ).remove();
					$itemTd.append(
						'<div class="notice notice-error inline w3tc-imageservice-error">' +
						message +
						'</div>'
					);
				});
		}
	}

	/**
	 * Refresh statistics/counts.
	 *
	 * @since 2.2.0
	 */
	function refreshStats() {
		var $countsTable = $( 'table#w3tc-imageservice-counts' );

		// Update the refresh button text.
		$refreshStatsButton
			.val( w3tcData.lang.refreshing )
			.prop( 'disabled', true )
			.prop( 'aria-disabled', 'true' );

		// Remove any error notices.
		$countsTable.find( '.w3tc-imageservice-error' ).remove();

		$.ajax({
			method: 'POST',
			url: ajaxurl,
			data: {
				_wpnonce: w3tcData.nonces.submit,
				action: 'w3tc_imageservice_counts'
			}
		})
			.done( function( response ) {
				if ( response.data && response.data.hasOwnProperty( 'total' ) ) {
					[ 'total', 'converted', 'sending', 'processing', 'notconverted', 'unconverted' ].forEach( function( className ) {
						var size,
							$size,
							$count = $countsTable.find( '#w3tc-imageservice-' + className );
						if ( parseInt( $count.text() ) !== response.data[ className ] ) {
							$count.text( response.data[ className ] ).closest( 'tr' ).addClass( 'w3tc-highlight' );

							className += 'bytes';
							$size = $countsTable.find( '#w3tc-imageservice-' + className );
							size = sizeFormat( response.data[ className ], 2 );
							$size.text( size );
						}
					} );
				}

				// Update the refresh button text.
				$refreshStatsButton
					.val( w3tcData.lang.refresh )
					.prop( 'disabled', false )
					.prop( 'aria-disabled', 'false' );

				// Remove highlights.
				setTimeout(
					function() {
						$countsTable.find( '.w3tc-highlight' ).removeClass( 'w3tc-highlight' );
					},
					1000
				);
			})
			.fail( function() {
				$countsTable.append(
					'<div class="notice notice-error inline w3tc-imageservice-error">' +
					w3tcData.lang.ajaxFail +
					'</div>'
				);

				// Update the refresh button text.
				$refreshStatsButton
					.val( w3tcData.lang.error )
					.prop( 'disabled', false )
					.prop( 'aria-disabled', 'false' );
			});
	}

	/**
	 * Refresh API usage statistics.
	 *
	 * @since 2.2.0
	 */
	function refreshUsage() {
		var $usageTable = $( 'table#w3tc-imageservice-usage' );

		// Update the refresh button text.
		$refreshUsageButton
			.val( w3tcData.lang.refreshing )
			.prop( 'disabled', true )
			.prop( 'aria-disabled', 'true' );

		// Remove any error notices.
		$usageTable.find( '.w3tc-imageservice-error' ).remove();

		$.ajax({
			method: 'POST',
			url: ajaxurl,
			data: {
				_wpnonce: w3tcData.nonces.submit,
				action: 'w3tc_imageservice_usage'
			}
		})
			.done( function( response ) {
				if ( response.data && response.data.hasOwnProperty( 'usage_hourly' ) ) {
					[ 'usage_hourly', 'usage_monthly', 'limit_hourly', 'limit_monthly' ].forEach( function( keyName ) {
						var className = keyName.replace( '_', '-' ),
							$count = $usageTable.find( '#w3tc-imageservice-' + className );
						if ( $count.text() != response.data[ keyName ] ) {
							$count.text( response.data[ keyName ] ).closest( 'tr' ).addClass( 'w3tc-highlight' );
						}
					});
				}

				// Update the refresh button text.
				$refreshUsageButton
					.val( w3tcData.lang.refresh )
					.prop( 'disabled', false )
					.prop( 'aria-disabled', 'false' );

				// Remove highlights.
				setTimeout(
					function() {
						$usageTable.find( '.w3tc-highlight' ).removeClass( 'w3tc-highlight' );
					},
					1000
				);
			})
			.fail( function() {
				$usageTable.append(
					'<div class="notice notice-error inline w3tc-imageservice-error">' +
					w3tcData.lang.ajaxFail +
					'</div>'
				);

				// Update the refresh button text.
				$refreshUsageButton
					.val( w3tcData.lang.error )
					.prop( 'disabled', false )
					.prop( 'aria-disabled', 'false' );
			});
	}

	/**
	 * Convert number of bytes largest unit bytes will fit into.
	 *
	 * Similar to size_format(), but in JavaScript.
	 *
	 * @since 2.2.0
	 *
	 * @param int size     Size in bytes.
	 * @param int decimals Number of decimal places.
	 * @return string
	 */
	function sizeFormat( size, decimals = 0 ) {
		var bytes = parseFloat( size ),
			units = [ 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' ],
			i = 0;

		if ( isNaN( bytes ) ) {
			return '0 B';
		}

		while ( bytes >= 1024 ) {
			bytes /= 1024;
			++i;
		}

		return bytes.toFixed( decimals ) + ' ' + units[ i ];
	}

	/* Event callback functions */

	/**
	 * Event callback: Convert an item.
	 *
	 * @since 2.2.0
	 *
	 * @param event e Event object.
	 */
	 function convertItem() {
		var $clicked = $( this ),
			$itemTd = $clicked.closest( 'td' ),
			$primaryLink = $itemTd.find( 'a.w3tc-convert' ).first();

		// Fallback: if no primary link found, use clicked link.
		if ( ! $primaryLink.length ) {
			$primaryLink = $clicked;
		}

		// If the conversion was canceled and the compression setting is "lossless", then go to the settings page.
		if ( 'notconverted' === $primaryLink.data( 'status' ) && 'lossless' === w3tcData.settings.compression ) {
			window.location.href = w3tcData.settingsUrl;
			return;
		}

		$primaryLink
			.text( w3tcData.lang.sending )
			.prop( 'aria-disabled' , 'true')
			.closest( 'span' ).addClass( 'w3tc-disabled' );

		// Remove any previous optimization information, revert link, and error notices.
		$itemTd.find( '.w3tc-converted-reduced, .w3tc-converted-increased, .w3tc-notconverted, .w3tc-revert, .w3tc-imageservice-error, .w3tc-converted-error, .w3tc-convert-avif, .w3tc-convert-webp' ).remove();

		// Get format from data-format attribute if specified (for "Convert to AVIF" or "Convert to WebP" links).
		var format = $clicked.data( 'format' );
		var ajaxData = {
			_wpnonce: w3tcData.nonces.submit,
			action: 'w3tc_imageservice_submit',
			post_id: $primaryLink.data( 'post-id' )
		};

		// Add format parameter if specified.
		if ( format ) {
			ajaxData.format = format;
		}

		$.ajax({
			method: 'POST',
			url: ajaxurl,
			data: ajaxData
		})
			.done( function( response ) {
				if ( response.success ) {
					$primaryLink
						.text( w3tcData.lang.processing )
						.data( 'status', 'processing' );

					startCheckItems();
				} else if ( response.data && response.data.hasOwnProperty( 'error' ) ) {
					$primaryLink
						.text( w3tcData.lang.error )
						.data( 'status', 'error' );

					$itemTd.append(
						'<div class="notice notice-error inline">' +
						response.data.error +
						'</div>'
					);
				} else {
					$primaryLink
						.text( w3tcData.lang.error )
						.data( 'status', 'error' );

					$itemTd.append(
						'<div class="notice notice-error inline w3tc-imageservice-error">' +
						w3tcData.lang.apiError +
						'</div>'
					);
				}
			})
			.fail( function( response ) {
				var message,
					rebindBuyClick = false,
					$wrap = $( '.wrap' );

				$primaryLink
					.text( w3tcData.lang.error )
					.data( 'status', 'error' );

				if (
					response && response.hasOwnProperty( 'responseJSON' ) &&
					response.responseJSON && response.responseJSON.hasOwnProperty( 'data' ) &&
					response.responseJSON.data.hasOwnProperty( 'error' )
				) {
					message = response.responseJSON.data.error;
				} else if (
					response && response.hasOwnProperty( 'responseJSON' ) &&
					response.responseJSON.hasOwnProperty( 'data' ) &&
					response.responseJSON.data.hasOwnProperty( 'message' )
				) {
					message = response.responseJSON.data.message;
					rebindBuyClick = true;

					if ( 'accept' === w3tcData.tos_choice && w3tcData.track_usage ) {
						(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
							(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
							m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
							})(window,document,'script','https://api.w3-edge.com/v1/analytics','w3tc_ga');

						if ( window.w3tc_ga ) {
							w3tc_ga( 'create', w3tcData.ga_profile, 'auto' );
							w3tc_ga( 'send', 'event', 'w3tc_error', 'imageservice', response.responseJSON.data.code );
						}
					}
				} else {
					message = w3tcData.lang.ajaxFail;
				}

				$itemTd.append(
					'<div class="notice notice-error inline w3tc-imageservice-error">' +
					message +
					'</div>'
				);

				// Rebind click event handler after adding a new link that may need it.
				if ( rebindBuyClick ) {
					// Ensure overlay.
					if ( 'w3tc' !== $wrap.attr( 'id' ) ) {
						$wrap.attr( 'id', 'w3tc' );
					}

					// Rebind click event.
					$( '.button-buy-plugin' )
					.off( 'click' )
					.on( 'click',  function() {
						if ( ! $( '.w3tc-overlay' ).length ) {
							w3tc_lightbox_upgrade( w3tc_nonce, $( this ).data('src'), null );
						}
					} );
				}
			});
	}

	/**
	 * Event callback: Revert item.
	 *
	 * @since 2.2.0
	 *
	 * @param event e Event object.
	 */
	function revertItem() {
		var $this = $( this ),
			$itemTd = $this.closest( 'td' ),
			$convertLink = $itemTd.find( 'a.w3tc-convert' );

		$this
			.text( w3tcData.lang.reverting )
			.prop( 'aria-disabled', 'true' )
			.closest( 'span' ).addClass( 'w3tc-disabled' );

		$convertLink
			.prop( 'aria-disabled', 'true' )
			.closest( 'span' ).addClass( 'w3tc-disabled' );

		// Remove error notices.
		$itemTd.find( '.w3tc-imageservice-error' ).remove();

		$.ajax({
			method: 'POST',
			url: ajaxurl,
			data: {
				_wpnonce: w3tcData.nonces.revert,
				action: 'w3tc_imageservice_revert',
				post_id: $convertLink.data( 'post-id' )
			}
		})
			.done( function( response ) {
				if ( response.success ) {
					$this.closest( 'span' ).remove(); // Remove the revert link.
					$itemTd.find( 'div' ).remove(); // Remove optimization info.
					$itemTd.find( '.w3tc-convert-avif, .w3tc-convert-webp' ).remove(); // Remove secondary convert links.

					$convertLink
						.text( w3tcData.lang.convert )
						.prop( 'aria-disabled', false )
						.data( 'status', null )
						.closest( 'span' ).removeClass( 'w3tc-disabled' );
				} else if ( response.data && response.data.hasOwnProperty( 'error' ) ) {
					$this
						.text( w3tcData.lang.error )
						.data( 'status', 'error' );

					$itemTd.parent().append(
						'<div class="notice notice-error inline">' +
						response.data.error +
						'</div>'
					);
				} else {
					$this
						.text( w3tcData.lang.error )
						.data( 'status', 'error' );

					$itemTd.append(
						'<div class="notice notice-error inline w3tc-imageservice-error">' +
						w3tcData.lang.apiError +
						'</div>'
					);
				}
			})
			.fail( function( response ) {
				var message;

				$this
					.text( w3tcData.lang.error )
					.data( 'status', 'error' );

				if (
					response && response.hasOwnProperty( 'responseJSON' ) &&
					response.responseJSON && response.responseJSON.hasOwnProperty( 'data' ) &&
					response.responseJSON.data.hasOwnProperty( 'error' )
				) {
					message = response.responseJSON.data.error;
				} else {
					message = w3tcData.lang.ajaxFail;
				}

				$itemTd.append(
					'<div class="notice notice-error inline w3tc-imageservice-error">' +
					message +
					'</div>'
				);
			});
	}

	/**
	 * Event callback: Convert all items.
	 *
	 * @since 2.2.0
	 *
	 * @see refreshStats()
	 * @see refreshUsage()
	 */
	 function convertItems() {
		var $this = $( this ),
			$parent = $this.parent();

		$this
			.text( w3tcData.lang.sending )
			.prop( 'disabled', true )
			.prop( 'aria-disabled', 'true' );

		// Remove error notices.
		$parent.find( '.w3tc-imageservice-error' ).remove();

		$.ajax({
			method: 'POST',
			url: ajaxurl,
			data: {
				_wpnonce: w3tcData.nonces.submit,
				action: 'w3tc_imageservice_all'
			}
		})
			.done( function( response ) {
				if ( response.success ) {
					$this.text( w3tcData.lang.submitted );
					$parent.append(
						'<div class="notice notice-info inline">' +
						w3tcData.lang.submittedAllDesc +
						'</div>'
					);
					refreshStats();
					refreshUsage();
				} else if ( response.data && response.data.hasOwnProperty( 'error' ) ) {
					$this.text( w3tcData.lang.error );
					$parent.append(
						'<div class="notice notice-error inline">' +
						response.data.error +
						'</div>'
					);
				} else {
					$this.text( w3tcData.lang.error );
					$parent.append(
						'<div class="notice notice-error inline w3tc-imageservice-error">' +
						w3tcData.lang.apiError +
						'</div>'
					);
				}
			})
			.fail( function() {
				$this.text( w3tcData.lang.error );
				$parent.append(
					'<div class="notice notice-error inline w3tc-imageservice-error">' +
					w3tcData.lang.ajaxFail +
					'</div>'
				);
			});
	}

	/**
	 * Event callback: Revert all items.
	 *
	 * @since 2.2.0
	 *
	 * @see refreshStats()
	 */
	 function revertItems() {
		var $this = $( this );

		$this.text( w3tcData.lang.reverting )
			.prop( 'disabled', true )
			.prop( 'aria-disabled', 'true' );

		$.ajax({
			method: 'POST',
			url: ajaxurl,
			data: {
				_wpnonce: w3tcData.nonces.submit,
				action: 'w3tc_imageservice_revertall'
			}
		})
			.done( function( response ) {
				if ( response.success ) {
					$this.text( w3tcData.lang.reverted );
					$convertAllButton
						.prop( 'disabled', false )
						.prop( 'aria-disabled', 'false' );
					refreshStats();
				} else if ( response.data && response.data.hasOwnProperty( 'error' ) ) {
					$this
						.text( w3tcData.lang.error )
						.parent().append(
							'<div class="notice notice-error inline">' +
							response.data.error +
							'</div>'
						);
				} else {
					$this
						.text( w3tcData.lang.error )
						.parent().append(
							'<div class="notice notice-error inline w3tc-imageservice-error">' +
							w3tcData.lang.apiError +
							'</div>'
						);
				}
			})
			.fail( function() {
				$this
					.text( w3tcData.lang.error )
					.parent().append(
						'<div class="notice notice-error inline w3tc-imageservice-error">' +
						w3tcData.lang.ajaxFail +
						'</div>'
					);
			});
	}
})( jQuery );
