<?php

/**
 * The admin-specific functionality of the plugin.
 *
 * @link       #
 * @since      1.0.0
 *
 * @package    Esraw
 * @subpackage Esraw/admin
 */

namespace EasyShippingRate\Admin;

use EasyShippingRate\ShippingMethod;
use EasyShippingRate\Notifications;
use function EasyShippingRate\Support\get_user_roles;
use function EasyShippingRate\Support\get_shipping_list_for_export;
use function EasyShippingRate\Support\get_shipping_zones_list_for_import;
use function EasyShippingRate\Support\is_premium;

/**
 * The admin-specific functionality of the plugin.
 *
 * @package    Esraw
 * @subpackage Esraw/admin
 */
class Admin {

	/**
	 * Master switch for the per-row inline delete feature. Off until the
	 * donation flow is debugged; flip to true to re-enable everything.
	 */
	const INLINE_DELETE_ENABLED = false;

	/**
	 * Per-row inline delete is free for this many uses, then a donation is asked.
	 */
	const INLINE_DELETE_FREE_LIMIT = 1;
	const INLINE_DELETE_OPTION     = 'esraw_inline_delete_uses';

	/**
	 * Where the donation notice sends the user.
	 */
	const DONATE_URL = 'https://www.buymeacoffee.com/azouamauriac';

	/**
	 * @since    1.0.0
	 * @access   private
	 * @var      string
	 */
	private $plugin_name;

	/**
	 * @since    1.0.0
	 * @access   private
	 * @var      string
	 */
	private $version;

	/**
	 * @since    1.0.0
	 * @param    string $plugin_name
	 * @param    string $version
	 */
	public function __construct( $plugin_name, $version ) {
		$this->plugin_name = $plugin_name;
		$this->version     = $version;
	}

	/**
	 * Register the stylesheets for the admin area.
	 *
	 * @param string $hook_suffix Current admin page.
	 */
	public function enqueue_styles( $hook_suffix ) {
		if ( ! $this->is_esraw_admin_screen( $hook_suffix ) ) {
			return;
		}

		wp_enqueue_style( $this->plugin_name, ESRAW_URL . 'src/Admin/css/rsw-admin.css', array(), $this->version, 'all' );
		// WooCommerce ships the select2 styles, so we don't bundle our own.
		wp_enqueue_style( 'woocommerce_admin_styles' );
		// The settings UI uses prefixed Tailwind utilities (warnings, notices, labels),
		// so the compiled stylesheet must load here, not only with the review notice.
		wp_enqueue_style( $this->plugin_name . '-tailwind', ESRAW_URL . 'src/Admin/css/tailwind.build.css', array(), $this->version, 'all' );
	}

	/**
	 * Register the JavaScript for the admin area.
	 *
	 * @param string $hook_suffix Current admin page.
	 */
	public function enqueue_scripts( $hook_suffix ) {
		if ( ! $this->is_esraw_admin_screen( $hook_suffix ) ) {
			return;
		}

		// Depend on WooCommerce's bundled selectWoo rather than shipping a duplicate select2.
		// wp-hooks is needed to unhook WooCommerce's marketplace suggestions on our method page.
		wp_enqueue_script( $this->plugin_name, ESRAW_URL . 'src/Admin/js/esraw-admin.js', array( 'jquery', 'selectWoo', 'wp-hooks' ), $this->version, false );

		$data = array(
			'esraw_condition_choices'  => ShippingMethod::CONDITION_CHOICES,
			'esraw_operator'           => ShippingMethod::OPERATOR,
			'esraw_condition_actions'  => ShippingMethod::CONDITIONS_ACTIONS,
			'esraw_currency_symbol'    => get_woocommerce_currency_symbol(),
			'esraw_ship_classes_array' => ShippingMethod::ship_classes_select_field(),
			'esraw_user_roles'         => get_user_roles(),
			'esraw_rule_templates'     => ShippingMethod::rule_templates(),
			// On our method's page, WooCommerce's own extension suggestions are hidden.
			'is_own_method_page'       => $this->is_own_method_instance_page(),
			// Product search uses WC's native AJAX endpoint — no full product list needed.
			'ajax_url'                 => admin_url( 'admin-ajax.php' ),
			'search_products_nonce'    => wp_create_nonce( 'search-products' ),
			'inline_delete'            => array(
				'enabled'    => self::INLINE_DELETE_ENABLED,
				'remaining'  => $this->inline_delete_remaining(),
				'donate_url' => self::DONATE_URL,
				'message'    => __( 'You have used your free row deletions. Please make a donation to support the project and keep using this feature.', 'easy-shipping-rate' ),
				'donate'     => __( 'Donate', 'easy-shipping-rate' ),
			),
		);
		wp_localize_script( $this->plugin_name, 'esr_vars', $data );
	}

