/**
 * File and cropper workflow for PPOM frontend fields.
 *
 * Each file/cropper field gets a dedicated Plupload instance. This script owns
 * the upload UI, preview/croppie state, and the hidden inputs that eventually
 * travel through add-to-cart, cart restore, and order meta persistence.
 *
 * @see ppom_get_field_meta_by_id in js/ppom.inputs.js
 * @see ppom_update_option_prices in js/price/ppom-price.js
 * @see ppom_generate_cropper_data_for_cart
 */

/**
 * Minimal localized metadata used by the upload/cropper bootstrap.
 *
 * @typedef {{
 *   data_name: string,
 *   type: 'file'|'cropper',
 *   file_size: string,
 *   files_allowed: string,
 *   file_types: string,
 *   title?: string,
 *   required?: string,
 *   file_cost?: string,
 *   onetime?: string,
 *   max_img_w?: string,
 *   min_img_w?: string,
 *   max_img_h?: string,
 *   min_img_h?: string
 * }} PPOMUploadFieldMeta
 */
let isCartBlock = false;
// Runtime registries keyed by PPOM field data_name.
const plupload_instances = Array();
const field_file_count = Array();
const file_list_preview_containers = Array();
const ppom_file_progress = '';
const featherEditor = '';
const uploaderInstances = {};
const Cropped_Data_Captured = false;

// Track nonce refresh state to avoid duplicate requests
let nonceRefreshPromise = null;
let lastNonceRefreshTime = 0;
const NONCE_CACHE_DURATION = 300000; // 5 minutes in milliseconds

/**
 * Fetches fresh nonces from the REST API endpoint.
 *
 * This function is called before file operations to ensure nonces are valid,
 * solving the issue of stale nonces in cached pages or long-lived browser tabs.
 *
 * @returns {Promise<Object>} Promise that resolves with fresh nonce data.
 */
async function ppom_refresh_file_nonces() {
	// If we have a pending refresh request, return it instead of making a new one
	if ( nonceRefreshPromise ) {
		return nonceRefreshPromise;
	}

	// If nonces were refreshed recently (within cache duration), skip refresh
	const now = Date.now();
	if ( now - lastNonceRefreshTime < NONCE_CACHE_DURATION ) {
		return Promise.resolve( {
			ppom_file_upload_nonce: ppom_file_vars.ppom_file_upload_nonce,
			ppom_file_delete_nonce: ppom_file_vars.ppom_file_delete_nonce,
		} );
	}

	nonceRefreshPromise = fetch( ppom_file_vars.rest_url, {
		method: 'GET',
		credentials: 'same-origin',
		headers: {
			'Content-Type': 'application/json',
		},
	} )
		.then( ( response ) => {
			if ( ! response.ok ) {
				throw new Error( 'Failed to refresh nonces' );
			}
			return response.json();
		} )
		.then( ( data ) => {
			if ( data.status === 'success' ) {
				// Update the global nonce variables
				ppom_file_vars.ppom_file_upload_nonce =
					data.ppom_file_upload_nonce;
				ppom_file_vars.ppom_file_delete_nonce =
					data.ppom_file_delete_nonce;
				lastNonceRefreshTime = Date.now();
				return data;
			}
			throw new Error( 'Invalid nonce response' );
		} )
		.finally( () => {
			// Clear the promise so next request can proceed
			nonceRefreshPromise = null;
		} );

	return nonceRefreshPromise;
}

