<?php

namespace ProcessWire;

/**
 * PWCommerce: InputfieldPWCommerceShippingRate
 *
 * Inputfield for FieldtypePWCommerceShippingRate, the field that stores and outputs values of a PWCommerce shipping rate.
 *
 * @author Francis Otieno (Kongondo) <kongondo@gmail.com> kongondo.com
 *
 *
 *
 * InputfieldPWCommerceShippingRate for PWCommerce
 * Copyright (C) 2025 by Francis Otieno
 * MIT License
 *
 */

class InputfieldPWCommerceShippingRate extends Inputfield
{

	public static function getModuleInfo() {
		return array(
			'title' => 'PWCommerce Product Shipping Rate: Inputfield',
			'author' => 'Francis Otieno (Kongondo)',
			'version' => "100",
			'href' => 'https://kongondo.com',
			'summary' => 'GUI for the field that stores a PWCommerce shipping rate values.',
			'requires' => 'FieldtypePWCommerceShippingRate',
		);
	}

	protected $page;
	protected $field;

	// -----
	private $shopCurrencySymbolString = "";

	public function init() {
		parent::init();
		// if we want this modules css and js classes to be autoloaded
		// Any modules that extend: Inputfield, Process or ModuleJS will auto-load their CSS/JS files if they have the same name as the module and appear in the same directory. However, in order for that to work, their init() method has to be called. So if your module extends one of those, and has an init() method, then make sure to call the parent init() method:



	}

	public function setPage(Page $page) {
		$this->page = $page;
	}

	public function setField(Field $field) {
		$this->field = $field;
	}

	/**
	 * Render the entire input area for shipping rate
	 *
	 */
	public function ___render() {

		// NORMAL NON-AJAX/SAVED OUTPUT FOR SAVED VALUES
		// @note: we use classes for shared styles but unique ID for htmx here since this field will be used multiple times on the same page since shipping zones can have multiple rates.
		$out =
			"<div id='pwcommerce_shipping_rate_wrapper{$this->page->id}' class='pwcommerce_shipping_rates_wrapper'>" . $this->buildForm() . "</div>";
		return $out;
	}

	/**
	 * Called before render() or renderValue() method by InputfieldWrapper, before Inputfield-specific CSS/JS files added
	 *
	 * @param Inputfield|InputfieldWrapper|null The parent Inputfield/wrapper that is rendering it or null if no parent.
	 * @param bool $renderValueMode Whether renderValueMode will be used.
	 * @return bool
	 *
	 */
	public function renderReady(Inputfield $parent = null, $renderValueMode = false) {
		$this->preloadInputfieldAssets();
		// $scripts = $this->config->js($this->id, $options);
		// if currency locale set..
		// grab symbol; we use on price fields description
		$shopCurrencySymbolString = $this->pwcommerce->renderShopCurrencySymbolString();
		if (strlen($shopCurrencySymbolString)) {
			$this->shopCurrencySymbolString = " " . $shopCurrencySymbolString;
		}
		// -------------
		return parent::renderReady($parent, $renderValueMode);
	}