	/**
	 * Free inline deletions left for this site. Premium installs are unlimited.
	 *
	 * @return int
	 */
	private function inline_delete_remaining() {
		if ( is_premium() ) {
			return PHP_INT_MAX;
		}
		$uses = (int) get_option( self::INLINE_DELETE_OPTION, 0 );
		return max( 0, self::INLINE_DELETE_FREE_LIMIT - $uses );
	}

	/**
	 * Server-side gate, enforced when rules are saved. Returns whether deleting
	 * this many rules is allowed; if so it charges them against the free quota.
	 * The client-side limit is only a hint — this is the real check.
	 *
	 * @param int $deleted Number of rules being removed in this save.
	 * @return bool
	 */
	public static function allow_rule_deletions( $deleted ) {
		if ( ! self::INLINE_DELETE_ENABLED || $deleted <= 0 || is_premium() ) {
			return true;
		}
		$uses      = (int) get_option( self::INLINE_DELETE_OPTION, 0 );
		$remaining = max( 0, self::INLINE_DELETE_FREE_LIMIT - $uses );
		if ( $deleted > $remaining ) {
			set_transient( 'esraw_delete_blocked', true, MINUTE_IN_SECONDS );
			return false;
		}
		update_option( self::INLINE_DELETE_OPTION, $uses + $deleted );
		return true;
	}

	/**
	 * Tell the user, after a save, that their deletions were blocked by the quota.
	 */
	public function maybe_show_delete_blocked_notice() {
		if ( ! get_transient( 'esraw_delete_blocked' ) ) {
			return;
		}
		delete_transient( 'esraw_delete_blocked' );
		?>
		<div class="notice notice-warning is-dismissible">
			<p>
				<?php esc_html_e( 'You have reached the free limit for deleting rules, so your deletions were not saved.', 'easy-shipping-rate' ); ?>
				<a href="<?php echo esc_url( self::DONATE_URL ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Make a donation to keep using this feature.', 'easy-shipping-rate' ); ?></a>
			</p>
		</div>
		<?php
	}

	/**
	 * On the plugin's own screens, hide admin notices coming from other plugins
	 * or themes so the merchant only sees messages relevant to what they are
	 * configuring. Runs just before WordPress prints the notices; every other
	 * admin page is left untouched.
	 */
	public function remove_foreign_admin_notices() {
		if ( ! $this->is_esraw_notice_scope() ) {
			return;
		}
		foreach ( array( 'admin_notices', 'all_admin_notices', 'network_admin_notices', 'user_admin_notices' ) as $hook ) {
			$this->remove_foreign_notice_callbacks( $hook );
		}
	}

	/**
	 * Only load our admin assets where they are used: the WooCommerce shipping
	 * settings and this plugin's own import/export pages.
	 *
	 * @param string $hook_suffix Current admin page.
	 * @return bool
	 */
	private function is_esraw_admin_screen( $hook_suffix ) {
		// WooCommerce settings (where the method rules UI lives) and our import/export pages.
		return 'woocommerce_page_wc-settings' === $hook_suffix
			|| false !== strpos( $hook_suffix, 'easy_shipping_rate' )
			|| false !== strpos( $hook_suffix, 'import-methods-esraw' );
	}

	/**
	 * Whether the current admin screen is one of the plugin's pages: the
	 * top-level settings page, the Import / Export submenu, or the WooCommerce
	 * shipping settings where the method rules are edited.
	 *
	 * @return bool
	 */
	private function is_esraw_plugin_screen() {
		$screen = get_current_screen();
		if ( ! $screen ) {
			return false;
		}
		return false !== strpos( $screen->id, 'easy_shipping_rate' )
			|| false !== strpos( $screen->id, 'easy-shipping-import-export' )
			|| 'woocommerce_page_wc-settings' === $screen->id;
	}