jQuery( function ( $ ) {
	// Keep cropper previews, price recalculation, and modal placement aligned
	// with the rest of the PPOM product form lifecycle.
	// If cropper input found in fields
	// if (ppom_get_field_meta_by_type('cropper').length > 0) {

	//     var wc_cart_form = $('form.cart');
	//     $(wc_cart_form).on('submit', function(e) {

	//         // e.preventDefault();
	//         var cropper_fields = ppom_get_field_meta_by_type('cropper');
	//         $.each(cropper_fields, function(i, cropper) {

	//             if (cropper.legacy_cropper !== undefined) return;

	//             var cropper_name = cropper.data_name;
	//             ppom_generate_cropper_data_for_cart(cropper.data_name);

	//         });
	//     });
	// }

	$( document ).on( 'ppom_image_ready', function ( e ) {
		const image_url = e.image_url;
		const image_id = e.image.id;
		const data_name = e.data_name;
		const input_type = e.input_type;
		const file_input = e.file_input;

		if ( input_type === 'cropper' ) {
			field_meta = ppom_get_field_meta_by_id( data_name );
			// console.log('ppom',field_meta)
			if ( field_meta.legacy_cropper === undefined ) {
				ppom_show_cropped_preview(
					data_name,
					image_url,
					image_id,
					file_input
				);
				// hiding the filelist-{data_name} when preview enabled
				$( `#filelist-${ data_name }` ).hide();
				// hide the file upload area too
				$( `.ppom-file-container.${ data_name }` ).hide();
				// also hide the crop ratio if only one option is provided
				if ( $( `#crop-size-${ data_name } option` ).length === 1 ) {
					$( `#crop-size-${ data_name }` ).hide();
				}
			}
		}

		// moving modal to body end
		$( '.ppom-modals' ).appendTo( 'body' );
	} );

	// On file removed
	$( document ).on( 'ppom_uploaded_file_removed', function ( e ) {
		const field_name = e.field_name;
		// var fileid      = e.fileid;

		ppom_reset_cropping_preview( field_name );
		ppom_update_option_prices();
	} );

	// Croppie update size
	$( '.ppom-croppie-preview' ).on(
		'change',
		'.ppom-cropping-size',
		function ( e ) {
			const data_name = $( this ).data( 'field_name' );
			const cropp_preview_container = jQuery(
				'.ppom-croppie-wrapper-' + data_name
			);
			const v_width = $( 'option:selected', this ).data( 'width' );
			const v_height = $( 'option:selected', this ).data( 'height' );

			cropp_preview_container
				.find( '.croppie-container' )
				.each( function ( i, croppie_dom ) {
					const image_id = jQuery( croppie_dom ).attr(
						'data-image_id'
					);
					const croppie_container = jQuery(
						'.ppom-croppie-preview-' + image_id
					);
					const image_url = jQuery( croppie_dom )
						.find( 'img' )
						.attr( 'src' );
					$( croppie_dom ).croppie( 'destroy' );
					const viewport = { width: v_width, height: v_height };

					file_list_preview_containers[ data_name ].croppie[
						image_id
					] = croppie_container;
					file_list_preview_containers[ data_name ].image_id = image_id;
					file_list_preview_containers[ data_name ].image_url = image_url;

					ppom_set_croppie_options( data_name, viewport, image_id );
				} );
		}
	);

	// Deleting File
	document
		.querySelector( '.ppom-wrapper' )
		?.addEventListener( 'click', async function ( e ) {
			if (
				! e.target.classList.contains( 'u_i_c_tools_del' ) ||
				! plupload_instances
			) {
				return;
			}

			e.preventDefault();

			const delMessage = ppom_file_vars.delete_file_msg;
			if ( ! confirm( delMessage ) ) {
				return;
			}

			const ppomFileWrapper = e.target.closest( '.ppom-file-wrapper' );
			const fileId = ppomFileWrapper?.getAttribute( 'data-fileid' );
			const ppomFieldWrapper = e.target.closest(
				'div.ppom-field-wrapper'
			);
			const fileDataName =
				ppomFieldWrapper?.getAttribute( 'data-data_name' );

			if ( ! fileId || ! fileDataName ) {
				return;
			}

			field_file_count[ fileDataName ] = 0;

			const uploaderInstance = plupload_instances[ fileDataName ];
			if ( uploaderInstance ) {
				uploaderInstance.removeFile( fileId );
			}

			const checkbox = document.querySelector(
				`input[name="ppom[fields][${ fileDataName }][${ fileId }][org]"]`
			);
			const fileName = checkbox?.value;

			if ( ! fileName ) {
				return;
			}

			// Delete animation.
			const imageElement = document.querySelector(
				`#u_i_c_${ fileId } img`
			);
			if ( imageElement ) {
				imageElement.src = `${ ppom_file_vars.plugin_url }/images/loading.gif`;
			}

			// Refresh nonces before delete operation
			try {
				await ppom_refresh_file_nonces();
			} catch ( error ) {
				// Continue with existing nonce if refresh fails
				console.warn(
					'Failed to refresh nonce, using existing:',
					error
				);
			}

			const data = new URLSearchParams( {
				action: 'ppom_delete_file',
				file_name: fileName,
				ppom_nonce: ppom_file_vars.ppom_file_delete_nonce,
			} );

			try {
				const response = await fetch( ppom_file_vars.ajaxurl, {
					method: 'POST',
					body: data,
					headers: {
						'Content-Type': 'application/x-www-form-urlencoded',
						'X-Requested-With': 'XMLHttpRequest',
					},
				} );

				const responseText = await response.text();
				if ( ! response.ok ) {
					confirm( `Error: ${ responseText }` );
					return;
				}

				// Update UI
				const fileContainer = document.querySelector(
					`#u_i_c_${ fileId }`
				);
				if ( fileContainer ) {
					fileContainer.remove();
				}

				if ( checkbox ) {
					checkbox.remove();
				}

				const parentBox = e.target.closest( '.u_i_c_box' );
				if ( parentBox ) {
					parentBox.remove();
				}

				const croppiePreview = document.querySelector(
					`.ppom-croppie-preview-${ fileId }`
				);
				if ( croppiePreview ) {
					croppiePreview.remove();
				}

				// Send action to PPOM_Validate
				document.dispatchEvent(
					new CustomEvent( 'ppom_uploaded_file_removed', {
						detail: {
							field_name: fileDataName,
							fileid: fileId,
							time: new Date(),
						},
					} )
				);

				// Decrease file count
				field_file_count[ fileDataName ] -= 1;
			} catch ( error ) {
				confirm( `Error: ${ error.message }` );
			}
		} );

	$.each( ppom_input_vars.ppom_inputs, function ( index, file_input ) {
		if ( file_input.type === 'file' || file_input.type === 'cropper' ) {
			const file_data_name = file_input.data_name;
			ppom_setup_file_upload_input( file_input );
		}
	} ); // $.each(ppom_file_vars
} ); //	jQuery(function($){});