	protected function renderAddNewLink($pageID, $name) {
		// @note: $name and $pageID here are provided by the requesting method, e.g. runtime markup module
		$adminEditURL = $this->wire('config')->urls->admin . "page/edit/";
		$adminEdit = "{$adminEditURL}?id={$pageID}&field={$name}&context=new_item";
		// TODO: @NOTE: TESTING THE CLASS 'pwcommerce_reload_inputfield_runtimemarkup_list' to trigger a reload of the inputfields in newly inserted fieldset by runtimemarkup

		/*
															The a.classes explainer
															- pwcommerce_reload_inputfield_runtimemarkup_list: signals to InputfieldPWCommerceRuntimeMarkup that inputfields will need to be reloaded since new item inserted and the JS will need to catch on, e.g. RTE, etc.
															- pwcommerce_run_after_settle_operations: tells InputfieldPWCommerceRuntimeMarkup that htmx-after-settle operations will need to be run.
															- pwcommerce_open_newly_created_inputfieldset: tells InputfieldPWCommerceRuntimeMarkup the specific after-settle action to take.
															- pwcommerce_focus_input_in_newly_created_inputfield: tells InputfieldPWCommerceRuntimeMarkup to focus the InputfieldPageTitle input after new attribute option is added
															*/

		//--------
		$out =
			"<div id='pwcommerce_shipping_rate_add_new_wrapper' class='pwcommerce_add_new_wrapper'>" .
			"<a id='pwcommerce_shipping_rate_add_new' class='pwcommerce_reload_inputfield_runtimemarkup_list pwcommerce_run_after_settle_operations pwcommerce_open_newly_created_inputfieldset pwcommerce_focus_input_in_newly_created_inputfield pwcommerce_run_request_indicators_operations' href='#' hx-get='{$adminEdit}' hx-target='#wrap_Inputfield_pwcommerce_runtime_markup > div.InputfieldContent > ul.Inputfields:first-child' hx-swap='beforeend' hx-indicator='#pwcommerce_add_new_shipping_rate_spinner_indicator{$pageID}'>" .
			"<i id='pwcommerce_add_new_shipping_rate_spinner_indicator{$pageID}' class='pwcommerce_add_new_shipping_rate_spinner_indicator pwcommerce_add_new_item_spinner_indicator pwcommerce_spinner_indicator fa fa-fw fa-plus-circle'></i>" .
			$this->_("Add new shipping rate") .
			"</a>" .
			"</div>";
		return $out;
	}

	/**
	 * Render markup for the 'footer' of the markup when used in InputfieldPWCommerceRuntimeMarkup.
	 *
	 * @access private
	 * @param integer $pageID The ID of the page whose footer we are building.
	 * @param string $name The name to use for the InputfieldWrapper to return.
	 * @return InputfieldWrapper $wrapper The built wrapper.
	 */
	private function renderFooter($pageID, $name) {


		//------------------- add new shipping rate (InputfieldMarkup)
		// @note: SINGLE ADD NEW IN FOOTER OF WRAPPER - CAN ONLY HAVE ONE!
		// TODO: WILL PROBABLY MOVE TO RUNTIME MARKUP SO WE HAVE ONLY ONE ON THE PAGE!

		$wrapper = $this->pwcommerce->getInputfieldWrapper();

		// save parent page (shipping zone) of the shipping rates created here
		$options = [
			'id' => "pwcommerce_shipping_rate_parent_page_id{$pageID}",
			'name' => 'pwcommerce_shipping_rate_parent_page_id',
			'value' => $pageID, // store the parent ID of the new/incoming shipping rate [new Page()]
		];

		$field = $this->pwcommerce->getInputfieldHidden($options);
		$wrapper->add($field);

		// -------------

		$options = [
			'skipLabel' => Inputfield::skipLabelHeader,
			'collapsed' => Inputfield::collapsedNever,
			'wrapClass' => true,
			'classes' => 'pwcommerce_shipping_rate_add_new',
			'wrapper_classes' => 'pwcommerce_no_outline',
			'value' => $this->renderAddNewLink($pageID, $name),
		];

		$field = $this->pwcommerce->getInputfieldMarkup($options);

		$wrapper->add($field);
		// @note: return unrendered wrapper
		return $wrapper;
	}

	private function preloadInputfieldAssets() {
		// TODO: DELETE WHEN DONE IF NOT IN USE
	}