	/**
	 * Whether the review prompt should be displayed on the current request. Used
	 * both to render the notice and to decide whether to enqueue its stylesheet.
	 *
	 * @return bool
	 */
	private function should_show_review_notice() {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return false;
		}
		if ( ! $this->is_esraw_plugin_screen() ) {
			return false;
		}
		// Clicking "Leave a review" hides the prompt for good; only a fresh
		// install (which resets the flag) brings it back.
		if ( 'yes' === get_option( 'esraw_review_done' ) ) {
			return false;
		}
		// "No thanks" only snoozes the prompt for two weeks
		// (esraw_review_snooze_until), after which it reappears.
		$snooze_until = (int) get_option( 'esraw_review_snooze_until', 0 );
		if ( $snooze_until && time() < $snooze_until ) {
			return false;
		}
		return true;
	}

	/**
	 * Enqueue the compiled Tailwind stylesheet, but only where the review notice
	 * is actually rendered. Hooked on admin_enqueue_scripts so the styles land in
	 * the page <head> instead of being inlined.
	 */
	public function enqueue_notice_styles() {
		if ( ! $this->should_show_review_notice() ) {
			return;
		}

		wp_enqueue_style( $this->plugin_name . '-tailwind', ESRAW_URL . 'src/Admin/css/tailwind.build.css', array(), $this->version, 'all' );
	}

	/**
	 * Show the review prompt on every plugin screen. "No thanks" snoozes it for
	 * two weeks; "Leave a review" routes through our handler, which hides the
	 * prompt for good before sending the user to WordPress.org. Styled with the
	 * plugin's prefixed Tailwind utilities.
	 */
	public function maybe_show_review_notice() {
		if ( ! $this->should_show_review_notice() ) {
			return;
		}

		$review_url  = wp_nonce_url( add_query_arg( 'esraw_review_action', 'review' ), 'esraw-review-prompt' );
		$dismiss_url = wp_nonce_url( add_query_arg( 'esraw_review_action', 'dismiss' ), 'esraw-review-prompt' );
		?>
		<div class="notice esraw-flex esraw-items-center esraw-gap-5 esraw-border-l-4 esraw-border-l-brand esraw-p-5">
			<div class="esraw-flex esraw-h-12 esraw-w-12 esraw-shrink-0 esraw-items-center esraw-justify-center esraw-rounded-full esraw-bg-brand">
				<span class="dashicons dashicons-heart esraw-text-white" aria-hidden="true"></span>
			</div>
			<div class="esraw-min-w-0 esraw-flex-1">
				<div class="esraw-mb-2 esraw-text-xl esraw-leading-none esraw-tracking-widest esraw-text-star" aria-hidden="true">&#9733;&#9733;&#9733;&#9733;&#9733;</div>
				<h2 class="esraw-m-0 esraw-mb-1 esraw-p-0 esraw-text-lg esraw-font-bold esraw-text-gray-900">
					<?php esc_html_e( 'Loving Easy Shipping Rate? Help us with a 5-star review!', 'easy-shipping-rate' ); ?>
				</h2>
				<p class="esraw-m-0 esraw-mb-4 esraw-max-w-3xl esraw-p-0 esraw-text-sm esraw-leading-relaxed esraw-text-gray-700">
					<?php esc_html_e( 'It takes less than a minute and makes a huge difference — your review helps other store owners discover the plugin and motivates us to keep improving it. Thank you so much!', 'easy-shipping-rate' ); ?>
				</p>
				<div class="esraw-flex esraw-flex-wrap esraw-items-center esraw-gap-4">
					<a href="<?php echo esc_url( $review_url ); ?>" class="esraw-inline-flex esraw-items-center esraw-gap-2 esraw-rounded esraw-bg-brand esraw-px-5 esraw-py-3 esraw-text-sm esraw-font-semibold esraw-text-white esraw-no-underline esraw-shadow hover:esraw-bg-brand-dark" target="_blank" rel="noopener noreferrer">
						<span class="dashicons dashicons-star-filled esraw-text-star-soft" aria-hidden="true"></span>
						<?php esc_html_e( 'Leave a 5-star review', 'easy-shipping-rate' ); ?>
					</a>
					<a href="<?php echo esc_url( $dismiss_url ); ?>" class="esraw-text-sm esraw-text-gray-500 esraw-no-underline hover:esraw-text-gray-700"><?php esc_html_e( 'No thanks', 'easy-shipping-rate' ); ?></a>
				</div>
			</div>
		</div>
		<?php
	}

	/**
	 * Handle the review prompt buttons. "No thanks" snoozes the prompt for two
	 * weeks; "Leave a review" hides it for good (esraw_review_done) and forwards
	 * the user to WordPress.org.
	 */
	public function handle_review_prompt_actions() {
		if ( ! isset( $_GET['esraw_review_action'] ) ) {
			return;
		}
		check_admin_referer( 'esraw-review-prompt' );
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}

		$action = sanitize_key( wp_unslash( $_GET['esraw_review_action'] ) );

		if ( 'review' === $action ) {
			update_option( 'esraw_review_done', 'yes' );
			wp_redirect( 'https://wordpress.org/support/plugin/easy-shipping-rate/reviews/?filter=5#new-post' );
			exit;
		}

		if ( 'dismiss' === $action ) {
			update_option( 'esraw_review_snooze_until', time() + 2 * WEEK_IN_SECONDS );
		}

		wp_safe_redirect( remove_query_arg( array( 'esraw_review_action', '_wpnonce' ) ) );
		exit;
	}

	/**
	 * Initialize the shipping method class.
	 */
	public function init_shipping_method() {
		new ShippingMethod();
	}

	/**
	 * Register the shipping method with WooCommerce.
	 *
	 * @param array $methods
	 * @return array
	 */
	public function add_easy_rate_shipping_method( $methods ) {
		$methods[ ShippingMethod::METHOD_ID ] = ShippingMethod::class;
		return $methods;
	}

	/**
	 * Register the two plugin admin pages:
	 *   - Top-level: plugin settings (Hide method, Delete data on uninstall).
	 *   - Submenu:   Import / Export.
	 */
	public function add_admin_menu() {
		add_menu_page(
			__( 'Easy Shipping', 'easy-shipping-rate' ),
			__( 'Easy Shipping', 'easy-shipping-rate' ),
			'manage_woocommerce',
			'easy_shipping_rate',
			array( $this, 'settings_page' ),
			'dashicons-car',
			56
		);
		add_submenu_page(
			'easy_shipping_rate',
			__( 'Import / Export', 'easy-shipping-rate' ),
			__( 'Import / Export', 'easy-shipping-rate' ),
			'manage_woocommerce',
			'easy-shipping-import-export',
			array( $this, 'import_export_page' )
		);
	}

	/**
	 * Render the plugin settings page and handle form saves.
	 */
	public function settings_page() {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}

		$method = new ShippingMethod();
		$saved  = false;

		if ( isset( $_POST['esraw_settings_nonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_POST['esraw_settings_nonce'] ) ), 'esraw-save-settings' ) ) {
			$method->process_admin_options();
			if ( Notifications::ENABLED ) {
				$consent = isset( $_POST['esraw_usage_consent'] ) ? 'yes' : 'no';
				update_option( Notifications::CONSENT_OPTION, $consent );
				if ( 'no' === $consent ) {
					delete_option( Notifications::PENDING_OPTION );
				}
			}
			$saved = true;
		}
		?>
		<div class="wrap">
			<h1><?php esc_html_e( 'Easy Shipping — Settings', 'easy-shipping-rate' ); ?></h1>

			<?php if ( $saved ) : ?>
				<div class="notice notice-success is-dismissible">
					<p><?php esc_html_e( 'Settings saved.', 'easy-shipping-rate' ); ?></p>
				</div>
			<?php endif; ?>

			<p>
				<?php esc_html_e( 'Need to back up or migrate your shipping methods?', 'easy-shipping-rate' ); ?>
				&nbsp;<a href="<?php echo esc_url( admin_url( 'admin.php?page=easy-shipping-import-export' ) ); ?>"><?php esc_html_e( 'Go to Import / Export →', 'easy-shipping-rate' ); ?></a>
			</p>

			<form method="POST">
				<?php wp_nonce_field( 'esraw-save-settings', 'esraw_settings_nonce' ); ?>
				<table class="form-table" role="presentation">
					<?php echo $method->generate_settings_html( $method->get_form_fields(), false ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
					<?php if ( Notifications::ENABLED ) : ?>
						<tr>
							<th scope="row">
								<label for="esraw_usage_consent"><?php esc_html_e( 'Usage notifications', 'easy-shipping-rate' ); ?></label>
							</th>
							<td>
								<label for="esraw_usage_consent">
									<input type="checkbox" name="esraw_usage_consent" id="esraw_usage_consent" value="1" <?php checked( 'yes', get_option( Notifications::CONSENT_OPTION ) ); ?>>
									<?php esc_html_e( 'Email the developer when the plugin is installed, activated or deactivated.', 'easy-shipping-rate' ); ?>
								</label>
							</td>
						</tr>
					<?php endif; ?>
				</table>
				<?php submit_button( __( 'Save Settings', 'easy-shipping-rate' ) ); ?>
			</form>
		</div>
		<?php
	}

	/**
	 * Render the Import / Export page and handle both form submissions.
	 */
	public function import_export_page() {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}

		// Export: stream CSV before further output.
		if (
			isset( $_POST['esraw_export_nonce'] )
			&& wp_verify_nonce( sanitize_key( wp_unslash( $_POST['esraw_export_nonce'] ) ), 'esraw-export' )
			&& isset( $_POST['esraw_shipping_export_field'] )
			&& is_array( $_POST['esraw_shipping_export_field'] )
		) {
			$export_data = array_map( 'absint', wp_unslash( $_POST['esraw_shipping_export_field'] ) );
			$records     = array();

			foreach ( $export_data as $ship_instance_id ) {
				$method_instance  = get_option( 'woocommerce_' . ShippingMethod::METHOD_ID . '_' . $ship_instance_id . '_settings' );
				$method_condition = get_option( ShippingMethod::METHOD_ID . $ship_instance_id );
				if ( is_array( $method_instance ) && is_array( $method_condition ) ) {
					$method_instance['next']  = 'yes';
					$method_condition['next'] = 'no';
					$records[]                = array( wp_json_encode( $method_instance ) );
					$records[]                = array( wp_json_encode( $method_condition ) );
				} else {
					wp_die( esc_html__( 'Couldn\'t get export file', 'easy-shipping-rate' ) );
				}
			}

			ob_end_clean();
			$csv_file = 'easy_rate_shipping_methods_' . gmdate( 'Ymd_His' ) . '.csv';
			header( 'Content-Type: text/csv' );
			header( 'Content-Disposition: attachment; filename="' . $csv_file . '"' );
			$fh = fopen( 'php://output', 'w' );
			foreach ( $records as $record ) {
				fputcsv( $fh, $record );
			}
			fclose( $fh );
			exit;
		}

		// Import: process then redirect to avoid double-submit on refresh.
		if (
			isset( $_POST['esraw_import_nonce'] )
			&& wp_verify_nonce( sanitize_key( wp_unslash( $_POST['esraw_import_nonce'] ) ), 'esraw-import' )
			&& isset( $_POST['esraw_shipping_zones_import'] )
			&& is_array( $_POST['esraw_shipping_zones_import'] )
			&& ! empty( $_FILES['esraw_import_file']['tmp_name'] )
			&& is_uploaded_file( sanitize_text_field( wp_unslash( $_FILES['esraw_import_file']['tmp_name'] ) ) )
		) {
			$file  = sanitize_text_field( wp_unslash( $_FILES['esraw_import_file']['tmp_name'] ) );
			$zones = array_map( 'absint', wp_unslash( $_POST['esraw_shipping_zones_import'] ) );

			foreach ( $zones as $zone_id ) {
				$zone   = new \WC_Shipping_Zone( $zone_id );
				$handle = fopen( $file, 'r' );
				if ( false === $handle ) {
					continue;
				}
				$ship_instance_id = null;
				while ( ( $data = fgetcsv( $handle, 1000, ',' ) ) !== false ) {
					$data_decode = json_decode( current( $data ), true );
					if ( ! is_array( $data_decode ) || ! isset( $data_decode['next'] ) ) {
						continue;
					}
					$data_decode = map_deep( $data_decode, 'sanitize_text_field' );
					if ( 'yes' === $data_decode['next'] ) {
						$ship_instance_id = $zone->add_shipping_method( ShippingMethod::METHOD_ID );
						unset( $data_decode['next'] );
						update_option( 'woocommerce_' . ShippingMethod::METHOD_ID . '_' . $ship_instance_id . '_settings', $data_decode );
					} elseif ( 'no' === $data_decode['next'] && $ship_instance_id ) {
						unset( $data_decode['next'] );
						update_option( ShippingMethod::METHOD_ID . $ship_instance_id, $data_decode );
					}
				}
				fclose( $handle );
			}

			wp_safe_redirect(
				add_query_arg( 'esraw_imported', '1', admin_url( 'admin.php?page=easy-shipping-import-export' ) )
			);
			exit;
		}

		$methods = get_shipping_list_for_export();
		$zones   = get_shipping_zones_list_for_import();
		?>
		<div class="wrap">
			<h1><?php esc_html_e( 'Import / Export', 'easy-shipping-rate' ); ?></h1>

			<?php if ( isset( $_GET['esraw_imported'] ) ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
				<div class="notice notice-success is-dismissible">
					<p><?php esc_html_e( 'Shipping methods imported successfully.', 'easy-shipping-rate' ); ?></p>
				</div>
			<?php endif; ?>

			<p><a href="<?php echo esc_url( admin_url( 'admin.php?page=easy_shipping_rate' ) ); ?>">&#8592; <?php esc_html_e( 'Back to Settings', 'easy-shipping-rate' ); ?></a></p>

			<h2><?php esc_html_e( 'Export', 'easy-shipping-rate' ); ?></h2>
			<p><?php esc_html_e( 'Export the full configuration of one or more Easy Shipping methods — including all settings and rules — as a CSV file. Use this to back up your configuration or copy methods to another zone or another store.', 'easy-shipping-rate' ); ?></p>

			<form method="POST">
				<?php wp_nonce_field( 'esraw-export', 'esraw_export_nonce' ); ?>
				<table class="form-table" role="presentation">
					<tr>
						<th scope="row">
							<label for="esraw_shipping_export_field"><?php esc_html_e( 'Methods to export', 'easy-shipping-rate' ); ?></label>
						</th>
						<td>
							<?php if ( empty( $methods ) ) : ?>
								<p><?php esc_html_e( 'No Easy Shipping methods found. Add one to a shipping zone first.', 'easy-shipping-rate' ); ?></p>
							<?php else : ?>
								<select multiple name="esraw_shipping_export_field[]" id="esraw_shipping_export_field"
										size="<?php echo esc_attr( min( count( $methods ), 8 ) ); ?>"
										class="esraw-min-w-[260px]">
									<?php foreach ( $methods as $key => $method ) : ?>
										<option value="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $method ); ?></option>
									<?php endforeach; ?>
								</select>
								<p class="description"><?php esc_html_e( 'Hold Ctrl (Windows) or Cmd (Mac) to select multiple methods.', 'easy-shipping-rate' ); ?></p>
							<?php endif; ?>
						</td>
					</tr>
				</table>
				<?php if ( ! empty( $methods ) ) : ?>
					<?php submit_button( __( 'Generate Export File', 'easy-shipping-rate' ), 'secondary' ); ?>
				<?php endif; ?>
			</form>

			<hr/>

			<h2><?php esc_html_e( 'Import', 'easy-shipping-rate' ); ?></h2>
			<p><?php esc_html_e( 'Upload a CSV file previously exported from Easy Shipping. The methods will be added to the zone(s) you select — existing methods are not modified or deleted.', 'easy-shipping-rate' ); ?></p>
			<div class="notice notice-warning inline esraw-m-0 esraw-mb-4">
				<p><?php esc_html_e( 'Importing will add new Easy Shipping methods to the selected zones. Existing methods are not modified or deleted. To undo an import, go to the zone\'s method list and delete the newly created methods.', 'easy-shipping-rate' ); ?></p>
			</div>

			<form method="POST" enctype="multipart/form-data">
				<?php wp_nonce_field( 'esraw-import', 'esraw_import_nonce' ); ?>
				<table class="form-table" role="presentation">
					<tr>
						<th scope="row">
							<label for="esraw_shipping_zones_import"><?php esc_html_e( 'Add to zones', 'easy-shipping-rate' ); ?></label>
						</th>
						<td>
							<?php if ( empty( $zones ) ) : ?>
								<p><?php esc_html_e( 'No shipping zones found. Create a zone in WooCommerce first.', 'easy-shipping-rate' ); ?></p>
							<?php else : ?>
								<select multiple name="esraw_shipping_zones_import[]" id="esraw_shipping_zones_import"
										size="<?php echo esc_attr( min( count( $zones ), 8 ) ); ?>"
										class="esraw-min-w-[260px]">
									<?php foreach ( $zones as $key => $zone ) : ?>
										<option value="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $zone ); ?></option>
									<?php endforeach; ?>
								</select>
								<p class="description"><?php esc_html_e( 'Hold Ctrl (Windows) or Cmd (Mac) to select multiple zones.', 'easy-shipping-rate' ); ?></p>
							<?php endif; ?>
						</td>
					</tr>
					<tr>
						<th scope="row">
							<label for="esraw_import_file"><?php esc_html_e( 'CSV file', 'easy-shipping-rate' ); ?></label>
						</th>
						<td>
							<input type="file" name="esraw_import_file" id="esraw_import_file" accept=".csv">
							<p class="description"><?php esc_html_e( 'Select the .csv file previously exported from Easy Shipping.', 'easy-shipping-rate' ); ?></p>
						</td>
					</tr>
				</table>
				<?php if ( ! empty( $zones ) ) : ?>
					<?php submit_button( __( 'Import Methods', 'easy-shipping-rate' ), 'secondary' ); ?>
				<?php endif; ?>
			</form>
		</div>
		<?php
	}

	/**
	 * Clean up saved conditions when a zone method is deleted.
	 *
	 * @param int $instance_id
	 */
	public function delete_shipping_conditions( $instance_id ) {
		delete_option( ShippingMethod::METHOD_ID . $instance_id );
	}

	/**
	 * Screens where only this plugin's notices should appear: its own admin
	 * pages, and the WooCommerce shipping settings only when the method being
	 * edited is ours — the rest of the WooCommerce settings is shared territory
	 * and is not filtered.
	 *
	 * @return bool
	 */
	private function is_esraw_notice_scope() {
		$screen = get_current_screen();
		if ( ! $screen ) {
			return false;
		}
		if ( false !== strpos( $screen->id, 'easy_shipping_rate' ) || false !== strpos( $screen->id, 'easy-shipping-import-export' ) ) {
			return true;
		}
		return 'woocommerce_page_wc-settings' === $screen->id && $this->is_own_method_instance_page();
	}

	/**
	 * Whether the request is the WooCommerce shipping settings screen editing an
	 * instance of this plugin's method (tab=shipping with our instance_id).
	 *
	 * @return bool
	 */
	private function is_own_method_instance_page() {
		if ( ! class_exists( 'WC_Shipping_Zones' ) ) {
			return false;
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check to scope display.
		$tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : '';
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check to scope display.
		$instance_id = isset( $_GET['instance_id'] ) ? absint( wp_unslash( $_GET['instance_id'] ) ) : 0;
		if ( 'shipping' !== $tab || ! $instance_id ) {
			return false;
		}
		$method = \WC_Shipping_Zones::get_shipping_method( $instance_id );
		return $method && ShippingMethod::METHOD_ID === $method->id;
	}

	/**
	 * Drop every callback attached to the given notice hook that does not belong
	 * to this plugin.
	 *
	 * @param string $hook Notice hook name.
	 */
	private function remove_foreign_notice_callbacks( $hook ) {
		global $wp_filter;
		if ( ! isset( $wp_filter[ $hook ] ) ) {
			return;
		}
		foreach ( $wp_filter[ $hook ]->callbacks as $priority => $callbacks ) {
			foreach ( $callbacks as $id => $callback ) {
				if ( ! $this->is_plugin_callback( $callback['function'] ) ) {
					unset( $wp_filter[ $hook ]->callbacks[ $priority ][ $id ] );
				}
			}
		}
	}

	/**
	 * Whether a hook callback belongs to this plugin. Closures and other
	 * unattributable callables are treated as foreign.
	 *
	 * @param mixed $callback Registered hook callback.
	 * @return bool
	 */
	private function is_plugin_callback( $callback ) {
		if ( is_array( $callback ) && isset( $callback[0] ) ) {
			$holder = is_object( $callback[0] ) ? get_class( $callback[0] ) : (string) $callback[0];
			return 0 === strpos( $holder, 'EasyShippingRate\\' );
		}
		if ( is_string( $callback ) ) {
			return 0 === strpos( $callback, 'EasyShippingRate\\' ) || 0 === strpos( $callback, 'esraw_' );
		}
		return false;
	}
}