// Build the temporary thumbnail shell shown while a file is uploading.
function add_thumb_box( file, $filelist_DIV ) {
	let inner_html =
		'<div class="u_i_c_thumb"><div class="progress_bar"><span class="progress_bar_runner"></span><span class="progress_bar_number">(' +
		plupload.formatSize( file.size ) +
		')<span></div></div>';
	inner_html +=
		'<div class="u_i_c_name"><strong>' + file.name + '</strong></div>';

	jQuery( '<div />', {
		id: 'u_i_c_' + file.id,
		class: 'uk-text-center ppom-file-wrapper',
		'data-fileid': file.id,
		html: inner_html,
	} ).appendTo( $filelist_DIV );

	// clearfix
	// 1- removing last clearfix first
	$filelist_DIV.find( '.u_i_c_box_clearfix' ).remove();

	jQuery( '<div />', {
		class: 'u_i_c_box_clearfix',
	} ).appendTo( $filelist_DIV );
}

// save croped/edited photo
function save_edited_photo( img_id, photo_url ) {
	//console.log(img_id);

	//setting new image width to 75
	jQuery( '#' + img_id ).attr( 'width', 75 );

	//disabling add to cart button for a while
	jQuery( 'form.cart' ).block( {
		message: null,
		overlayCSS: {
			background: '#fff',
			opacity: 0.6,
		},
	} );
	const post_data = {
		action: 'ppom_save_edited_photo',
		image_url: photo_url,
		filename: jQuery( '#' + img_id ).attr( 'data-filename' ),
	};

	jQuery.post( ppom_file_vars.ajaxurl, post_data, function ( resp ) {
		//console.log( resp );
		jQuery( 'form.cart' ).unblock();
	} );
}