	private function buildForm() {

		/** @var WireData $value */
		$value = $this->attr('value');

		$pageID = $this->page->id;

		// GET WRAPPER FOR ALL INPUTFIELDS HERE
		$wrapper = $this->pwcommerce->getInputfieldWrapper();

		// @note: we need page->id suffixes to id and names of inputs since this field will be used multiple times on the same page in case a shipping zone has multiple rates (child pages).

		//------------------- rate/cost/price/shippingRate (getInputfieldText)
		$description = $this->_('Shipping amount to charge for this rate');
		// append currency symbol string if available
		$description .= $this->shopCurrencySymbolString . '.';

		$options = [
			'id' => "pwcommerce_shipping_rate_rate{$pageID}",
			'name' => "pwcommerce_shipping_rate_rate{$pageID}",
			'type' => 'number',
			'step' => '0.01',
			'min' => 0,
			'label' => $this->_('Charge'),
			// TODO: Rate? Cost?
			'description' => $description,
			'collapsed' => Inputfield::collapsedNever,
			'wrapClass' => true,
			'wrapper_classes' => 'pwcommerce_no_outline',
			// 'value' => $value->shippingRate,
			// @note: server-side locale-aware value converted to properly render in HTML5 input of type number
			'value' => $this->pwcommerce->localeConvertValue($value->shippingRate)
		];

		$field = $this->pwcommerce->getInputfieldText($options);
		$wrapper->add($field);

		//------------------- shipping rate criteria/conditions header markup (getInputfieldMarkup)
		$description = $this->_('Conditions');
		$kg = $this->_('kg');
		// -----------
		// markup to target symbols for toggle show depending on handling fee type
		// symbols are percentage (%) and currency, e.g. €
		// toggle classes
		$shippingRateBasedOnWeightClass = $value->shippingRateCriteriaType === 'weight' ? '' :
			" pwcommerce_hide";
		$shippingRateBasedOnPriceClass = $value->shippingRateCriteriaType === 'price' ? '' : " pwcommerce_hide";

		// weight
		$description .= "<span class='pwcommerce_shipping_rate_criteria_type_weight{$shippingRateBasedOnWeightClass}'> ({$kg})</span>";
		// price
		$description .= "<span class='pwcommerce_shipping_rate_criteria_type_price{$shippingRateBasedOnPriceClass}'>{$this->shopCurrencySymbolString}</span>";


		$description .= ".";
		// ------

		$options = [
			'skipLabel' => Inputfield::skipLabelHeader,
			'label' => $this->_('Shipping Time'),
			'collapsed' => Inputfield::collapsedNever,
			'classes' => 'pwcommerce_shipping_rate_criteria_header',
			'wrapClass' => true,
			'wrapper_classes' => 'pwcommerce_no_outline',
			// 'value' => $this->_('Conditions'),
			'description' => $description,

		];

		$field = $this->pwcommerce->getInputfieldMarkup($options);
		// allow HTML in description
		$field->entityEncodeText = false;
		$wrapper->add($field);

		//------------------- shipping_rate_criteria_type (InputfieldSelect)

		$selectOptionsShippingRateCriteriaType = [
			'none' => __('None'),
			'weight' => __('Weight'),
			'price' => __('Price'),
			'quantity' => __('Quantity'),
		];

		$columnWidth = 33;

		$options = [
			'id' => "pwcommerce_shipping_rate_criteria_type{$pageID}",
			'name' => "pwcommerce_shipping_rate_criteria_type{$pageID}",
			'label' => $this->_('Rate Based on'),
			'collapsed' => Inputfield::collapsedNever,
			'columnWidth' => $columnWidth,
			// 33
			'select_options' => $selectOptionsShippingRateCriteriaType,
			'wrapClass' => true,
			'wrapper_classes' => 'pwcommerce_no_outline',
			'classes' => 'pwcommerce_shipping_rate_criteria_type',
			'value' => empty($value->shippingRateCriteriaType) ? 'none' : $value->shippingRateCriteriaType,
		];

		$field = $this->pwcommerce->getInputfieldSelect($options);
		$wrapper->add($field);

		//------------------- shipping_rate_criteria_minimum (getInputfieldText)

		$criteriaMinMaxStep = $value->shippingRateCriteriaType === 'quantity' ? 1 : 0.01;

		$options = [
			'id' => "pwcommerce_shipping_rate_criteria_minimum{$pageID}",
			'name' => "pwcommerce_shipping_rate_criteria_minimum{$pageID}",
			'type' => 'number',
			'step' => $criteriaMinMaxStep,
			'min' => 0,
			'label' => $this->_('Minimum'),
			// TODO: Rate? Cost?
			'collapsed' => Inputfield::collapsedNever,
			'columnWidth' => $columnWidth,
			// 33
			'classes' => 'pwcommerce_shipping_rate_criteria_min_max',
			'wrapClass' => true,
			'wrapper_classes' => 'pwcommerce_no_outline',
			'show_if' => "pwcommerce_shipping_rate_criteria_type{$pageID}!=none",
			// 'value' => $value->shippingRateCriteriaMinimum,
			// @note: server-side locale-aware value converted to properly render in HTML5 input of type number
			'value' => $this->pwcommerce->localeConvertValue($value->shippingRateCriteriaMinimum)
		];

		$field = $this->pwcommerce->getInputfieldText($options);
		$wrapper->add($field);

		//------------------- shipping_rate_criteria_maximum (getInputfieldText)

		$options = [
			'id' => "pwcommerce_shipping_rate_criteria_maximum{$pageID}",
			'name' => "pwcommerce_shipping_rate_criteria_maximum{$pageID}",
			'type' => 'number',
			'step' => $criteriaMinMaxStep,
			'min' => 0,
			'label' => $this->_('Maximum'),
			// TODO: Rate? Cost?
			'collapsed' => Inputfield::collapsedNever,
			'columnWidth' => $columnWidth,
			// 33
			'classes' => 'pwcommerce_shipping_rate_criteria_min_max',
			'wrapClass' => true,
			'wrapper_classes' => 'pwcommerce_no_outline',
			'show_if' => "pwcommerce_shipping_rate_criteria_type{$pageID}!=none",
			// 'value' => $value->shippingRateCriteriaMaximum,
			// @note: server-side locale-aware value converted to properly render in HTML5 input of type number
			'value' => $this->pwcommerce->localeConvertValue($value->shippingRateCriteriaMaximum)
		];

		$field = $this->pwcommerce->getInputfieldText($options);
		$wrapper->add($field);

		//------------------- shipping rate delivery times header markup (getInputfieldMarkup)

		$options = [
			'skipLabel' => Inputfield::skipLabelHeader,
			'label' => $this->_('Shipping Time'),
			'collapsed' => Inputfield::collapsedNever,
			'classes' => 'pwcommerce_shipping_rate_delivery_times_header',
			'wrapClass' => true,
			'wrapper_classes' => 'pwcommerce_no_outline',
			// 'value' => $this->renderAddNewLink(),
			//    'value' => $this->_('Estimated Shipping Times.'),
			'description' => $this->_('Estimated Shipping Times.'),

		];

		$field = $this->pwcommerce->getInputfieldMarkup($options);
		$wrapper->add($field);

		//------------------- shipping_rate_delivery_time_minimum_days (getInputfieldText)

		$options = [
			'id' => "pwcommerce_shipping_rate_delivery_time_minimum_days{$pageID}",
			'name' => "pwcommerce_shipping_rate_delivery_time_minimum_days{$pageID}",
			'type' => 'number',
			'step' => '1',
			'min' => 0,
			// TODO: OK WITH MINIMUM 0 DAY? For now yes, minimum 1 causes JS issues since if value not saved, DB will sanitize to 0; If we have min=1, we then get invalid form control
			'label' => $this->_('Minimum Days'),
			'collapsed' => Inputfield::collapsedNever,
			'columnWidth' => 50,
			'wrapClass' => true,
			'wrapper_classes' => 'pwcommerce_no_outline',
			'value' => $value->shippingRateDeliveryTimeMinimumDays,
		];

		$field = $this->pwcommerce->getInputfieldText($options);
		$wrapper->add($field);

		//------------------- shipping_rate_delivery_time_maximum_days (getInputfieldText)

		$options = [
			'id' => "pwcommerce_shipping_rate_delivery_time_maximum_days{$pageID}",
			'name' => "pwcommerce_shipping_rate_delivery_time_maximum_days{$pageID}",
			'type' => 'number',
			'step' => '1',
			'min' => 0,
			// TODO: OK WITH MINIMUM 0 DAY? For now yes, minimum 1 causes JS issues since if value not saved, DB will sanitize to 0; If we have min=1, we then get invalid form control
			'label' => $this->_('Maximum Days'),
			'collapsed' => Inputfield::collapsedNever,
			'columnWidth' => 50,
			'wrapClass' => true,
			'wrapper_classes' => 'pwcommerce_no_outline',
			'value' => $value->shippingRateDeliveryTimeMaximumDays,
		];

		$field = $this->pwcommerce->getInputfieldText($options);
		$wrapper->add($field);

		//----------------------

		$out = $wrapper->render();

		return $out;
	}