// Once an upload finishes, create the Croppie preview that feeds the hidden
// cropped-image payload later submitted with the add-to-cart request.
function ppom_show_cropped_preview(
	file_name,
	image_url,
	image_id,
	file_input
) {
	const cropp_preview_container = jQuery(
		'.ppom-croppie-wrapper-' + file_name
	);
	// Enable size option
	cropp_preview_container
		.find( '.ppom-cropping-size' )
		.prop( 'disabled', false );
	cropp_preview_container.find( '.ppom-cropping-size' ).show();

	const container_width = jQuery(
		'#ppom-file-container-' + file_name
	).width();
	const croppie_container = jQuery( '<div/>' )
		.addClass( 'ppom-croppie-preview-' + image_id )
		.attr( 'data-image_id', image_id )
		.appendTo( cropp_preview_container );

	// Change preview image
	jQuery( '<a/>' )
		.addClass( 'btn ' + image_id )
		.attr( 'href', 'javascript:;' )
		.attr( 'id', 'selectfiles-' + file_name + '-' + image_id )
		.attr( 'data-field-name', file_name )
		.attr( 'data-image-id', image_id )
		.html( 'Change image' )
		.appendTo( cropp_preview_container )
		.click( function ( e ) {
			e.preventDefault();
		} );

	const file_inputs = {
		...file_input,
		data_name: file_name + '-' + image_id,
		is_change_image: true,
		original_data_name: file_name,
	};
	ppom_setup_file_upload_input( file_inputs );

	// file_list_preview_containers[file_name]['croppie'] = cropp_preview_container.find('.ppom-croppie-preview');

	jQuery( croppie_container ).on(
		'update.croppie',
		function ( ev, cropData ) {
			// console.log(cropData);
			// croppie_container.croppie('result', 'rawcanvas').then(function(canvas) {
			// console.log(canvas);

			ppom_generate_cropper_data_for_cart( file_name );

			jQuery.event.trigger( {
				type: 'ppom_croppie_update',
				img_id: image_id,
				croppie_obj: croppie_container,
				crop_data: cropData,
				dataname: file_name,
				time: new Date(),
			} );
		}
	);

	file_list_preview_containers[ file_name ].croppie[ image_id ] =
		croppie_container;
	file_list_preview_containers[ file_name ].image_id = image_id;
	file_list_preview_containers[ file_name ].image_url = image_url;

	file_list_preview_containers[ file_name ].container_width =
		container_width;
	ppom_set_croppie_options( file_name, undefined, image_id );
}

function ppom_set_croppie_options( file_name, viewport, image_id ) {
	const croppie_options = ppom_file_vars.croppie_options;
	jQuery.each( croppie_options, function ( field_name, option ) {
		if ( file_name === field_name ) {
			option.url = file_list_preview_containers[ file_name ].image_url;
			if ( viewport !== undefined ) {
				viewport.type = option.viewport.type;
				option.viewport = viewport;
			}

			const preview = file_list_preview_containers[ file_name ];
			let applied = option;
			if (
				preview.container_width !== undefined &&
				preview.container_width !== null
			) {
				applied = get_responsive_croppie_options(
					option,
					preview.container_width
				);
			}
			// console.log($filelist_DIV[file_name]['croppie'][image_id]);
			preview.croppie[ image_id ].croppie( applied );
		}
	} );
}

// Reset cropping when image removed
function ppom_reset_cropping_preview( file_name ) {
	const cropp_preview_container = jQuery(
		'.ppom-croppie-wrapper-' + file_name
	);
	// Reseting preview DOM
	cropp_preview_container.find( '.ppom-croppie-preview' ).html( '' );
}

/**
 * Attach one Plupload instance per PPOM file/cropper field and keep the
 * resulting hidden checkbox inputs compatible with the price/validation stack.
 *
 * @param {PPOMUploadFieldMeta} file_input
 * @return {void}
 */
function ppom_setup_file_upload_input( file_input ) {
	const file_inputs = file_input;
	const parts = file_input.data_name.split( '-' );
	const [ file_data_name, file_id ] = parts;
	let data_name = file_data_name;

	if ( file_id !== undefined ) {
		data_name = file_data_name + '-' + file_id;
	}

	if ( plupload_instances[ data_name ] !== undefined ) {
		return;
	}

	if ( ! Object.prototype.hasOwnProperty.call( field_file_count, file_data_name ) ) {
		field_file_count[ file_data_name ] = 0;
	}
	file_list_preview_containers[ file_data_name ] = jQuery(
		'#filelist-' + file_data_name
	);

	// Energy pack
	const bar = window.document.getElementById(
		`ppom-progressbar-${ file_data_name }`
	);

	const ppom_file_data = {
		action: 'ppom_upload_file',
		data_name: file_data_name,
		ppom_nonce: ppom_file_vars.ppom_file_upload_nonce,
		product_id: ppom_file_vars.product_id,
	};

	let img_dim_errormsg = 'Please upload correct image dimension';
	if ( file_input.img_dimension_error ) {
		img_dim_errormsg = file_input.img_dimension_error;
	}

	plupload_instances[ file_data_name ] = new plupload.Uploader( {
		runtimes: ppom_file_vars.plupload_runtime,
		browse_button: 'selectfiles-' + data_name, // you can pass in id...
		container: 'ppom-file-container-' + file_data_name, // ... or DOM Element itself
		drop_element: 'ppom-file-container-' + file_data_name,
		url: ppom_file_vars.ajaxurl,
		multipart_params: ppom_file_data,
		max_file_size: file_input.file_size,
		max_file_count: parseInt( file_input.files_allowed ),
		unique_names: ppom_file_vars.enable_file_rename,
		chunk_size: '2mb',
		unique_names: false,

		filters: {
			mime_types: [
				{ title: 'Filetypes', extensions: file_input.file_types },
			],
		},

		init: {
			PostInit() {
				// file_list_preview_containers[file_data_name].html('');
				if (
					! file_list_preview_containers[ file_data_name ].is(
						':visible'
					)
				) {
					jQuery( document ).on( 'ppom_field_shown', function () {
						jQuery.each(
							ppom_input_vars.ppom_inputs,
							function ( index, file_input ) {
								if (
									file_input &&
									( file_input.type === 'file' ||
										file_input.type === 'cropper' )
								) {
									if (
										file_input.data_name &&
										file_input.files_allowed &&
										file_input.file_size &&
										file_input.files_allowed
									) {
										ppom_setup_file_upload_input(
											file_input
										);
									}
								}
							}
						);
					} );
				}
				/*$('#uploadfiles-'+file_data_name).bind('click', function() {
                	upload_instance[file_data_name].start();
                	return false;
                });*/
			},

			FilesAdded( up, files ) {
				// Adding progress bar
				const file_pb = jQuery( '<div/>' )
					.addClass( 'progress' )
					.css( 'width', '100%' )
					.css( 'clear', 'both' )
					.css( 'margin', '5px auto' )
					.appendTo( file_list_preview_containers[ file_data_name ] );
				const file_pb_runner = jQuery( '<div/>' )
					.addClass( 'progress-bar' )
					.attr( 'role', 'progressbar' )
					.attr( 'aria-valuenow', 0 )
					.attr( 'aria-valuemin', 0 )
					.attr( 'aria-valuemax', 100 )
					.css( 'height', '15px' )
					.css( 'width', 0 )
					.appendTo( file_pb );

				const files_added = files.length;
				// return;

				// console.log('image w bac', files);
				// plupload.each(files, function(file, i) {
				//     var img = new mOxie.Image;
				//     img.onload = function() {
				//         var img_height = this.height;
				//         var img_width = this.width;
				//         // if ((img_height >= 1024 || img_height <= 1100) && (img_width >= 750 || img_width <= 800)) {
				//         if ((img_width >= parseFloat(file_input.max_img_w) || img_width <= parseFloat(file_input.min_img_w))) {
				//             alert("Height and Width must not exceed 1100*800.");
				//             return false;
				//         }
				//         console.log('image h', parseFloat(file_input.max_img_w));
				//         // access image size here using this.width and this.height
				//     };
				//     img.load(file.getSource());
				// });

				if ( file_id !== undefined ) {
					--field_file_count[ file_data_name ];
				}

				if (
					field_file_count[ file_data_name ] + files_added >
					plupload_instances[ file_data_name ].settings.max_file_count
				) {
					alert(
						plupload_instances[ file_data_name ].settings
							.max_file_count +
							ppom_file_vars.mesage_max_files_limit
					);
				} else {
					if ( file_id !== undefined ) {
						jQuery( '.ppom-croppie-preview-' + file_id )
							.hide( 500 )
							.remove();
						jQuery( `.btn.${ file_id }` ).hide( 500 ).remove();
						jQuery( '#u_i_c_' + file_id ).hide( 500 ).remove();
						jQuery(
							`input[name="ppom[fields][${ file_data_name }][${ file_data_name }][cropped]"]`
						)
							.hide( 500 )
							.remove();
					}

					plupload.each( files, function ( file ) {
						if (
							file.type.indexOf( 'image' ) !== -1 &&
							file.type !== 'image/photoshop'
						) {
							const img = new moxie.image.Image();
							img.load = function () {
								const img_height = this.height;
								const img_width = this.width;

								const aspect_ratio =
									Math.max( img_width, img_height ) /
									Math.min( img_width, img_height );

								if (
									img_width >=
										parseFloat( file_input.max_img_w ) ||
									img_width <=
										parseFloat( file_input.min_img_w ) ||
									img_height >=
										parseFloat( file_input.max_img_h ) ||
									img_height <=
										parseFloat( file_input.min_img_h )
								) {
									up.removeFile( file );
									alert( img_dim_errormsg );
								} else {
									field_file_count[ file_data_name ]++;
									// Code to add pending file details, if you want
									add_thumb_box(
										file,
										file_list_preview_containers[
											file_data_name
										],
										up
									);
									up.start();
								}
							};
							img.load( file.getSource() );
						} else {
							field_file_count[ file_data_name ]++;
							// Code to add pending file details, if you want
							add_thumb_box(
								file,
								file_list_preview_containers[ file_data_name ],
								up
							);
							up.start();
						}

						// Energy pack
						if ( bar ) {
							bar.removeAttribute( 'hidden' );
							bar.max = file.size;
							bar.value = file.loaded;
						}
					} );
				}
			},

			FileUploaded( up, file, info ) {
				const obj_resp = jQuery.parseJSON( info.response );

				if ( obj_resp.file_name === 'ThumbNotFound' ) {
					plupload_instances[ file_data_name ].removeFile( file.id );
					jQuery( '#u_i_c_' + file.id )
						.hide( 500 )
						.remove();
					field_file_count[ file_data_name ]--;

					alert( 'There is some error please try again' );
					return;
				} else if ( obj_resp.status === 'error' ) {
					plupload_instances[ file_data_name ].removeFile( file.id );

					jQuery( '#u_i_c_' + file.id )
						.hide( 500 )
						.remove();

					field_file_count[ file_data_name ]--;
					alert( obj_resp.message );
					return;
				}

				// var img_w = obj_resp.file_w
				// var img_h = obj_resp.file_h
				// if (img_w > parseFloat(file_input.max_img_w)) {
				//     upload_instance[file_data_name].removeFile(file.id);
				//     jQuery("#u_i_c_" + file.id).hide(500).remove();
				//     file_count[file_data_name]--;
				//     alert('Image Dimension Error');
				//     jQuery('form.cart').unblock();
				//     return;
				// }

				let file_thumb = '';

				/*if( file_input.file_cost != "" ) {
                    jQuery('input[name="woo_file_cost"]').val( file_input.file_cost );
                }*/

				file_list_preview_containers[ file_data_name ]
					.find( '#u_i_c_' + file.id )
					.html( obj_resp.html )
					.trigger( {
						type: 'ppom_image_ready',
						image: file,
						data_name: file_data_name,
						input_type: file_input.type,
						image_url: obj_resp.file_url,
						image_resp: obj_resp,
						file_input: file_inputs,
						time: new Date(),
					} );

				// checking if uploaded file is thumb
				const ext = obj_resp.file_name
					.substring( obj_resp.file_name.lastIndexOf( '.' ) + 1 )
					.toLowerCase();

				if (
					ext === 'png' ||
					ext === 'gif' ||
					ext === 'jpg' ||
					ext === 'jpeg'
				) {
					const file_full =
						ppom_file_vars.file_upload_path + obj_resp.file_name;
					// thumb thickbox only shown if it is image
					file_list_preview_containers[ file_data_name ]
						.find( '#u_i_c_' + file.id )
						.find( '.u_i_c_thumb' )
						.append(
							'<div style="display:none" id="u_i_c_big' +
								file.id +
								'"><img src="' +
								file_full +
								'" /></div>'
						);

					// Aviary editing tools
					if (
						file_input.photo_editing === 'on' &&
						ppom_file_vars.aviary_api_key !== ''
					) {
						const editing_tools = file_input.editing_tools;
						file_list_preview_containers[ file_data_name ]
							.find( '#u_i_c_' + file.id )
							.find( '.u_i_c_tools_edit' )
							.append(
								'<a onclick="return   (\'thumb_' +
									file.id +
									"', '" +
									file_full +
									"', '" +
									obj_resp.file_name +
									"', '" +
									editing_tools +
									'\')" href="javascript:;" title="Edit"><img width="15" src="' +
									ppom_file_vars.plugin_url +
									'/images/edit.png" /></a>'
							);
					}
				} else {
					file_thumb = ppom_file_vars.plugin_url + '/images/file.png';
					file_list_preview_containers[ file_data_name ]
						.find( '#u_i_c_' + file.id )
						.find( '.u_i_c_thumb' )
						.html(
							'<img src="' +
								file_thumb +
								'" id="thumb_' +
								file.id +
								'" />'
						);
				}

				// adding checkbox input to Hold uploaded file name as array
				const file_container = file_list_preview_containers[
					file_data_name
				].find( '#u_i_c_' + file.id );
				let input_class = 'ppom-input';
				input_class +=
					file_input.required === 'on' ? ' ppom-required' : '';

				// Add file check
				jQuery(
					'<input checked="checked" name="ppom[fields][' +
						file_data_name +
						'][' +
						file.id +
						'][org]" type="checkbox"/>'
				)
					.attr( 'data-price', file_input.file_cost )
					.attr( 'data-label', obj_resp.file_name )
					.attr( 'data-data_name', file_input.data_name )
					.attr( 'data-title', file_input.title )
					.attr( 'data-onetime', file_input.onetime )
					.val( obj_resp.file_name )
					.css( 'display', 'none' )
					.addClass( 'ppom-file-cb-' + file_data_name )
					.addClass( 'ppom-file-cb' )
					.addClass( input_class )
					.appendTo( file_container )
					.trigger( 'change' );

				ppom_update_option_prices();

				jQuery( 'form.cart' ).unblock();
				isCartBlock = false;

				// Removing progressbar
				file_list_preview_containers[ file_data_name ]
					.find( '.progress' )
					.remove();

				if ( bar ) {
					setTimeout( function () {
						bar.setAttribute( 'hidden', 'hidden' );
					}, 1000 );
					bar.max = file.size;
					bar.value = file.loaded;
				}

				// Trigger
				jQuery.event.trigger( {
					type: 'ppom_file_uploaded',
					file,
					file_meta: file_input,
					file_resp: obj_resp,
					time: new Date(),
				} );
			},

			async BeforeUpload( up, file ) {
				// Refresh nonces before upload to handle stale nonces in cached pages
				try {
					await ppom_refresh_file_nonces();
					// Update the multipart_params with the fresh nonce
					up.setOption( 'multipart_params', {
						action: 'ppom_upload_file',
						data_name: file_data_name,
						ppom_nonce: ppom_file_vars.ppom_file_upload_nonce,
						product_id: ppom_file_vars.product_id,
					} );
				} catch ( error ) {
					// Log warning but continue with existing nonce
					console.warn(
						'Failed to refresh upload nonce, using existing:',
						error
					);
				}
			},

			UploadProgress( up, file ) {
				// Energy pack
				if ( bar ) {
					bar.max = file.size;
					bar.value = file.loaded;
				}

				file_list_preview_containers[ file_data_name ]
					.find( '.progress-bar' )
					.css( 'width', file.percent + '%' );

				//disabling add to cart button for a while
				if ( ! isCartBlock ) {
					jQuery( 'form.cart' ).block( {
						message: null,
						overlayCSS: {
							background: '#fff',
							opacity: 0.6,
							onBlock() {
								isCartBlock = true;
							},
						},
					} );
				}
			},

			Error( up, err ) {
				if ( -600 === err.code && file_input.file_size ) {
					alert( ppom_file_vars.max_file_size.replace( '%s', file_input.file_size.toUpperCase() )  );
				} else if ( -601 === err.code && file_input.file_types ) {
					alert( ppom_file_vars.invalid_file_type);
				} else if ( -602 === err.code ) {
					alert( ppom_file_vars.duplicate_file );
				} else {
					alert( 'Error #' + err.code + ': ' + err.message );
				}
			},
		},
	} );

	// console.log('running file', upload_instance[file_data_name]);
	plupload_instances[ file_data_name ].init();
	uploaderInstances[ file_data_name ] = plupload_instances[ file_data_name ];
}