	// extra content to be  to InputfieldPWCommerceRuntimeMarkup with respect to this field
	// @note: TODO: we MIGHT still handle any JS interactions here!
	public function getAppendContent($page, $name) {
		return $this->renderFooter($page->id, $name);
	}

	// extra content to be added as assets to InputfieldPWCommerceRuntimeMarkup with respect to this field
	// @note: TODO: we MIGHT still handle any JS interactions here!
	// TODO: DELETE METHOD IF NO LONGER NEEDED AS SCRIPT IS ADDED VIA PROCESSPWCOMMERCE!
	public function getPreloadAssetsContent() {
		// TODO: conditionally add below if in SHOP CONTEXT ONLY! I.E., WE NEED TO BE IN PROCESS EDIT MODULE! OR DON'T ADD BELOW AT ALL? SINCE WE NOW HAVE HTMX ADDED VIA PROCESS MODULE? OTHERWISE WE GET ERRORS IN JS WHEN EDITING THE PAGE NATURALLY
		// TODO - RELATED TO ABOVE, DO WE SHOW WARNING TO SUPERUSER / USER IF THEY ARE EDITING A SHOP PAGE OUTSIDE THE SHOP CONTEXT? I.E., NOT ALL FEATURES AVAILABLE OR DISALBE THEM? DISABLING MAYBE IN THE FUTURE? BUT MIGHT CONFUSE IF NO WARNING?
		return;
		$url = $this->wire('config')->urls->ProcessPWCommerce;
		return [
			['source' => "{$url}vendors/scripts/htmx/htmx.1.7.0.min.js"],
		];
	}