// Persist the Croppie canvas output into hidden inputs so PHP can rebuild the
// edited image from the same request payload used for normal uploaded files.
function ppom_generate_cropper_data_for_cart( field_name ) {
	const cropp_preview_container = jQuery(
		'.ppom-croppie-wrapper-' + field_name
	);

	cropp_preview_container
		.find( '.croppie-container' )
		.each( function ( i, croppie_dom ) {
			const image_id = jQuery( croppie_dom ).attr( 'data-image_id' );
			jQuery( croppie_dom )
				.croppie( 'result', {
					type: 'rawcanvas',
					// size: { width: 300, height: 300 },
					size: 'original',
					format: 'png',
				} )
				.then( function ( canvas ) {
					const image_url = canvas.toDataURL();
					//console.log(image_url);
					// remove first
					jQuery(
						`input[name="ppom[fields][${ field_name }][${ image_id }][cropped]"]`
					).remove();

					// Add file check
					jQuery(
						'<input checked="checked" name="ppom[fields][' +
							field_name +
							'][' +
							image_id +
							'][cropped]" type="checkbox"/>'
					)
						.val( image_url )
						.css( 'display', 'none' )
						.appendTo( file_list_preview_containers[ field_name ] );
				} );
		} );
}

/**
 * Scale Croppie boundary/viewport when the field container is narrower than
 * configured dimensions (responsive cropper).
 *
 * @param {Object} baseOptions Croppie options object for the field.
 * @param {number} max_width  Container width in pixels.
 * @return {Object} Options safe to pass to .croppie() without mutating globals.
 */