	/**
	 * For InputfieldPWCommerceRuntimeMarkup.
	 *
	 * For when new Shipping Rate is requested by a shipping zone in edit.
	 * Return a new blank page of this type that is ready for editing and saving.
	 *
	 * @return Page $newPage The new blank item.
	 */
	public function getBlankItem() {
		$newPage = new Page();
		$template = $this->wire('templates')->get('pwcommerce-shipping-rate');
		$newPage->template = $template;
		$newPage->title = $this->_('New Unsaved Shipping Rate');
		// @note: add a temporary ID to track new pages for this context (e.g. a new shipping rate)
		$newPage->id = str_replace('.', '-', microtime(true));
		return $newPage;
	}

	// ~~~~~~~~~~~~~~

	/**
	 * Process input for the values sent from the shipping rate for this page
	 *
	 */
	public function ___processInput(WireInputData $input) {

		// **** @NOTE: @UPDATE TODO? THIS IS OK SINCE THIS IS A CUSTOM INPUTFIELD FOR A VERY SPECIFIC NEED! PWCOMMERCE! ****
		// @note: this is now called once from inside InputfieldPWCommerceRuntimeMarkup::processInput!
		// SAVE NEW ITEMS FIRST
		// @note: these were added as empty items via ajax
		// we need to create and save their pages first!
		// $newItems = $input->pwcommerce_is_new_item;
		// if (!empty($newItems)) {
		//   // $this->processInputCreateNewItems($input);
		// }

		// @note -ditto-
		// $deleteItems = $input->pwcommerce_is_delete_item;
		// if (!empty($deleteItems)) {
		//   $this->processInputDeleteItems($input);
		// }

		//-----------------
		// SAVE RATE VALUES FOR EXISTING PAGES

		$pageID = $this->page->id;

		$rate = $this->field->type->getBlankValue($this->page, $this->field);

		// @note: we have page->id suffixes to id and names of inputs since this field will be used multiple times on the same page in case a product has variants.

		// process values
		$rate->shippingRate = (float) $input->{"pwcommerce_shipping_rate_rate{$pageID}"};

		$rate->shippingRateCriteriaType = $this->wire('sanitizer')->pageName($input->{"pwcommerce_shipping_rate_criteria_type{$pageID}"});

		$rate->shippingRateCriteriaMinimum = (float) $input->{"pwcommerce_shipping_rate_criteria_minimum{$pageID}"};
		$rate->shippingRateCriteriaMaximum = (float) $input->{"pwcommerce_shipping_rate_criteria_maximum{$pageID}"};

		$rate->shippingRateDeliveryTimeMinimumDays = (int) $input->{"pwcommerce_shipping_rate_delivery_time_minimum_days{$pageID}"};
		$rate->shippingRateDeliveryTimeMaximumDays = (int) $input->{"pwcommerce_shipping_rate_delivery_time_maximum_days{$pageID}"};

		// if the string value of the processed shipping rate is different from the previous,
		// then flag this Inputfield as changed
		// so that it will be automatically saved with the page
		// @note: we compare using an in-house toString() private method as we don't implement toString() in the field.
		if ($this->toStringInhouse($rate) !== $this->toStringInhouse($this->value)) {
			$this->attr('value', $rate);
			$this->trackChange('value');
		}
	}