function get_responsive_croppie_options( baseOptions, max_width ) {
	const boundary = baseOptions.boundary || {};

	const boundaryWidthOriginal = Number( boundary.width );
	const boundaryHeightOriginal = Number( boundary.height );
	if (
		! Number.isFinite( boundaryWidthOriginal ) ||
		! Number.isFinite( boundaryHeightOriginal ) ||
		boundaryWidthOriginal <= 0 ||
		boundaryHeightOriginal <= 0
	) {
		return baseOptions;
	}
	if ( max_width >= boundaryWidthOriginal ) {
		return baseOptions;
	}
	if ( ! Number.isFinite( max_width ) ) {
		return baseOptions;
	}
	const aspectRatio = boundaryHeightOriginal / boundaryWidthOriginal || 1;
	const boundaryWidth = Math.floor( max_width );
	const boundaryHeight = Math.floor( boundaryWidth * aspectRatio );

	const result = {
		...baseOptions,
		boundary: {
			...baseOptions.boundary,
			width: boundaryWidth,
			height: boundaryHeight,
		},
	};

	if (
		baseOptions.viewport &&
		baseOptions.viewport.width &&
		baseOptions.viewport.height
	) {
		const scale = boundaryWidth / boundaryWidthOriginal;
		const viewportWidth = Math.floor( baseOptions.viewport.width * scale );
		const viewportHeight = Math.floor( baseOptions.viewport.height * scale );

		result.viewport = {
			...baseOptions.viewport,
			width: Math.min( viewportWidth, boundaryWidth - 2 ),
			height: Math.min( viewportHeight, boundaryHeight - 2 ),
		};
	}

	return result;
}