	public function processInputCreateNewItems(WireInputData $input) {

		// @note: inputs named differently since have temp/empty id of page!
		$newShippingRateParentID = (int) $input->pwcommerce_shipping_rate_parent_page_id;
		$parent = $this->wire('pages')->get("id=${newShippingRateParentID}");

		// we found parent page (shipping zone)
		if ($parent) {
			$newItems = $input->pwcommerce_is_new_item;
			$languages = $this->wire('languages');
			$sanitizer = $this->wire('sanitizer');
			$template = $this->wire('templates')->get('pwcommerce-shipping-rate');
			//------------

			// @NOTE: if this method is called from outside this class, we don't have a $this->name, $this->field or $this->page
			// if the field was called, e.g. inside InputfieldRuntimeMarkup, get the field name of shipping rate field without suffixes
			$fieldName = $this->name() ? preg_replace('/_repeater\d+$/', '', $this->name) : 'pwcommerce_shipping_rate';

			// ----------
			foreach ($newItems as $temporaryIDAsSuffix) {
				// prepare titles and name + will help check if identical exists
				// @note: our title and description are suffixed with 'repeaterxxxx'
				$title = $sanitizer->text($input->{"title_repeater{$temporaryIDAsSuffix}"});
				$name = $sanitizer->pageName($title, true);

				// first check if page already exists (under this parent)
				$pageIDExists = $this->wire('pages')->getRaw("parent_id={$parent->id},name=$name", 'id');
				if (!empty($pageIDExists)) {
					// CHILD PAGE (SHIPPING RATE) ALREADY EXISTS!
					continue;
				}

				// good to go

				// CREATE NEW SHIPPING RATE FOR THIS SHIPPING ZONE
				//------------
				$p = new Page();
				$p->template = $template;
				$p->parent = $parent;
				$p->title = $title;
				$p->name = $name;
				// description
				$p->pwcommerce_description = $sanitizer->purify($input->{"pwcommerce_description_repeater{$temporaryIDAsSuffix}"});

				// add other languages
				if ($languages) {
					foreach ($languages as $language) {
						// skip default language as already set above
						if ($language->name == 'default') {
							continue;
						}
						// language title
						$languageTitle = $sanitizer->text($input->{"title_repeater{$temporaryIDAsSuffix}__{$language->id}"});
						$p->title->setLanguageValue($language, $languageTitle);
						// TODO: set name too?
						// language description
						$languageDescription = $sanitizer->purify($input->{"pwcommerce_description_repeater{$temporaryIDAsSuffix}__{$language->id}"});
						$p->pwcommerce_description->setLanguageValue($language, $languageDescription);

						// ++++++++++++
						// set shipping rate page as active in other languages
						$p->set("status$language", 1);
					}
				}

				//--------------
				// process rate values
				//----------
				// save shipping-rate fields themselves
				// since inputs are for the temporary pages, we need to do it here
				// TODO: BELOW, WE DON'T WANT TO SAVE THESE AGAIN! OK HERE?

				// --------------
				// @NOTE: if this method is called from outside this class, we don't have a $this->field or $this->page; hence, we create a new blank value ourselves. In which case, we just create a blank item ourselves; it's just a blank WireData!
				// $newRate = $this->field->type->getBlankValue($this->page, $this->field);
				$newRate = $this->field ? $this->field->type->getBlankValue($this->page, $this->field) : new WireData();

				// -------------
				$newRate->shippingRate = (float) $input->{"pwcommerce_shipping_rate_rate{$temporaryIDAsSuffix}"};

				$newRate->shippingRateCriteriaType = $this->wire('sanitizer')->pageName($input->{"pwcommerce_shipping_rate_criteria_type{$temporaryIDAsSuffix}"});

				$newRate->shippingRateCriteriaMinimum = (float) $input->{"pwcommerce_shipping_rate_criteria_minimum{$temporaryIDAsSuffix}"};
				$newRate->shippingRateCriteriaMaximum = (float) $input->{"pwcommerce_shipping_rate_criteria_maximum{$temporaryIDAsSuffix}"};

				$newRate->shippingRateDeliveryTimeMinimumDays = (int) $input->{"pwcommerce_shipping_rate_delivery_time_minimum_days{$temporaryIDAsSuffix}"};
				$newRate->shippingRateDeliveryTimeMaximumDays = (int) $input->{"pwcommerce_shipping_rate_delivery_time_maximum_days{$temporaryIDAsSuffix}"};

				//  $p->setAndSave([
				//   'pwcommerce_description' => $description,
				//   $fieldName => $newRate,
				//  ]);
				// set value to shipping rate field
				$p->set($fieldName, $newRate);

				//------------------
				// SAVE the new shipping rate page
				$p->save();
			}
			// end loop
		}
	}

	public function processInputDeleteItems(WireInputData $input) {
		$deleteItems = $input->pwcommerce_is_delete_item;
		// page IDs are in one hidden inputfield; get the first array item
		$deleteRatesIDsCSV = $deleteItems[0]; // csv string of IDs
		$deleteRatesIDsArray = $this->wire('sanitizer')->intArray($deleteRatesIDsCSV);
		if (!empty($deleteRatesIDsArray)) {
			$deleteRatesIDs = implode('|', $deleteRatesIDsArray);
			//-------------
			$pages = $this->wire('pages');
			$rates = $pages->find("id={$deleteRatesIDs}");

			// ---------
			// TRASH each rate page

			$notDeletedRatesTitles = [];
			$deletedRatesTitles = [];
			foreach ($rates as $rate) {
				// locked for edits
				if ($rate->isLocked()) {
					$notDeletedRatesTitles[] = $rate->title;
					continue;
				}
				$pages->trash($rate);
				// successfully trashed
				if ($rate->isTrash()) {
					$deletedRatesTitles[] = $rate->title;
				}
			}
			// ------
			// NOTICES
			// success
			if (!empty($deletedRatesTitles)) {
				$this->message(sprintf(__("Deleted these rates: %s."), implode(', ', $deletedRatesTitles)));
			}
			// error
			if (!empty($notDeletedRatesTitles)) {
				$this->warning(sprintf(__("Could not delete these rates: %s."), implode(', ', $notDeletedRatesTitles)));
			}
		}
	}

	/**
	 * Make a string value to represent the shipping fee settings values that can be used for comparison purposes.
	 *
	 * @note: this is only for internal use since we don't have a __toString() method.
	 * @return string
	 *
	 */
	private function toStringInhouse($item) {
		$string = (string) "$item->shippingRate: $item->shippingRateCriteriaType: $item->shippingRateCriteriaMinimum: $item->shippingRateCriteriaMaximum: $item->shippingRateDeliveryTimeMinimumDays: $item->shippingRateDeliveryTimeMaximumDays";
		return $string;
	}
}