<?php

namespace WPKIN_SHOP_MANAGER\API\AdminApi;

if (! defined('ABSPATH')) {
	wp_die(esc_html__('You can\'t access this page', 'shop-manager'));
}

/**
 * API Callback
 *
 * @since 1.0.0
 */
class Callback extends ApiHelper
{

	/**
	 * Summary of wpkin_admin_order_statuses
	 * @param mixed $request
	 * @return \WP_REST_Response
	 */
	public function wpkin_admin_order_statuses()
	{

		$order_statuses = [];

		if (function_exists('wc_get_order_statuses')) {
			$order_statuses = wc_get_order_statuses();
		}

		$custom_status = get_option('wpkin_sm_admin_settings', [])['orders']['custom_statuses'] ?? [];

		// Remove matching keys
		$filtered_statuses = array_diff_key($order_statuses, $custom_status);

		return rest_ensure_response(
			[
				'statuses' => $filtered_statuses,
			]
		);
	}

	/**
	 * Save admin settings
	 */
	public function wpkin_save_admin_settings($request)
	{
		try {
			// Get and validate the incoming data
			$data = $request->get_json_params();

			// $active_tab = isset($data['active_tab']) ? sanitize_text_field($data['active_tab']) : 'modules';// Uncomment it If needed

			// Validate data
			if (empty($data)) {
				return new \WP_REST_Response(
					[
						'status' => 'error',
						'message' => 'Invalid or empty data received',
						'code' => 'invalid_data',
					],
					400
				);
			}

			// Initialize settings data
			$settings_data = [
				'last_updated' => current_time('mysql'),
			];

			// Process module settings if provided
			if (isset($data['module_settings'])) {
				$settings_data['module_settings'] = $data['module_settings'];
			}

			// Process order statuses if provided
			if (isset($data['order_statuses'])) {
				// Get WooCommerce order statuses
				$wc_statuses = wc_get_order_statuses();

				// Include custom statuses from saved settings (they may not be registered with WC when Pro is off)
				$saved_custom = get_option( 'wpkin_sm_admin_settings', [] )['orders']['custom_statuses'] ?? [];
				foreach ( $saved_custom as $cs_key => $cs ) {
					if ( ! isset( $wc_statuses[ $cs_key ] ) ) {
						$wc_statuses[ $cs_key ] = $cs['name'] ?? $cs_key;
					}
				}

				// Create array of selected statuses with their labels
				$selected_statuses = [];
				foreach ($data['order_statuses'] as $status) {
					if (isset($wc_statuses[$status])) {
						$selected_statuses[$status] = $wc_statuses[$status];
					}
				}

				$settings_data['orders']['order_statuses'] = $selected_statuses;
			}

			if (isset($data['default_status_styles'])) {
				$settings_data['orders']['default_status_styles'] = $data['default_status_styles'];
			}

			if (isset($data['custom_statuses'])) {
				$settings_data['orders']['custom_statuses'] = $data['custom_statuses'];
			}

			// Process filter settings if provided
			if (isset($data['filter_settings'])) {
				$settings_data['orders']['filter_settings'] = $data['filter_settings'];
			}

			// Process product settings if provided
			if (isset($data['products']) && is_array($data['products']) && ! empty($data['products'])) {
				$p = $data['products'];
				$settings_data['products'] = [
					'low_stock_threshold'      => max( 0, intval( $p['low_stock_threshold']      ?? 2 ) ),
					'out_of_stock_visibility'  => (bool) ( $p['out_of_stock_visibility']  ?? true ),
					'default_stock_management' => (bool) ( $p['default_stock_management'] ?? false ),
					'default_sort'             => sanitize_text_field( $p['default_sort'] ?? 'date' ),
					'per_page'                 => max( 1, intval( $p['per_page'] ?? 20 ) ),
					'sku_prefix'               => sanitize_text_field( $p['sku_prefix'] ?? '' ),
					'enable_reviews'           => (bool) ( $p['enable_reviews']           ?? true ),
					'verified_purchase_only'   => (bool) ( $p['verified_purchase_only']   ?? false ),
				];
			}

			// Process customer tagging settings if provided
			if (isset($data['customer_tagging']) && is_array($data['customer_tagging']) && ! empty($data['customer_tagging'])) {
				$ct = $data['customer_tagging'];
				$settings_data['customer_tagging'] = [
					'vip_spend_threshold'    => max( 0, floatval( $ct['vip_spend_threshold']    ?? 500 ) ),
					'vip_orders_threshold'   => max( 1, intval(   $ct['vip_orders_threshold']   ?? 10 ) ),
					'loyal_orders_threshold' => max( 1, intval(   $ct['loyal_orders_threshold'] ?? 5 ) ),
					'loyal_days_window'      => max( 1, intval(   $ct['loyal_days_window']      ?? 60 ) ),
					'new_days_threshold'     => max( 1, intval(   $ct['new_days_threshold']     ?? 30 ) ),
					'big_spender_threshold'  => max( 0, floatval( $ct['big_spender_threshold']  ?? 200 ) ),
					'frequent_orders_count'  => max( 1, intval(   $ct['frequent_orders_count']  ?? 3 ) ),
					'frequent_orders_window' => max( 1, intval(   $ct['frequent_orders_window'] ?? 30 ) ),
					'at_risk_days'           => max( 1, intval(   $ct['at_risk_days']           ?? 90 ) ),
					'inactive_days'          => max( 1, intval(   $ct['inactive_days']          ?? 180 ) ),
					'excluded_roles'         => array_map( 'sanitize_text_field', (array) ( $ct['excluded_roles'] ?? [] ) ),
				];
			}

			// Process invoice settings if provided
			if (isset($data['invoice_settings']) && is_array($data['invoice_settings']) && ! empty($data['invoice_settings'])) {
				$iv = $data['invoice_settings'];
				$settings_data['invoice_settings'] = [
					'template'             => sanitize_text_field( $iv['template']             ?? 'modern' ),
					'primary_color'        => sanitize_hex_color( $iv['primary_color']         ?? '#1677ff' ) ?: '#1677ff',
					'accent_color'         => sanitize_hex_color( $iv['accent_color']          ?? '#e6f4ff' ) ?: '#e6f4ff',
					'text_color'           => sanitize_hex_color( $iv['text_color']            ?? '#1a1a1a' ) ?: '#1a1a1a',
					'auto_generate'        => (bool) ( $iv['auto_generate']                    ?? true ),
					'send_with_email'      => (bool) ( $iv['send_with_email']                  ?? true ),
					'invoice_prefix'       => sanitize_text_field( $iv['invoice_prefix']       ?? 'INV-' ),
					'number_padding'       => max( 1, min( 10, intval( $iv['number_padding']   ?? 4 ) ) ),
					'page_size'            => sanitize_text_field( $iv['page_size']            ?? 'A4' ),
					'logo_url'             => esc_url_raw( $iv['logo_url']                     ?? '' ),
					'company_name'         => sanitize_text_field( $iv['company_name']         ?? '' ),
					'company_tagline'      => sanitize_text_field( $iv['company_tagline']      ?? '' ),
					'company_address'      => sanitize_text_field( $iv['company_address']      ?? '' ),
					'company_city'         => sanitize_text_field( $iv['company_city']         ?? '' ),
					'company_phone'        => sanitize_text_field( $iv['company_phone']        ?? '' ),
					'company_email'        => sanitize_email( $iv['company_email']             ?? '' ),
					'company_website'      => esc_url_raw( $iv['company_website']              ?? '' ),
					'show_logo'            => (bool) ( $iv['show_logo']                        ?? true ),
					'show_tax'             => (bool) ( $iv['show_tax']                         ?? true ),
					'show_shipping'        => (bool) ( $iv['show_shipping']                    ?? true ),
					'show_discount'        => (bool) ( $iv['show_discount']                    ?? true ),
					'show_customer_notes'  => (bool) ( $iv['show_customer_notes']              ?? true ),
					'show_payment_method'  => (bool) ( $iv['show_payment_method']              ?? true ),
					'show_order_number'    => (bool) ( $iv['show_order_number']                ?? true ),
					'col_qty'              => (bool) ( $iv['col_qty']                          ?? true ),
					'col_sku'              => (bool) ( $iv['col_sku']                          ?? false ),
					'col_tax'              => (bool) ( $iv['col_tax']                          ?? true ),
					'col_discount'         => (bool) ( $iv['col_discount']                     ?? false ),
					'footer_text'          => sanitize_textarea_field( $iv['footer_text']      ?? '' ),
					'terms_text'           => sanitize_textarea_field( $iv['terms_text']       ?? '' ),
					'payment_info'         => sanitize_textarea_field( $iv['payment_info']     ?? '' ),
				];
			}

			// Process employee management settings if provided
			if ( isset( $data['employee_management'] ) && is_array( $data['employee_management'] ) ) {
				$em = $data['employee_management'];
				$settings_data['employee_management'] = [
					'log_retention_days' => in_array( (int) ( $em['log_retention_days'] ?? 30 ), [ 30, 60, 90 ], true )
						? (int) $em['log_retention_days']
						: 30,
				];
			}

			// Process appearance settings if provided
			if (isset($data['appearance']) && is_array($data['appearance'])) {
				$allowed_presets    = ['modern', 'classic', 'bold', 'soft', 'compact'];
				$allowed_colors     = ['emerald', 'ocean', 'purple', 'sunset', 'rose', 'teal', 'amber', 'slate', 'crimson', 'indigo'];
				$allowed_dark_modes = ['midnight', 'slate', 'charcoal', 'forest'];
				$ap = $data['appearance'];
				$settings_data['appearance'] = [
					'preset'        => in_array( $ap['preset'] ?? '', $allowed_presets, true )
						? $ap['preset'] : 'compact',
					'colorScheme'   => in_array( $ap['colorScheme'] ?? '', $allowed_colors, true )
						? $ap['colorScheme'] : 'ocean',
					'darkMode'      => in_array( $ap['darkMode'] ?? '', $allowed_dark_modes, true )
						? $ap['darkMode'] : null,
					'preferredDark' => in_array( $ap['preferredDark'] ?? '', $allowed_dark_modes, true )
						? $ap['preferredDark'] : 'slate',
				];
			}

			// Process AI settings if provided (skip empty object — means AI tab was never visited)
			if (isset($data['ai_settings']) && is_array($data['ai_settings']) && ! empty($data['ai_settings'])) {
				$ai = $data['ai_settings'];

				$settings_data['ai_settings'] = [
					'provider'    => sanitize_text_field($ai['provider'] ?? 'claude'),
					'model'       => sanitize_text_field($ai['model'] ?? 'claude-sonnet-4-6'),
					'max_tokens'  => intval($ai['max_tokens'] ?? 1024),
					'temperature' => floatval($ai['temperature'] ?? 0.7),
				];

				// Only update the encrypted key if a new non-empty key was submitted
				$new_key = isset($ai['api_key']) ? trim($ai['api_key']) : '';
				if ($new_key !== '') {
					$settings_data['ai_settings']['api_key_encrypted'] = $this->wpkin_encrypt_api_key($new_key);
				} else {
					// Keep the existing encrypted key
					$existing = get_option('wpkin_sm_admin_settings', []);
					$settings_data['ai_settings']['api_key_encrypted'] = $existing['ai_settings']['api_key_encrypted'] ?? '';
				}

				// Always set api_key_set flag
				$settings_data['ai_settings']['api_key_set'] = ! empty($settings_data['ai_settings']['api_key_encrypted']);
			}

			// Sanitize the settings data
			$sanitized_settings = $this->wpkin_sanitize_settings_data($settings_data);

			// Get existing settings to merge with new ones
			$existing_settings = get_option('wpkin_sm_admin_settings', []);

			// If existing settings is not an array, initialize it
			if (! is_array($existing_settings)) {
				$existing_settings = [];
			}

			//  Making History for Order tab
			if (isset($sanitized_settings['orders']) && $sanitized_settings['orders']) {
				$order_settings['orders'] = $sanitized_settings['orders'] ? $sanitized_settings['orders'] : [];
				update_option('wpkin_sm_order_tab_settings', $order_settings);
			}

			$order_settings = get_option('wpkin_sm_order_tab_settings', []) ?? [];

			$merged_settings = array_merge($existing_settings, $sanitized_settings, $order_settings);

			// Deep-merge employee_management so custom_roles/access_config are preserved
			if ( isset( $sanitized_settings['employee_management'] ) && isset( $existing_settings['employee_management'] ) && is_array( $existing_settings['employee_management'] ) ) {
				$merged_settings['employee_management'] = array_merge(
					$existing_settings['employee_management'],
					$sanitized_settings['employee_management']
				);
			}

			// Save to options
			$update_result = update_option('wpkin_sm_admin_settings', $merged_settings);

			// If customer_tagging settings changed, invalidate all cached auto-tags
			// so every customer gets recalculated with new thresholds on next API read.
			$old_ct = $existing_settings['customer_tagging'] ?? [];
			$new_ct = $sanitized_settings['customer_tagging'] ?? null;
			if ( $new_ct !== null && $new_ct !== $old_ct ) {
				global $wpdb;
				$wpdb->delete( $wpdb->usermeta, [ 'meta_key' => '_sm_customer_tags_auto' ] );
				$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_sm_customer_time_tags_%' OR option_name LIKE '_transient_timeout_sm_customer_time_tags_%'" );
			}

			if (! $update_result && $merged_settings !== $existing_settings) {
				return new \WP_REST_Response(
					[
						'status' => 'error',
						'message' => 'Failed to update settings',
						'code' => 'update_failed',
					],
					400
				);
			}

			// Return success response
			return new \WP_REST_Response(
				[
					'status' => 'success',
					'message' => 'Settings saved successfully',
					'data' => $merged_settings,
				],
				201
			);
		} catch (\Exception $e) {
			error_log( 'Shop Manager save_admin_settings error: ' . $e->getMessage() );
			return new \WP_REST_Response(
				[
					'status'  => 'error',
					'message' => 'An unexpected error occurred',
					'code'    => 'server_error',
				],
				500
			);
		}
	}

	// ─── AI helpers ──────────────────────────────────────────────────────────

	/**
	 * Encrypt an API key using AES-256-CBC.
	 */
	private function wpkin_encrypt_api_key( string $key ): string {
		$secret = substr( hash( 'sha256', AUTH_KEY . AUTH_SALT ), 0, 32 );
		$iv     = openssl_random_pseudo_bytes( 16 );
		$enc    = openssl_encrypt( $key, 'AES-256-CBC', $secret, 0, $iv );
		return base64_encode( $iv . '::' . $enc );
	}

	/**
	 * Decrypt an API key.
	 */
	public function wpkin_decrypt_api_key( string $stored ): string {
		if ( empty( $stored ) ) return '';
		$decoded = base64_decode( $stored );
		if ( strpos( $decoded, '::' ) === false ) return '';
		[ $iv, $enc ] = explode( '::', $decoded, 2 );
		$secret = substr( hash( 'sha256', AUTH_KEY . AUTH_SALT ), 0, 32 );
		return openssl_decrypt( $enc, 'AES-256-CBC', $secret, 0, $iv ) ?: '';
	}

	// ─── AI Helpers (shared with Pro via inheritance) ─────────────────────────

	/**
	 * Build the AI prompt for product/employee content generation.
	 */
	protected function wpkin_build_ai_prompt( string $product_type, string $keywords, string $tone, string $field, string $custom_prompt = '' ): string {
		$kw         = $keywords ? "Keywords to naturally include: {$keywords}." : '';
		$shared_ctx = "You are an expert ecommerce copywriter. Product type: \"{$product_type}\". {$kw} Tone: {$tone}.";
		$extra      = $custom_prompt ? "\n\nAdditional instructions from the user: {$custom_prompt}" : '';

		$instructions = [
			'title'             => '"title": engaging product title, 5–10 words, SEO-friendly, no punctuation at the end.',
			'short_description' => '"short_description": 1–2 sentences highlighting key benefits, plain text, no HTML.',
			'description'       => '"description": 3–4 paragraphs covering features, benefits, and a call to action. Use <p> tags.',
		];

		if ( $field === 'all' ) {
			$fields_list = implode( "\n  ", array_values( $instructions ) );
			return "{$shared_ctx}{$extra}\n\nReturn ONLY a valid JSON object with these exact keys:\n{\n  {$fields_list}\n}\n\nReturn ONLY the JSON. No markdown, no extra text.";
		}

		if ( isset( $instructions[ $field ] ) ) {
			return "{$shared_ctx}{$extra}\n\nReturn ONLY a valid JSON object: { {$instructions[$field]} }\n\nReturn ONLY the JSON. No markdown, no extra text.";
		}

		return '';
	}

	/**
	 * Call the configured AI provider and return the raw text response.
	 *
	 * @return string|\WP_Error
	 */
	protected function wpkin_call_ai_provider( string $provider, string $model, string $raw_key, string $prompt, int $max_tokens, float $temperature ) {
		$sslverify = ! ( defined( 'WP_DEBUG' ) && WP_DEBUG );

		if ( $provider === 'claude' ) {
			$response = wp_remote_post( 'https://api.anthropic.com/v1/messages', [
				'timeout'   => 30,
				'sslverify' => $sslverify,
				'headers'   => [
					'x-api-key'         => $raw_key,
					'anthropic-version' => '2023-06-01',
					'content-type'      => 'application/json',
				],
				'body' => wp_json_encode( [
					'model'       => $model ?: 'claude-sonnet-4-6',
					'max_tokens'  => $max_tokens,
					'temperature' => $temperature,
					'messages'    => [ [ 'role' => 'user', 'content' => $prompt ] ],
				] ),
			] );
			if ( is_wp_error( $response ) ) return $response;
			$code = wp_remote_retrieve_response_code( $response );
			$body = json_decode( wp_remote_retrieve_body( $response ), true );
			if ( $code !== 200 ) return new \WP_Error( 'ai_error', $body['error']['message'] ?? "HTTP {$code}" );
			return $body['content'][0]['text'] ?? '';

		} elseif ( $provider === 'openai' ) {
			$response = wp_remote_post( 'https://api.openai.com/v1/chat/completions', [
				'timeout'   => 30,
				'sslverify' => $sslverify,
				'headers'   => [
					'Authorization' => 'Bearer ' . $raw_key,
					'Content-Type'  => 'application/json',
				],
				'body' => wp_json_encode( [
					'model'       => $model ?: 'gpt-4o-mini',
					'max_tokens'  => $max_tokens,
					'temperature' => $temperature,
					'messages'    => [ [ 'role' => 'user', 'content' => $prompt ] ],
				] ),
			] );
			if ( is_wp_error( $response ) ) return $response;
			$code = wp_remote_retrieve_response_code( $response );
			$body = json_decode( wp_remote_retrieve_body( $response ), true );
			if ( $code !== 200 ) return new \WP_Error( 'ai_error', $body['error']['message'] ?? "HTTP {$code}" );
			return $body['choices'][0]['message']['content'] ?? '';

		} elseif ( $provider === 'gemini' ) {
			$gem_model = $model ?: 'gemini-2.0-flash';
			$url       = "https://generativelanguage.googleapis.com/v1beta/models/{$gem_model}:generateContent?key={$raw_key}";
			$response  = wp_remote_post( $url, [
				'timeout'   => 30,
				'sslverify' => $sslverify,
				'headers'   => [ 'Content-Type' => 'application/json' ],
				'body'      => wp_json_encode( [
					'contents'         => [ [ 'parts' => [ [ 'text' => $prompt ] ] ] ],
					'generationConfig' => [ 'maxOutputTokens' => $max_tokens, 'temperature' => $temperature ],
				] ),
			] );
			if ( is_wp_error( $response ) ) return $response;
			$code = wp_remote_retrieve_response_code( $response );
			$body = json_decode( wp_remote_retrieve_body( $response ), true );
			if ( $code !== 200 ) return new \WP_Error( 'ai_error', $body['error']['message'] ?? "HTTP {$code}" );
			return $body['candidates'][0]['content']['parts'][0]['text'] ?? '';
		}

		return new \WP_Error( 'unknown_provider', 'Unknown AI provider configured.' );
	}

	/**
	 * Strip markdown fences and parse JSON from AI response text.
	 */
	protected function wpkin_parse_ai_json( string $text, string $field ): ?array {
		$clean = preg_replace( '/^```(?:json)?\s*/i', '', trim( $text ) );
		$clean = preg_replace( '/\s*```$/', '', $clean );
		$clean = trim( $clean );

		$parsed = json_decode( $clean, true );

		if ( json_last_error() !== JSON_ERROR_NONE ) {
			if ( preg_match( '/\{[\s\S]*\}/u', $clean, $matches ) ) {
				$parsed = json_decode( $matches[0], true );
			}
		}

		if ( ! is_array( $parsed ) ) return null;

		$result = [];
		$all    = $field === 'all';

		if ( ( $all || $field === 'title' ) && isset( $parsed['title'] ) ) {
			$result['title'] = sanitize_text_field( $parsed['title'] );
		}
		if ( ( $all || $field === 'short_description' ) && isset( $parsed['short_description'] ) ) {
			$result['short_description'] = wp_kses_post( $parsed['short_description'] );
		}
		if ( ( $all || $field === 'description' ) && isset( $parsed['description'] ) ) {
			$result['description'] = wp_kses_post( $parsed['description'] );
		}

		return empty( $result ) ? null : $result;
	}

	/**
	 * Test AI provider connection.
	 */
	/**
	 * Sanitize settings data
	 */
	private function wpkin_sanitize_settings_data($settings_data)
	{
		$sanitized = [];

		// Sanitize module settings
		if (isset($settings_data['module_settings']) && is_array($settings_data['module_settings'])) {
			$sanitized['module_settings'] = [];
			foreach ($settings_data['module_settings'] as $module_id => $enabled) {
				$sanitized['module_settings'][sanitize_text_field($module_id)] = (bool) $enabled;
			}
		}

		if ($settings_data['orders']['order_statuses']) {
			// Sanitize order statuses
			if (isset($settings_data['orders']['order_statuses']) && is_array($settings_data['orders']['order_statuses'])) {
				$sanitized['orders']['order_statuses'] = [];
				foreach ($settings_data['orders']['order_statuses'] as $key => $value) {
					$sanitized['orders']['order_statuses'][sanitize_text_field($key)] = sanitize_text_field($value);
				}
			}

			// Sanitize custom statuses
			if (isset($settings_data['orders']['custom_statuses']) && is_array($settings_data['orders']['custom_statuses'])) {
				$sanitized['orders']['custom_statuses'] = [];
				foreach ($settings_data['orders']['custom_statuses'] as $key => $status) {
					if (isset($status['id']) && isset($status['name']) && isset($status['colors'])) {
						$sanitized_status = [
							'id' => sanitize_text_field($status['id']),
							'name' => sanitize_text_field($status['name']),
							'colors' => [
								'background' => sanitize_text_field($status['colors']['background'] ?? '#f0f0f0'),
								'text' => sanitize_text_field($status['colors']['text'] ?? '#000000'),
								'border' => sanitize_text_field($status['colors']['border'] ?? '#d9d9d9'),
							],
						];
						$sanitized['orders']['custom_statuses'][sanitize_text_field($key)] = $sanitized_status;
					}
				}
			}

			// Sanitize default status styles
			if (isset($settings_data['orders']['default_status_styles']) && is_array($settings_data['orders']['default_status_styles'])) {
				$sanitized['orders']['default_status_styles'] = [];
				foreach ($settings_data['orders']['default_status_styles'] as $key => $status) {
					if (isset($status['id']) && isset($status['name']) && isset($status['colors'])) {
						$sanitized_status = [
							'id' => sanitize_text_field($status['id']),
							'name' => sanitize_text_field($status['name']),
							'colors' => [
								'background' => sanitize_text_field($status['colors']['background'] ?? '#f0f0f0'),
								'text' => sanitize_text_field($status['colors']['text'] ?? '#000000'),
								'border' => sanitize_text_field($status['colors']['border'] ?? '#d9d9d9'),
							],
						];
						$sanitized['orders']['default_status_styles'][sanitize_text_field($key)] = $sanitized_status;
					}
				}
			}

			// Sanitize filter settings
			if (isset($settings_data['orders']['filter_settings']) && is_array($settings_data['orders']['filter_settings'])) {
				$sanitized['orders']['filter_settings'] = [
					'enabled' => isset($settings_data['orders']['filter_settings']['enabled']) ? (bool) $settings_data['orders']['filter_settings']['enabled'] : '',
					'displayMode' => isset($settings_data['orders']['filter_settings']['displayMode']) ? sanitize_text_field($settings_data['orders']['filter_settings']['displayMode']) : 'section',
					'displayStyle' => isset($settings_data['orders']['filter_settings']['displayStyle']) ? sanitize_text_field($settings_data['orders']['filter_settings']['displayStyle']) : 'accordion',
				];

				// Sanitize sections if they exist
				if (isset($settings_data['orders']['filter_settings']['sections']) && is_array($settings_data['orders']['filter_settings']['sections'])) {
					$sanitized['orders']['filter_settings']['sections'] = [];

					foreach ($settings_data['orders']['filter_settings']['sections'] as $section_key => $section) {
						$sanitized_section = [
							'enabled' => isset($section['enabled']) ? (bool) $section['enabled'] : true,
							'title' => isset($section['title']) ? sanitize_text_field($section['title']) : '',
						];

						// Sanitize fields if they exist
						if (isset($section['fields']) && is_array($section['fields'])) {
							$sanitized_section['fields'] = [];

							foreach ($section['fields'] as $field_key => $field) {
								$sanitized_section['fields'][sanitize_text_field($field_key)] = [
									'enabled' => isset($field['enabled']) ? (bool) $field['enabled'] : true,
									'label' => isset($field['label']) ? sanitize_text_field($field['label']) : '',
								];
							}
						}

						$sanitized['orders']['filter_settings']['sections'][sanitize_text_field($section_key)] = $sanitized_section;
					}
				}
			}
		}

		// Sanitize product settings
		if (isset($settings_data['products']) && is_array($settings_data['products'])) {
			$p = $settings_data['products'];
			$sanitized['products'] = [
				'low_stock_threshold'      => max( 0, intval( $p['low_stock_threshold']      ?? 2 ) ),
				'out_of_stock_visibility'  => (bool) ( $p['out_of_stock_visibility']  ?? true ),
				'default_stock_management' => (bool) ( $p['default_stock_management'] ?? false ),
				'default_sort'             => sanitize_text_field( $p['default_sort'] ?? 'date' ),
				'per_page'                 => max( 1, intval( $p['per_page'] ?? 20 ) ),
				'sku_prefix'               => sanitize_text_field( $p['sku_prefix'] ?? '' ),
				'enable_reviews'           => (bool) ( $p['enable_reviews']           ?? true ),
				'verified_purchase_only'   => (bool) ( $p['verified_purchase_only']   ?? false ),
			];
		}

		// Sanitize customer tagging settings
		if (isset($settings_data['customer_tagging']) && is_array($settings_data['customer_tagging'])) {
			$ct = $settings_data['customer_tagging'];
			$sanitized['customer_tagging'] = [
				'vip_spend_threshold'    => max( 0, floatval( $ct['vip_spend_threshold']    ?? 500 ) ),
				'vip_orders_threshold'   => max( 1, intval(   $ct['vip_orders_threshold']   ?? 10 ) ),
				'loyal_orders_threshold' => max( 1, intval(   $ct['loyal_orders_threshold'] ?? 5 ) ),
				'loyal_days_window'      => max( 1, intval(   $ct['loyal_days_window']      ?? 60 ) ),
				'new_days_threshold'     => max( 1, intval(   $ct['new_days_threshold']     ?? 30 ) ),
				'big_spender_threshold'  => max( 0, floatval( $ct['big_spender_threshold']  ?? 200 ) ),
				'frequent_orders_count'  => max( 1, intval(   $ct['frequent_orders_count']  ?? 3 ) ),
				'frequent_orders_window' => max( 1, intval(   $ct['frequent_orders_window'] ?? 30 ) ),
				'at_risk_days'           => max( 1, intval(   $ct['at_risk_days']           ?? 90 ) ),
				'inactive_days'          => max( 1, intval(   $ct['inactive_days']          ?? 180 ) ),
				'excluded_roles'         => array_map( 'sanitize_text_field', (array) ( $ct['excluded_roles'] ?? [] ) ),
			];
		}

		// Sanitize invoice settings
		if (isset($settings_data['invoice_settings']) && is_array($settings_data['invoice_settings'])) {
			$iv = $settings_data['invoice_settings'];
			$sanitized['invoice_settings'] = [
				'template'             => sanitize_text_field( $iv['template']             ?? 'modern' ),
				'primary_color'        => sanitize_hex_color( $iv['primary_color']         ?? '#1677ff' ) ?: '#1677ff',
				'accent_color'         => sanitize_hex_color( $iv['accent_color']          ?? '#e6f4ff' ) ?: '#e6f4ff',
				'text_color'           => sanitize_hex_color( $iv['text_color']            ?? '#1a1a1a' ) ?: '#1a1a1a',
				'auto_generate'        => (bool) ( $iv['auto_generate']                    ?? true ),
				'send_with_email'      => (bool) ( $iv['send_with_email']                  ?? true ),
				'invoice_prefix'       => sanitize_text_field( $iv['invoice_prefix']       ?? 'INV-' ),
				'number_padding'       => max( 1, min( 10, intval( $iv['number_padding']   ?? 4 ) ) ),
				'page_size'            => sanitize_text_field( $iv['page_size']            ?? 'A4' ),
				'logo_url'             => esc_url_raw( $iv['logo_url']                     ?? '' ),
				'company_name'         => sanitize_text_field( $iv['company_name']         ?? '' ),
				'company_tagline'      => sanitize_text_field( $iv['company_tagline']      ?? '' ),
				'company_address'      => sanitize_text_field( $iv['company_address']      ?? '' ),
				'company_city'         => sanitize_text_field( $iv['company_city']         ?? '' ),
				'company_phone'        => sanitize_text_field( $iv['company_phone']        ?? '' ),
				'company_email'        => sanitize_email( $iv['company_email']             ?? '' ),
				'company_website'      => esc_url_raw( $iv['company_website']              ?? '' ),
				'show_logo'            => (bool) ( $iv['show_logo']                        ?? true ),
				'show_tax'             => (bool) ( $iv['show_tax']                         ?? true ),
				'show_shipping'        => (bool) ( $iv['show_shipping']                    ?? true ),
				'show_discount'        => (bool) ( $iv['show_discount']                    ?? true ),
				'show_customer_notes'  => (bool) ( $iv['show_customer_notes']              ?? true ),
				'show_payment_method'  => (bool) ( $iv['show_payment_method']              ?? true ),
				'show_order_number'    => (bool) ( $iv['show_order_number']                ?? true ),
				'col_qty'              => (bool) ( $iv['col_qty']                          ?? true ),
				'col_sku'              => (bool) ( $iv['col_sku']                          ?? false ),
				'col_tax'              => (bool) ( $iv['col_tax']                          ?? true ),
				'col_discount'         => (bool) ( $iv['col_discount']                     ?? false ),
				'footer_text'          => sanitize_textarea_field( $iv['footer_text']      ?? '' ),
				'terms_text'           => sanitize_textarea_field( $iv['terms_text']       ?? '' ),
				'payment_info'         => sanitize_textarea_field( $iv['payment_info']     ?? '' ),
			];
		}

		// Sanitize AI settings
		if (isset($settings_data['ai_settings']) && is_array($settings_data['ai_settings'])) {
			$ai = $settings_data['ai_settings'];
			$sanitized['ai_settings'] = [
				'provider'           => sanitize_text_field($ai['provider']            ?? 'claude'),
				'model'              => sanitize_text_field($ai['model']               ?? 'claude-sonnet-4-6'),
				'max_tokens'         => intval($ai['max_tokens']                       ?? 1024),
				'temperature'        => floatval($ai['temperature']                    ?? 0.7),
				'api_key_encrypted'  => sanitize_text_field($ai['api_key_encrypted']   ?? ''),
				'api_key_set'        => (bool)($ai['api_key_set']                      ?? false),
			];
		}

		// Sanitize employee management settings
		if (isset($settings_data['employee_management']) && is_array($settings_data['employee_management'])) {
			$em = $settings_data['employee_management'];
			$sanitized['employee_management'] = [
				'log_retention_days' => in_array( (int) ( $em['log_retention_days'] ?? 30 ), [ 30, 60, 90 ], true )
					? (int) $em['log_retention_days'] : 30,
			];
		}

		// Sanitize AI chatbot settings
		if (isset($settings_data['chatbot_settings']) && is_array($settings_data['chatbot_settings'])) {
			$cs = $settings_data['chatbot_settings'];
			$sanitized['chatbot_settings'] = [
				'enabled'              => ! empty( $cs['enabled'] ),
				'max_messages_per_day' => max( 0, (int) ( $cs['max_messages_per_day'] ?? 50 ) ),
				'system_prompt_extra'  => sanitize_textarea_field( $cs['system_prompt_extra'] ?? '' ),
				'show_tool_calls'      => ! empty( $cs['show_tool_calls'] ),
			];
		}

		// Sanitize appearance settings
		if (isset($settings_data['appearance']) && is_array($settings_data['appearance'])) {
			$allowed_presets    = ['modern', 'classic', 'bold', 'soft', 'compact'];
			$allowed_colors     = ['emerald', 'ocean', 'purple', 'sunset', 'rose', 'teal', 'amber', 'slate', 'crimson', 'indigo'];
			$allowed_dark_modes = ['midnight', 'slate', 'charcoal', 'forest'];
			$ap = $settings_data['appearance'];
			$sanitized['appearance'] = [
				'preset'        => in_array( $ap['preset'] ?? '', $allowed_presets, true )
					? $ap['preset'] : 'compact',
				'colorScheme'   => in_array( $ap['colorScheme'] ?? '', $allowed_colors, true )
					? $ap['colorScheme'] : 'ocean',
				'darkMode'      => in_array( $ap['darkMode'] ?? '', $allowed_dark_modes, true )
					? $ap['darkMode'] : null,
				'preferredDark' => in_array( $ap['preferredDark'] ?? '', $allowed_dark_modes, true )
					? $ap['preferredDark'] : 'slate',
			];
		}

		// Sanitize last updated timestamp
		if (isset($settings_data['last_updated'])) {
			$sanitized['last_updated'] = sanitize_text_field($settings_data['last_updated']);
		}

		return $sanitized;
	}

	/**
	 * Get admin settings
	 */
	public function wpkin_get_admin_settings()
	{
		try {
			$settings = get_option('wpkin_sm_admin_settings', []);

			return new \WP_REST_Response(
				[
					'status' => 'success',
					'data'   => $settings,
				],
				200
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'status'  => 'error',
					'message' => 'Failed to retrieve settings',
					'code'    => 'retrieve_error',
					'debug'   => WP_DEBUG ? $e->getMessage() : null,
				],
				500
			);
		}
	}

	/**
	 * Get filtered orders list
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_get_order_list($request)
	{
		try {
			// Parse request parameters
			$params = $this->wpkin_parse_request_parameters($request);

			// Build query arguments
			$query_args = $this->wpkin_build_query_args($params);

			// Apply search if provided
			if (! empty($params['search'])) {
				$query_args = $this->wpkin_search_orders($query_args, $params);
			}

			// Apply filters
			$filtered_args = $this->wpkin_apply_filters($query_args, $params);

			// If filters returned false (no matches), return empty result
			if ($filtered_args === false) {
				return new \WP_REST_Response(
					[
						'success' => true,
						'data' => [],
						'total' => 0,
						'total_pages' => 0,
						'current_page' => $params['page'],
						'per_page' => $params['per_page'],
					],
					200
				);
			}

			$query_args = $filtered_args;

			// Apply sorting
			$query_args = $this->wpkin_apply_sorting($query_args, $params);

			// Execute the query
			$result = $this->wpkin_execute_orders_query($query_args, $params);

			if ($result === false) {
				return new \WP_REST_Response(
					[
						'success' => true,
						'data' => [],
						'total' => 0,
						'total_pages' => 0,
						'current_page' => $params['page'],
						'per_page' => $params['per_page'],
					],
					200
				);
			}

			// Format the orders for response
			$formatted_orders = $this->wpkin_format_orders($result['orders']);

			// Return the formatted response
			return new \WP_REST_Response(
				[
					'success' => true,
					'data' => $formatted_orders,
					'total' => $result['total_orders'],
					'total_pages' => $result['total_pages'],
					'current_page' => $params['page'],
					'per_page' => $params['per_page'],
				],
				200
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => 'Error processing request: ' . $e->getMessage(),
				],
				500
			);
		}
	}

	/**
	 * Update order status
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_update_order_status($request)
	{
		// Check permissions
		if (! current_user_can('edit_shop_orders')) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('You do not have permission to update orders', 'shop-manager'),
				],
				403
			);
		}

		// Get parameters
		$order_id = absint( $request->get_param('order_id') );
		$status = $request->get_param('status');

		// Validate parameters
		if (! $order_id || ! $status) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('Order ID and status are required', 'shop-manager'),
				],
				400
			);
		}

		try {

			// Get the order
			$order = wc_get_order($order_id);
			if (! $order) {
				return new \WP_REST_Response(
					[
						'success' => false,
						'message' => __('Order not found', 'shop-manager'),
					],
					404
				);
			}

			// Clean status
			$clean_status = str_replace('wc-', '', $status);

			// Update status
			$order->set_status($clean_status);
			$order->save();

			// Track who made the update
			$current_user = wp_get_current_user();
			if ( $current_user->ID ) {
				$order->update_meta_data( '_sm_last_updated_by', $current_user->display_name );
				$order->update_meta_data( '_sm_last_updated_date', current_time( 'mysql' ) );
				$order->add_order_note(
					sprintf( __( 'Order status changed to %s.', 'shop-manager' ), $clean_status ),
					0,
					true
				);
				$order->save();
			}

			return new \WP_REST_Response(
				[
					'success' => true,
					'message' => __('Order status updated successfully', 'shop-manager'),
				],
				200
			);
		} catch (\Exception $e) {
			throw new \Exception('Error updating order status: ' . $e->getMessage());
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => $e->getMessage(),
				],
				500
			);
		}
	}

	/**
	 * Get customer orders
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_get_customer_orders($request)
	{
		$customer_id = absint( $request->get_param('id') );

		if (! $customer_id) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('Customer ID is required', 'shop-manager'),
				],
				400
			);
		}

		$orders = wc_get_orders(
			[
				'customer_id' => $customer_id,
				'limit' => 50, // Limit to recent 50 orders
				'orderby' => 'date',
				'order' => 'DESC',
			]
		);

		if (empty($orders)) {
			return new \WP_REST_Response(
				[
					'success' => true,
					'orders' => [],
				],
				200
			);
		}

		$formatted_orders = [];

		foreach ($orders as $order) {
			$formatted_orders[] = [
				'id' => $order->get_id(),
				'date_created' => $order->get_date_created()->date('Y-m-d H:i:s'),
				'status' => $order->get_status(),
				'total' => $order->get_total(),
				'items_count' => count($order->get_items()),
			];
		}

		return new \WP_REST_Response(
			[
				'success' => true,
				'orders' => $formatted_orders,
			],
			200
		);
	}

	public function wpkin_get_order_counts( $_request = null )
	{
		try {
			// Get counts for all statuses
			$counts = [];

			// Get all statuses
			$statuses = array_keys(\wc_get_order_statuses());

			// Get count for each status and total
			$total_count = 0;
			foreach ($statuses as $status_key) {
				$status_clean = str_replace('wc-', '', $status_key);
				$count = \wc_orders_count($status_clean);
				$counts[$status_key] = $count;
				$total_count += $count;
			}

			// Add total count to the response
			$counts['total'] = $total_count;

			// Count trash orders
			$trash_count     = wc_orders_count('trash');
			$counts['trash'] = $trash_count;

			// Return response
			return new \WP_REST_Response(
				[
					'success' => true,
					'data' => $counts,
				],
				200
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => $e->getMessage(),
				],
				500
			);
		}
	}

	/**
	 * Move order to trash using WooCommerce native methods
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_trash_order($request)
	{

		// Get parameters
		$order_id = absint( $request->get_param('order_id') );

		// Validate parameters
		if (! $order_id) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('Order ID is required', 'shop-manager'),
				],
				400
			);
		}

		try {

			// Get the order object
			$order = wc_get_order($order_id);
			if (! $order) {
				return new \WP_REST_Response(
					[
						'success' => false,
						'message' => __('Order not found', 'shop-manager'),
					],
					404
				);
			}

			// Check if already in trash
			$current_status = $order->get_status();
			if ($current_status === 'trash') {
				return new \WP_REST_Response(
					[
						'success' => true,
						'message' => __('Order is already in trash', 'shop-manager'),
					],
					200
				);
			}

			if (method_exists($order, 'delete')) {
				update_post_meta($order_id, '_previous_order_status', $order->get_status());
				$result = $order->delete(false); // false = move to trash, not delete permanently

				// Verify the order is now in trash
				$new_order = wc_get_order($order_id);
				$new_status = $new_order ? $new_order->get_status() : null;

				if ($new_status === 'trash') {
					$this->log_order_action(
						(int) $order_id,
						'order_trashed',
						[],
						__( 'Order moved to trash.', 'shop-manager' )
					);
					return new \WP_REST_Response(
						[
							'success' => true,
							'message' => __('Order moved to trash successfully', 'shop-manager'),
						],
						200
					);
				}
			}

			if ($result !== false) {
				// Force clean post cache
				clean_post_cache($order_id);

				return new \WP_REST_Response(
					[
						'success' => true,
						'message' => __('Order moved to trash successfully', 'shop-manager'),
					],
					200
				);
			}

			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('Failed to move order to trash', 'shop-manager'),
				],
				500
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => $e->getMessage(),
				],
				500
			);
		}
	}

	public function wpkin_permanently_delete_order($request)
	{

		$order_id = absint( $request->get_param('order_id') );

		if (! $order_id) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('Order ID is required', 'shop-manager'),
				],
				400
			);
		}

		try {

			// Get the order object
			$order = wc_get_order($order_id);
			if (! $order) {
				return new \WP_REST_Response(
					[
						'success' => false,
						'message' => __('Order not found', 'shop-manager'),
					],
					404
				);
			}

			// Log before delete (order object won't exist after)
			$this->log_order_action( (int) $order_id, 'order_deleted' );

			// Delete permanently
			$result = $order->delete(true);

			if (! $result) {
				throw new \Exception(__('Failed to delete order', 'shop-manager'));
			}

			return new \WP_REST_Response(
				[
					'success' => true,
					'message' => __('Order permanently deleted', 'shop-manager'),
				],
				200
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => $e->getMessage(),
				],
				500
			);
		}
	}

	/**
	 * Restore a WooCommerce order from trash
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_restore_order($request)
	{
		// Get order ID from request
		$order_id = absint( $request->get_param('order_id') );

		// Validate order ID
		if (! $order_id || ! is_numeric($order_id)) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('Order ID is required.', 'shop-manager'),
				],
				400
			);
		}

		// Get the order object
		$order = wc_get_order($order_id);

		if (! $order || $order->get_type() !== 'shop_order') {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('Invalid order ID.', 'shop-manager'),
				],
				404
			);
		}

		try {
			$original_status = get_post_meta($order_id, '_previous_order_status', true);
			$post_status = $original_status ?: 'wc-pending';

			// Set a new status using WooCommerce functions
			$order->set_status($post_status, __('Restored from trash', 'shop-manager'));

			$saved = $order->save();

			if (! $saved || $saved <= 0) {
				return new \WP_REST_Response(
					[
						'success' => false,
						'message' => __('Failed to restore order from trash.', 'shop-manager'),
					],
					500
				);
			}

			// Clean up trash metadata
			delete_post_meta($order_id, '_previous_order_status');
			delete_post_meta($order_id, '_wp_trash_meta_status');
			delete_post_meta($order_id, '_wp_trash_meta_time');

			$this->log_order_action( (int) $order_id, 'order_restored' );

			return new \WP_REST_Response(
				[
					'success' => true,
					'message' => __('Order restored successfully.', 'shop-manager'),
				],
				200
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('Error restoring order: ', 'shop-manager') . $e->getMessage(),
				],
				500
			);
		}
	}



	/**
	 * Bulk move orders to trash using WooCommerce native methods.
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_bulk_trash_orders($request)
	{

		// Get and validate parameters
		$order_ids = $request->get_param('order_ids');

		if (! $order_ids || ! is_array($order_ids) || empty($order_ids)) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('Order IDs are required', 'shop-manager'),
				],
				400
			);
		}

		try {
			$success_count = 0;
			$already_trashed = 0;
			$failed_count = 0;

			foreach ($order_ids as $order_id) {
				// Get the order object
				$order = wc_get_order($order_id);

				if (! $order) {
					++$failed_count;
					continue;
				}

				// Check if already in trash
				if ($order->get_status() === 'trash') {
					++$already_trashed;
					continue;
				}

				// Attempt to move to trash
				if (method_exists($order, 'delete')) {
					update_post_meta($order_id, '_previous_order_status', $order->get_status());

					$order->delete(false); // false = move to trash

					// Verify if moved to trash
					$new_order = wc_get_order($order_id);
					$new_status = $new_order ? $new_order->get_status() : null;

					if ($new_status === 'trash') {
						++$success_count;
						clean_post_cache($order_id);
						$this->log_order_action( (int) $order_id, 'order_trashed' );
					} else {
						++$failed_count;
					}
				} else {
					++$failed_count;
				}
			}

			// Build response message
			$message_parts = [];

			if ($success_count > 0) {
				$message_parts[] = sprintf(
					_n('%d order moved to trash', '%d orders moved to trash', $success_count, 'shop-manager'),
					$success_count
				);
			}

			if ($already_trashed > 0) {
				$message_parts[] = sprintf(
					_n('%d order was already in trash', '%d orders were already in trash', $already_trashed, 'shop-manager'),
					$already_trashed
				);
			}

			if ($failed_count > 0) {
				$message_parts[] = sprintf(
					_n('%d order failed to move', '%d orders failed to move', $failed_count, 'shop-manager'),
					$failed_count
				);
			}

			return new \WP_REST_Response(
				[
					'success' => true,
					'message' => implode(', ', $message_parts),
					'success_count' => $success_count,
					'already_trashed' => $already_trashed,
					'failed_count' => $failed_count,
				],
				200
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => $e->getMessage(),
				],
				500
			);
		}
	}


	/**
	 * Bulk permanently delete orders
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_bulk_delete_orders($request)
	{
		// Check permissions
		if (! current_user_can('delete_shop_orders')) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('You do not have permission to delete orders.', 'shop-manager'),
				],
				403
			);
		}

		// Get parameters
		$order_ids = $request->get_param('order_ids');

		// Validate parameters
		if (! $order_ids || ! is_array($order_ids) || empty($order_ids)) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('Order IDs are required.', 'shop-manager'),
				],
				400
			);
		}

		try {
			$success_count = 0;
			$failed_count  = 0;

			foreach ($order_ids as $order_id) {
				$order = wc_get_order($order_id);

				if (! $order) {
					++$failed_count;
					continue;
				}

				$this->log_order_action( (int) $order_id, 'order_deleted' );
				$result = $order->delete(true); // true = force delete

				if ($result) {
					++$success_count;
					// Optionally clear post cache
					clean_post_cache($order_id);
				} else {
					++$failed_count;
				}
			}

			$message = sprintf(
				/* translators: %1$d is success count, %2$d is failed count */
				__('%1$d order(s) deleted permanently, %2$d failed.', 'shop-manager'),
				$success_count,
				$failed_count
			);

			return new \WP_REST_Response(
				[
					'success'        => true,
					'message'        => $message,
					'success_count'  => $success_count,
					'failed_count'   => $failed_count,
				],
				200
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => $e->getMessage(),
				],
				500
			);
		}
	}


	/**
	 * Bulk restore orders from trash
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_bulk_restore_orders($request)
	{
		if (! current_user_can('edit_shop_orders')) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('You do not have permission to restore orders.', 'shop-manager'),
				],
				403
			);
		}

		$order_ids = $request->get_param('order_ids');

		if (empty($order_ids) || ! is_array($order_ids)) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('Order IDs are required.', 'shop-manager'),
				],
				400
			);
		}

		$success_count = 0;
		$failed_count  = 0;

		foreach ($order_ids as $order_id) {
			$order = wc_get_order($order_id);

			if (! $order || $order->get_type() !== 'shop_order') {
				++$failed_count;
				continue;
			}

			$original_status = get_post_meta($order_id, '_previous_order_status', true);
			$post_status = $original_status ?: 'wc-pending';

			// Set a new status using WooCommerce functions
			$order->set_status($post_status, __('Restored from trash', 'shop-manager'));

			$saved = $order->save();

			if (is_wp_error($saved)) {
				++$failed_count;
				continue;
			}

			// Clean up trash metadata
			delete_post_meta($order_id, '_previous_order_status');
			delete_post_meta($order_id, '_wp_trash_meta_status');
			delete_post_meta($order_id, '_wp_trash_meta_time');

			$this->log_order_action( (int) $order_id, 'order_restored' );
			++$success_count;
		}

		$message = sprintf(
			__('%1$d order(s) restored from trash, %2$d failed.', 'shop-manager'),
			$success_count,
			$failed_count
		);

		return new \WP_REST_Response(
			[
				'success'        => true,
				'message'        => $message,
				'success_count'  => $success_count,
				'failed_count'   => $failed_count,
			],
			200
		);
	}

	/**
	 * Bulk update order statuses
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_bulk_update_order_status($request)
	{

		// Get parameters
		$order_ids = $request->get_param('order_ids');
		$status = $request->get_param('status');

		// Validate parameters
		if (! $order_ids || ! is_array($order_ids) || empty($order_ids)) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('Order IDs are required', 'shop-manager'),
				],
				400
			);
		}

		if (! $status) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __('Status is required', 'shop-manager'),
				],
				400
			);
		}

		try {
			// Clean status format
			$clean_status = str_replace('wc-', '', $status);

			$success_count = 0;
			$failed_count = 0;

			foreach ($order_ids as $order_id) {
				$order = wc_get_order($order_id);
				if ($order) {
					$order->set_status($clean_status);
					$order->save();
					++$success_count;
				} else {
					++$failed_count;
				}
			}

			$message = sprintf(
				/* translators: %1$d is success count, %2$d is failed count */
				__('%1$d orders updated, %2$d failed', 'shop-manager'),
				$success_count,
				$failed_count
			);

			return new \WP_REST_Response(
				[
					'success' => true,
					'message' => $message,
					'success_count' => $success_count,
					'failed_count' => $failed_count,
				],
				200
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => $e->getMessage(),
				],
				500
			);
		}
	}

	/**
	 * Export orders
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_export_orders($request)
	{

		// Get parameters
		$order_ids = $request->get_param('order_ids');
		$status = $request->get_param('status');
		$trash = $request->get_param('trash') === 'true';
		$search = $request->get_param('search');
		$date_from = $request->get_param('date_from');
		$date_to = $request->get_param('date_to');

		try {
			// Build query args
			$args = [
				'limit' => -1, // Get all matching orders
				'return' => 'ids',
			];

			// If specific order IDs provided, use those
			if ($order_ids && is_array($order_ids) && ! empty($order_ids)) {
				$args['include'] = $order_ids;
			} else {
				// Apply filters if no specific IDs

				// Status filter
				if ($trash) {
					// Use wc_get_orders() so this works with both HPOS and legacy tables.
					$trash_order_ids = wc_get_orders( [
						'status' => 'trash',
						'limit'  => -1,
						'return' => 'ids',
					] );

					if (! empty($trash_order_ids)) {
						$args['include'] = $trash_order_ids;
					} else {
						// No trashed orders
						return new \WP_REST_Response(
							[
								'success' => false,
								'message' => __('No orders found to export', 'shop-manager'),
							],
							404
						);
					}
				} elseif ($status) {
					// Regular status filter
					$clean_status = str_replace('wc-', '', $status);
					$args['status'] = $clean_status;
				}

				// Date range
				if ($date_from && $date_to) {
					$args['date_created'] = $date_from . '...' . $date_to;
				}

				// Search filter — use wc_get_orders() so this works with both HPOS and legacy tables.
				if ($search) {
					$search_order_ids = wc_get_orders( [
						'limit'  => -1,
						'return' => 'ids',
						'search' => sanitize_text_field( $search ),
					] );

					// Also include a direct order-ID hit (in case the search string is a number).
					if ( is_numeric( $search ) ) {
						$by_id = wc_get_order( absint( $search ) );
						if ( $by_id ) {
							$search_order_ids = array_unique( array_merge( $search_order_ids, [ absint( $search ) ] ) );
						}
					}

					if (! empty($search_order_ids)) {
						// If we already have IDs from other filters, intersect
						if (isset($args['include'])) {
							$args['include'] = array_intersect($args['include'], $search_order_ids);

							if (empty($args['include'])) {
								return new \WP_REST_Response(
									[
										'success' => false,
										'message' => __('No orders found matching your criteria', 'shop-manager'),
									],
									404
								);
							}
						} else {
							$args['include'] = $search_order_ids;
						}
					} else {
						return new \WP_REST_Response(
							[
								'success' => false,
								'message' => __('No orders found matching your search', 'shop-manager'),
							],
							404
						);
					}
				}
			}

			// Get the order IDs
			$order_ids = $args['include'] ?? wc_get_orders($args);

			if (empty($order_ids)) {
				return new \WP_REST_Response(
					[
						'success' => false,
						'message' => __('No orders found to export', 'shop-manager'),
					],
					404
				);
			}

			// Set headers for CSV download
			header('Content-Type: text/csv; charset=utf-8');
			header('Content-Disposition: attachment; filename=orders-export-' . date('Y-m-d') . '.csv');
			header('Pragma: no-cache');
			header('Expires: 0');

			// Create output stream
			$output = fopen('php://output', 'w');

			// Add CSV header row
			fputcsv(
				$output,
				[
					'Order ID',
					'Order Number',
					'Date',
					'Status',
					'Customer Name',
					'Customer Email',
					'Customer Phone',
					'Billing Address',
					'Shipping Address',
					'Payment Method',
					'Items',
					'Total',
					'Notes',
				]
			);

			// Process each order
			foreach ($order_ids as $id) {
				$order = wc_get_order($id);
				if (! $order) {
					continue;
				}

				// Format items
				$items = [];
				foreach ($order->get_items() as $item) {
					if ($item instanceof \WC_Order_Item_Product) {
						$items[] = $item->get_quantity() . 'x ' . $item->get_name() . ' (' . wc_price($item->get_total()) . ')';
					}
				}
				$items_str = implode('; ', $items);

				// Format addresses
				$billing_address = $order->get_formatted_billing_address();
				$billing_address = str_replace('<br/>', ', ', $billing_address);

				$shipping_address = $order->get_formatted_shipping_address();
				$shipping_address = str_replace('<br/>', ', ', $shipping_address);

				// Add order row to CSV
				fputcsv(
					$output,
					[
						$order->get_id(),
						$order->get_order_number(),
						$order->get_date_created()->date('Y-m-d H:i:s'),
						$order->get_status(),
						$order->get_formatted_billing_full_name(),
						$order->get_billing_email(),
						$order->get_billing_phone(),
						$billing_address,
						$shipping_address,
						$order->get_payment_method_title(),
						$items_str,
						$order->get_total(),
						$order->get_customer_note(),
					]
				);
			}

			fclose($output);
			exit; // Stop execution after sending the file

		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => $e->getMessage(),
				],
				500
			);
		}
	}

	/**
	 * Get references data for order filtering
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_get_order_filter_references( $_request = null )
	{
		try {
			$data = [
				'order_statuses' => [],
				'payment_methods' => [],
				'shipping_methods' => [],
				'product_categories' => [],
				'countries' => [],
				'states' => [],
			];

			// Get order statuses
			$statuses = wc_get_order_statuses();
			foreach ($statuses as $status_key => $status_name) {
				$data['order_statuses'][] = [
					'id' => $status_key,
					'name' => $status_name,
				];
			}

			// Get payment gateways/methods
			$payment_gateways = WC()->payment_gateways->get_available_payment_gateways();
			foreach ($payment_gateways as $gateway) {
				if ($gateway->enabled === 'yes') {
					$data['payment_methods'][] = [
						'id' => $gateway->id,
						'name' => $gateway->title,
					];
				}
			}

			// Get shipping methods
			$shipping_methods = WC()->shipping() ? WC()->shipping()->get_shipping_methods() : [];
			foreach ($shipping_methods as $method) {
				$data['shipping_methods'][] = [
					'id' => $method->id,
					'name' => $method->method_title,
				];
			}

			// Get product categories
			$product_categories = get_terms(
				[
					'taxonomy' => 'product_cat',
					'hide_empty' => false,
				]
			);

			if (! is_wp_error($product_categories)) {
				foreach ($product_categories as $category) {
					$data['product_categories'][] = [
						'id' => $category->term_id,
						'name' => $category->name,
						'count' => $category->count,
					];
				}
			}

			// Get countries
			$countries_obj = new \WC_Countries();
			$countries = $countries_obj->get_countries();

			foreach ($countries as $code => $name) {
				$data['countries'][] = [
					'code' => $code,
					'name' => $name,
				];
			}

			// Get states for US as an example (could be expanded)
			$states = $countries_obj->get_states('US');

			if ($states) {
				foreach ($states as $code => $name) {
					$data['states'][] = [
						'code' => 'US:' . $code, // Prefixed with country code for uniqueness
						'name' => $name,
					];
				}
			}

			return new \WP_REST_Response(
				[
					'success' => true,
					'data' => $data,
				],
				200
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => $e->getMessage(),
				],
				500
			);
		}
	}


	public function wpkin_get_products()
	{
		$products = wc_get_products(
			[
				'limit' => -1,
				'status' => 'publish',
			]
		);

		$formatted_products = array_map(
			function ($product) {
				$data = [
					'id' => $product->get_id(),
					'name' => $product->get_name(),
					'price' => $product->get_price(),
					'type' => $product->get_type(),
					'sku' => $product->get_sku(),
					'image' => wp_get_attachment_image_url($product->get_image_id(), 'thumbnail'),
				];

				if ($product->is_type('variable')) {
					$variations = $product->get_available_variations();
					$data['variations'] = array_map(
						function ($variation) {
							$variant = wc_get_product($variation['variation_id']);
							return [
								'id' => $variation['variation_id'],
								'attributes' => $variation['attributes'],
								'price' => $variant->get_price(),
								'regular_price' => $variant->get_regular_price(),
								'sale_price' => $variant->get_sale_price(),
								'sku' => $variant->get_sku(),
							];
						},
						$variations
					);
				}

				return $data;
			},
			$products
		);

		return new \WP_REST_Response(
			[
				'success' => true,
				'data' => $formatted_products,
			],
			200
		);
	}

	private function wpkin_get_payment_method_title($method)
	{
		$payment_methods = WC()->payment_gateways->payment_gateways();
		return isset($payment_methods[$method]) ? $payment_methods[$method]->get_title() : $method;
	}

	public function wpkin_create_wc_order($request)
	{
		$params = $request->get_params();

		try {
			// Create the order
			$order = wc_create_order();

			// Set addresses
			$order->set_address($params['billing'], 'billing');
			$order->set_address($params['shipping'], 'shipping');

			// Set customer data
			$order->set_customer_id(get_current_user_id());
			$order->set_billing_email($params['billing']['email']);
			$order->set_billing_phone($params['billing']['phone']);

			// Set customer note if provided
			if (! empty($params['customer_note'])) {
				$order->set_customer_note($params['customer_note']);
			}

			// Set CMS note as order meta if provided
			if (! empty($params['cms_note'])) {
				$order->add_meta_data('_cms_note', sanitize_textarea_field($params['cms_note']), true);
			}

			// Add products
			foreach ($params['items'] as $item) {
				if (! empty($item['variation_id'])) {
					// Format variation data from meta_data
					$variation_data = [];
					foreach ($item['meta_data'] as $meta) {
						if (strpos($meta['key'], 'attribute_') === 0) {
							$attr_key = str_replace('attribute_pa_', '', $meta['key']);
							$label = ucfirst($attr_key);
							$value = ucfirst($meta['value']);
							$variation_data[$label] = $value;
						}
					}

					// Add variable product
					$order->add_product(
						wc_get_product($item['variation_id']),
						$item['quantity'],
						[
							'variation' => $variation_data,
							'subtotal' => $item['subtotal'],
							'total' => $item['total'],
						]
					);
				} else {
					// Add simple product
					$order->add_product(
						wc_get_product($item['product_id']),
						$item['quantity']
					);
				}
			}

			// Set payment method
			$order->set_payment_method($params['payment_method']);
			$order->set_payment_method_title($this->wpkin_get_payment_method_title($params['payment_method']));

			// Handle discount
			if (! empty($params['discount']) && ! empty($params['discount']['value'])) {
				$discount_amount = floatval($params['discount']['value']);
				$discount_type = $params['discount']['type'];

				// Discount label (informational only)
				$_coupon_code = $discount_type === 'percent'
					? "Discount {$params['discount']['amount']}%"
					: "Discount \${$params['discount']['amount']}";

				// Add discount to order
				$item = new \WC_Order_Item_Fee();
				$item->set_name('Discount');
				$item->set_amount(-$discount_amount);
				$item->set_total(-$discount_amount);
				$order->add_item($item);

				// Store discount meta data
				$order->add_meta_data('_cart_discount', $discount_amount);
				$order->add_meta_data('_cart_discount_type', $discount_type);
				$order->add_meta_data('_cart_discount_amount', $params['discount']['amount']);
			}

			// Set order status
			$status = isset($params['status']) ? $params['status'] : 'wc-pending';
			$order->set_status($status);

			// Set order totals
			if (! empty($params['totals'])) {
				$order->set_total($params['totals']['discount'], 'discount');
				$order->set_total($params['totals']['tax'], 'tax');
				$order->set_total($params['totals']['total'], 'total');
			}

			// Calculate and save
			$order->calculate_totals(false); // false to prevent automatic calculations
			$order->save();

			return new \WP_REST_Response(
				[
					'success' => true,
					'order_id' => $order->get_id(),
					'message' => 'Order created successfully',
				],
				200
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => $e->getMessage(),
				],
				400
			);
		}
	}

	public function wpkin_update_order($request)
	{
		$order_id = absint( $request->get_param('id') );
		$params = $request->get_params();

		try {
			$order = wc_get_order($order_id);

			if (! $order) {
				return new \WP_REST_Response(
					[
						'success' => false,
						'message' => 'Order not found',
					],
					404
				);
			}

			// Update addresses
			$order->set_address($params['billing'], 'billing');
			$order->set_address($params['shipping'], 'shipping');

			// Update payment method
			$order->set_payment_method($params['payment_method']);
			$order->set_payment_method_title($this->wpkin_get_payment_method_title($params['payment_method']));

			// Update status
			$order->set_status($params['status']);

			// Remove existing items
			foreach ($order->get_items() as $item_id => $item) {
				wc_delete_order_item($item_id);
			}

			// Remove existing fee items (like discounts)
			foreach ($order->get_items('fee') as $item_id => $item) {
				wc_delete_order_item($item_id);
			}

			// Set customer note if provided
			if (! empty($params['customer_note'])) {
				$order->set_customer_note($params['customer_note']);
			}

			// Set CMS note as order meta if provided
			if (! empty($params['cms_note'])) {
				$order->update_meta_data('_cms_note', sanitize_textarea_field($params['cms_note']), true);
			}

			// Add new items
			foreach ($params['items'] as $item) {
				if (! empty($item['variation_id'])) {
					$order->add_product(
						wc_get_product($item['variation_id']),
						$item['quantity'],
						[
							'variation' => array_reduce(
								$item['meta_data'],
								function ($acc, $meta) {
									$acc[$meta['key']] = $meta['value'];
									return $acc;
								},
								[]
							),
							'subtotal' => $item['subtotal'],
							'total' => $item['total'],
						]
					);
				} else {
					$order->add_product(
						wc_get_product($item['product_id']),
						$item['quantity'],
						[
							'subtotal' => $item['subtotal'],
							'total' => $item['total'],
						]
					);
				}
			}

			// Handle discount
			if (! empty($params['discount']) && ! empty($params['discount']['value'])) {
				$discount_amount = floatval($params['discount']['value']);

				// Add discount as a fee item
				$fee = new \WC_Order_Item_Fee();
				$fee->set_name('Discount');
				$fee->set_amount(-$discount_amount);
				$fee->set_total(-$discount_amount);
				$order->add_item($fee);

				// Store discount meta data
				$order->update_meta_data('_cart_discount_type', $params['discount']['type']);
				$order->update_meta_data('_cart_discount_amount', $params['discount']['amount']);
			}

			// IMPORTANT: Set all totals explicitly from the frontend calculation
			if (! empty($params['totals'])) {
				$order->set_discount_total($params['totals']['discount']);
				$order->set_cart_tax($params['totals']['tax']);
				$order->set_shipping_total(0);
				$order->set_shipping_tax(0);
				$order->set_total($params['totals']['total']);
			}

			// Save without recalculating
			$order->save();

			// Track who made the update
			$current_user = wp_get_current_user();
			if ( $current_user->ID ) {
				$order->update_meta_data( '_sm_last_updated_by', $current_user->display_name );
				$order->update_meta_data( '_sm_last_updated_date', current_time( 'mysql' ) );
				$order->add_order_note(
					__( 'Order updated.', 'shop-manager' ),
					0,
					true
				);
				$order->save();
			}
			$this->log_order_action( $order->get_id(), 'order_updated' );

			return new \WP_REST_Response(
				[
					'success' => true,
					'order_id' => $order->get_id(),
					'message' => 'Order updated successfully',
				],
				200
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => $e->getMessage(),
				],
				400
			);
		}
	}

	// Add this helper function to get countries
	public function wpkin_get_countries()
	{
		return new \WP_REST_Response(
			[
				'success' => true,
				'data' => WC()->countries->get_countries(),
			],
			200
		);
	}

	// Add this helper function to get states
	public function wpkin_get_states($request)
	{
		$country = $request->get_param('country');
		return new \WP_REST_Response(
			[
				'success' => true,
				'data' => WC()->countries->get_states($country),
			],
			200
		);
	}

	public function wpkin_get_order($request)
	{
		$order_id = absint( $request->get_param('id') );
		$order = wc_get_order($order_id);

		if (! $order) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => 'Order not found',
				],
				404
			);
		}

		try {
			// Get WC_Countries instance for country/state name conversion
			$wc_countries = new \WC_Countries();
			$countries = $wc_countries->get_countries();

			// Get billing country and state full names
			$billing_country_code = $order->get_billing_country();
			$billing_state_code = $order->get_billing_state();
			$billing_country_full = isset($countries[$billing_country_code]) ? $countries[$billing_country_code] : $billing_country_code;

			$billing_states = $wc_countries->get_states($billing_country_code);
			$billing_state_full = isset($billing_states[$billing_state_code]) ? $billing_states[$billing_state_code] : $billing_state_code;

			// Get shipping country and state full names
			$shipping_country_code = $order->get_shipping_country();
			$shipping_state_code = $order->get_shipping_state();
			$shipping_country_full = isset($countries[$shipping_country_code]) ? $countries[$shipping_country_code] : $shipping_country_code;

			$shipping_states = $wc_countries->get_states($shipping_country_code);
			$shipping_state_full = isset($shipping_states[$shipping_state_code]) ? $shipping_states[$shipping_state_code] : $shipping_state_code;

			// Get order items
			$items = [];
			foreach ($order->get_items() as $item_id => $item) {
				$product = wc_get_product($item['variation_id'] ? $item['variation_id'] : $item['product_id']);
				$sku = $product ? $product->get_sku() : '';
				$image_url = wc_placeholder_img_src();

				if ($product) {
					$image_id = $product->get_image_id();
					if ($image_id) {
						$image_url = wp_get_attachment_image_url($image_id, 'thumbnail');
					} elseif ($product->is_type('variation')) {
						// Try to get parent product image if variation has no image
						$parent_product = wc_get_product($product->get_parent_id());
						if ($parent_product) {
							$parent_image_id = $parent_product->get_image_id();
							if ($parent_image_id) {
								$image_url = wp_get_attachment_image_url($parent_image_id, 'thumbnail');
							}
						}
					}
				}

				$item_data = [
					'product_id' => $item['product_id'],
					'variation_id' => $item['variation_id'],
					'name' => $item['name'],
					'quantity' => $item['quantity'],
					'subtotal' => $item['line_subtotal'],
					'total' => $item['line_total'],
					'price' => ($item['quantity'] > 0) ? ($item['line_total'] / $item['quantity']) : 0,
					'sku' => $sku,
					'image_url' => $image_url,
					'meta_data' => [],
				];

				// Get meta data
				$meta_data = wc_get_order_item_meta($item_id, '');
				foreach ($meta_data as $meta_key => $meta_value) {
					if (strpos($meta_key, 'pa_') === 0 || strpos($meta_key, 'attribute_') === 0) {
						$display_key = wc_attribute_label(str_replace('attribute_', '', $meta_key));
						$item_data['meta_data'][] = [
							'key' => $meta_key,
							'value' => is_array($meta_value) ? $meta_value[0] : $meta_value,
							'display_key' => $display_key,
							'display_value' => is_array($meta_value) ? $meta_value[0] : $meta_value,
						];
					}
				}

				$items[] = $item_data;
			}

			// Get order status history
			$order_notes = wc_get_order_notes(
				[
					'order_id' => $order_id,
					'order' => 'DESC',
				]
			);

			$history = [];
			foreach ($order_notes as $note) {
				$history[] = [
					'id' => $note->id,
					'date' => $note->date_created->date('Y-m-d H:i:s'),
					'content' => $note->content,
					'is_customer_note' => (bool) $note->customer_note,
					'added_by' => $note->added_by,
				];
			}

			// Get payment details
			$payment_method = $order->get_payment_method_title();
			$transaction_id = $order->get_transaction_id();
			$payment_date = $order->get_date_paid();
			$payment_status = $order->is_paid() ? 'Paid' : 'Unpaid';

			// Get shipping details
			$shipping_method = $order->get_shipping_method();
			$tracking_number = $order->get_meta('_tracking_number');
			$tracking_url = $order->get_meta('_tracking_url');
			$shipping_carrier = $order->get_meta('_shipping_carrier');
			$estimated_delivery = $order->get_meta('_estimated_delivery');

			// Get discount details
			$coupons = [];
			foreach ($order->get_coupon_codes() as $coupon_code) {
				$coupon = new \WC_Coupon($coupon_code);
				$coupons[] = [
					'code' => $coupon_code,
					'amount' => $coupon->get_amount(),
					'discount_type' => $coupon->get_discount_type(),
				];
			}

			// Get customer information
			$customer_id = $order->get_customer_id();
			$is_guest = empty($customer_id);
			$customer_since = '';
			$order_count = 0;

			if (! $is_guest) {
				$user = get_userdata($customer_id);
				if ($user) {
					$customer_since = $user->user_registered;
					$order_count = wc_get_customer_order_count($customer_id);
				}
			}

			// Get related orders (refunds)
			$refunds = [];
			foreach ($order->get_refunds() as $refund) {
				$refunds[] = [
					'id' => $refund->get_id(),
					'amount' => $refund->get_amount(),
					'reason' => $refund->get_reason(),
					'date' => $refund->get_date_created()->date('Y-m-d H:i:s'),
				];
			}

			$discount_type = $order->get_meta('_cart_discount_type');
			$discount_amount = $order->get_meta('_cart_discount_amount');

			$data = [
				'id' => $order->get_id(),
				'date_created' => $order->get_date_created()->date('Y-m-d H:i:s'),
				'billing' => [
					'first_name' => $order->get_billing_first_name(),
					'last_name' => $order->get_billing_last_name(),
					'company' => $order->get_billing_company(),
					'address_1' => $order->get_billing_address_1(),
					'address_2' => $order->get_billing_address_2(),
					'city' => $order->get_billing_city(),
					'state' => $order->get_billing_state(),
					'state_full' => $billing_state_full,
					'postcode' => $order->get_billing_postcode(),
					'country' => $order->get_billing_country(),
					'country_full' => $billing_country_full,
					'email' => $order->get_billing_email(),
					'phone' => $order->get_billing_phone(),
				],
				'shipping' => [
					'first_name' => $order->get_shipping_first_name(),
					'last_name' => $order->get_shipping_last_name(),
					'company' => $order->get_shipping_company(),
					'address_1' => $order->get_shipping_address_1(),
					'address_2' => $order->get_shipping_address_2(),
					'city' => $order->get_shipping_city(),
					'state' => $order->get_shipping_state(),
					'state_full' => $shipping_state_full,
					'postcode' => $order->get_shipping_postcode(),
					'country' => $order->get_shipping_country(),
					'country_full' => $shipping_country_full,
				],
				'payment' => [
					'method' => $payment_method,
					'transaction_id' => $transaction_id,
					'date' => $payment_date ? $payment_date->date('Y-m-d H:i:s') : '',
					'status' => $payment_status,
				],
				'shipping_details' => [
					'method' => $shipping_method,
					'tracking_number' => $tracking_number,
					'tracking_url' => $tracking_url,
					'carrier' => $shipping_carrier,
					'estimated_delivery' => $estimated_delivery,
				],
				'customer' => [
					'id' => $customer_id,
					'is_guest' => $is_guest,
					'since' => $customer_since,
					'order_count' => $order_count,
				],
				'payment_method' => $order->get_payment_method_title(),
				'shipping_method' => $order->get_shipping_method(),
				'status' => 'wc-' . $order->get_status('edit'),
				'items' => $items,
				'customer_note' => $order->get_customer_note(),
				'cms_note' => $order->get_meta('_cms_note', true),
				'order_history' => $history,
				'coupons' => $coupons,
				'refunds' => $refunds,
				'totals' => [
					'subtotal' => $order->get_subtotal(),
					'discount' => $order->get_total_discount(),
					'tax' => $order->get_total_tax(),
					'shipping' => $order->get_shipping_total(),
					'total' => $order->get_total(),
				],
				'discount' => [
					'type' => empty($discount_type) ? 'flat' : $discount_type,
					'amount' => empty($discount_amount) ? 0 : floatval($discount_amount),
					'value' => wc_format_decimal($order->get_total_discount(), 2),
				],
			];

			return new \WP_REST_Response(
				[
					'success' => true,
					'order' => $data,
				],
				200
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => $e->getMessage(),
				],
				500
			);
		}
	}

	public function wpkin_sm_delete_order($request)
	{
		$order_id = $request['id'];

		try {
			// Get the order
			$order = wc_get_order($order_id);

			if (! $order) {
				return new \WP_REST_Response(
					[
						'success' => false,
						'message' => 'Order not found',
					],
					404
				);
			}

			// Check if order is already in trash
			if ($order->get_status() === 'trash') {
				return new \WP_REST_Response(
					[
						'success' => false,
						'message' => 'Order is already in trash',
					],
					400
				);
			}

			// Add an order note before deletion
			$order->add_order_note(
				sprintf(
					'Order #%s moved to trash by %s',
					$order->get_order_number(),
					wp_get_current_user()->display_name
				),
				0,
				true
			);

			// Move the order to trash
			$order->set_status('trash');
			$order->save();

			// Update the post status directly
			wp_update_post(
				[
					'ID' => $order_id,
					'post_status' => 'trash',
				]
			);

			// Clear caches
			clean_post_cache($order_id);
			wc_delete_shop_order_transients($order_id);

			return new \WP_REST_Response(
				[
					'success' => true,
					'message' => 'Order successfully moved to trash',
					'data' => [
						'order_id' => $order_id,
					],
				],
				200
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => $e->getMessage(),
				],
				500
			);
		}
	}

	// Add these functions to your AdminApi class
	public function wpkin_sm_get_dashboard_stats( $request ) {
		$period    = sanitize_text_field( $request->get_param( 'period' ) ?: 'month' );
		$date_from = sanitize_text_field( $request->get_param( 'date_from' ) ?: '' );
		$date_to   = sanitize_text_field( $request->get_param( 'date_to' ) ?: '' );

		// Resolve current period date range
		switch ( $period ) {
			case 'today':
				$from = gmdate( 'Y-m-d' );
				$to   = gmdate( 'Y-m-d' );
				break;
			case 'week':
				$from = gmdate( 'Y-m-d', strtotime( 'monday this week' ) );
				$to   = gmdate( 'Y-m-d' );
				break;
			case 'year':
				$from = gmdate( 'Y-01-01' );
				$to   = gmdate( 'Y-m-d' );
				break;
			case 'lifetime':
				$from = '2000-01-01';
				$to   = gmdate( 'Y-m-d' );
				break;
			case 'custom':
				$from = $date_from ?: gmdate( 'Y-m-01' );
				$to   = $date_to   ?: gmdate( 'Y-m-d' );
				break;
			default: // month
				$period = 'month';
				$from   = gmdate( 'Y-m-01' );
				$to     = gmdate( 'Y-m-d' );
		}

		$cache_key = 'wpkin_sm_dashboard_' . $period . '_' . $from . '_' . $to;
		$cached    = get_transient( $cache_key );
		if ( false !== $cached ) {
			return new \WP_REST_Response( $cached, 200 );
		}

		// All registered statuses including custom ones, excluding trash/cancelled
		$excluded_statuses = [ 'trash', 'auto-draft', 'cancelled', 'failed', 'refunded' ];
		$all_statuses      = array_diff( array_keys( wc_get_order_statuses() ), array_map( fn( $s ) => 'wc-' . $s, $excluded_statuses ) );
		// Also include custom statuses registered in plugin settings
		$custom_statuses = get_option( 'wpkin_sm_admin_settings', [] )['orders']['custom_statuses'] ?? [];
		foreach ( $custom_statuses as $cs ) {
			if ( ! empty( $cs['id'] ) ) {
				$all_statuses[] = 'wc-' . $cs['id'];
			}
		}
		$all_statuses = array_values( array_unique( $all_statuses ) );

		// Fetch orders for current period (lifetime = no date filter)
		$order_query_args = [ 'status' => $all_statuses, 'limit' => -1, 'return' => 'objects' ];
		if ( $period !== 'lifetime' ) {
			$order_query_args['date_created'] = $from . '...' . $to;
		}
		$orders = wc_get_orders( $order_query_args );

		// Previous period (not applicable for lifetime)
		$prev_orders = [];
		if ( $period !== 'lifetime' ) {
			$days_diff   = (int) ceil( ( strtotime( $to ) - strtotime( $from ) ) / DAY_IN_SECONDS ) + 1;
			$prev_from   = gmdate( 'Y-m-d', strtotime( $from ) - $days_diff * DAY_IN_SECONDS );
			$prev_to     = gmdate( 'Y-m-d', strtotime( $from ) - DAY_IN_SECONDS );
			$prev_orders = wc_get_orders( [
				'date_created' => $prev_from . '...' . $prev_to,
				'status'       => $all_statuses,
				'limit'        => -1,
				'return'       => 'objects',
			] );
		}

		// ── KPIs ─────────────────────────────────────────────────────────────────
		$revenue     = 0.0;
		$prev_revenue = 0.0;
		foreach ( $orders as $o )      { $revenue      += (float) $o->get_total(); }
		foreach ( $prev_orders as $o ) { $prev_revenue += (float) $o->get_total(); }

		$order_count      = count( $orders );
		$prev_order_count = count( $prev_orders );
		$avg_order        = $order_count > 0 ? $revenue / $order_count : 0.0;
		$prev_avg         = $prev_order_count > 0 ? $prev_revenue / $prev_order_count : 0.0;

		$pct = static function ( $curr, $prev ) {
			if ( $prev == 0 ) { return $curr > 0 ? 100.0 : 0.0; }
			return round( ( $curr - $prev ) / $prev * 100, 1 );
		};

		// New customers registered in period
		$new_customers = ( new \WP_User_Query( [
			'fields'       => 'ID',
			'number'       => -1,
			'count_total'  => false,
			'date_query'   => [ [ 'after' => $from, 'before' => $to, 'inclusive' => true ] ],
			'role__not_in' => [ 'administrator', 'editor', 'shop_manager' ],
		] ) )->get_results();
		$prev_new_customers = ( new \WP_User_Query( [
			'fields'       => 'ID',
			'number'       => -1,
			'count_total'  => false,
			'date_query'   => [ [ 'after' => $prev_from, 'before' => $prev_to, 'inclusive' => true ] ],
			'role__not_in' => [ 'administrator', 'editor', 'shop_manager' ],
		] ) )->get_results();

		$kpis = [
			'revenue'         => [
				'value'      => round( $revenue, 2 ),
				'formatted'  => html_entity_decode( strip_tags( wc_price( $revenue ) ), ENT_QUOTES | ENT_HTML5, 'UTF-8' ),
				'change_pct' => $pct( $revenue, $prev_revenue ),
			],
			'orders'          => [
				'count'      => $order_count,
				'change_pct' => $pct( $order_count, $prev_order_count ),
			],
			'avg_order_value' => [
				'value'      => round( $avg_order, 2 ),
				'formatted'  => html_entity_decode( strip_tags( wc_price( $avg_order ) ), ENT_QUOTES | ENT_HTML5, 'UTF-8' ),
				'change_pct' => $pct( $avg_order, $prev_avg ),
			],
			'new_customers'   => [
				'count'      => count( $new_customers ),
				'change_pct' => $pct( count( $new_customers ), count( $prev_new_customers ) ),
			],
		];

		// ── Revenue chart ─────────────────────────────────────────────────────────
		$daily_revenue = [];
		$daily_orders  = [];

		if ( $period === 'today' ) {
			// Hourly buckets for today
			for ( $h = 0; $h < 24; $h++ ) {
				$label = str_pad( $h, 2, '0', STR_PAD_LEFT ) . ':00';
				$daily_revenue[ $label ] = 0.0;
				$daily_orders[ $label ]  = 0;
			}
			foreach ( $orders as $o ) {
				$date = $o->get_date_created();
				if ( ! $date ) { continue; }
				$label = $date->date( 'H' ) . ':00';
				$daily_revenue[ $label ] = ( $daily_revenue[ $label ] ?? 0.0 ) + (float) $o->get_total();
				$daily_orders[ $label ]  = ( $daily_orders[ $label ] ?? 0 ) + 1;
			}
		} else {
			// Daily buckets
			$cur = strtotime( $from );
			$end = strtotime( $to );
			while ( $cur <= $end ) {
				$d = gmdate( 'Y-m-d', $cur );
				$daily_revenue[ $d ] = 0.0;
				$daily_orders[ $d ]  = 0;
				$cur = strtotime( '+1 day', $cur );
			}
			foreach ( $orders as $o ) {
				$date = $o->get_date_created();
				if ( ! $date ) { continue; }
				$d = $date->date( 'Y-m-d' );
				if ( isset( $daily_revenue[ $d ] ) ) {
					$daily_revenue[ $d ] += (float) $o->get_total();
					$daily_orders[ $d ]  += 1;
				}
			}
		}

		$revenue_chart = [];
		foreach ( $daily_revenue as $d => $amt ) {
			$revenue_chart[] = [
				'date'    => $d,
				'revenue' => round( $amt, 2 ),
				'orders'  => $daily_orders[ $d ],
			];
		}

		// ── Orders by status ──────────────────────────────────────────────────────
		$status_colors = [
			'pending'    => '#faad14',
			'processing' => '#7b5ea7',
			'on-hold'    => '#d48806',
			'completed'  => '#5b841b',
			'cancelled'  => '#cf1322',
			'refunded'   => '#096dd9',
			'failed'     => '#820014',
		];
		// Merge custom status colors from settings
		$custom_statuses = get_option( 'wpkin_sm_admin_settings', [] )['orders']['custom_statuses'] ?? [];
		foreach ( $custom_statuses as $cs ) {
			if ( ! empty( $cs['id'] ) && ! empty( $cs['colors']['background'] ) ) {
				$status_colors[ $cs['id'] ] = $cs['colors']['background'];
			}
		}

		// Orders by status — respects the selected period (lifetime = no date filter)
		$status_query_args = [
			'status'  => $all_statuses,
			'limit'   => -1,
			'return'  => 'ids',
		];
		if ( $period !== 'lifetime' ) {
			$status_query_args['date_created'] = $from . '...' . $to;
		}
		$all_orders_for_status = wc_get_orders( $status_query_args );
		$status_counts = [];
		foreach ( $all_orders_for_status as $oid ) {
			$o = wc_get_order( $oid );
			if ( ! $o ) { continue; }
			$s = $o->get_status();
			$status_counts[ $s ] = ( $status_counts[ $s ] ?? 0 ) + 1;
		}
		$wc_labels        = wc_get_order_statuses();
		$orders_by_status = [];
		foreach ( $status_counts as $s => $cnt ) {
			$label = $wc_labels[ 'wc-' . $s ] ?? ucfirst( str_replace( '-', ' ', $s ) );
			$orders_by_status[] = [
				'status' => $s,
				'label'  => $label,
				'count'  => $cnt,
				'color'  => $status_colors[ $s ] ?? '#8884d8',
			];
		}

		// ── Top products ──────────────────────────────────────────────────────────
		$product_data = [];
		foreach ( $orders as $o ) {
			foreach ( $o->get_items() as $item ) {
				$pid = $item->get_product_id();
				if ( ! $pid ) { continue; }
				if ( ! isset( $product_data[ $pid ] ) ) {
					$product_data[ $pid ] = [
						'id'       => $pid,
						'name'     => $item->get_name(),
						'qty_sold' => 0,
						'revenue'  => 0.0,
					];
				}
				$product_data[ $pid ]['qty_sold'] += (int) $item->get_quantity();
				$product_data[ $pid ]['revenue']  += (float) $item->get_total();
			}
		}
		usort( $product_data, fn( $a, $b ) => $b['revenue'] <=> $a['revenue'] );
		$top_products = [];
		foreach ( array_slice( $product_data, 0, 5 ) as $p ) {
			$top_products[] = [
				'id'                => $p['id'],
				'name'              => $p['name'],
				'qty_sold'          => $p['qty_sold'],
				'revenue'           => round( $p['revenue'], 2 ),
				'formatted_revenue' => html_entity_decode( strip_tags( wc_price( $p['revenue'] ) ), ENT_QUOTES | ENT_HTML5, 'UTF-8' ),
			];
		}

		// ── Recent orders ─────────────────────────────────────────────────────────
		$recent_raw = wc_get_orders( [
			'limit'   => 5,
			'orderby' => 'date',
			'order'   => 'DESC',
			'return'  => 'objects',
		] );
		$recent_orders = [];
		foreach ( $recent_raw as $o ) {
			$s             = $o->get_status();
			$s_color       = $status_colors[ $s ] ?? '#8884d8';
			$s_label       = $wc_labels[ 'wc-' . $s ] ?? ucfirst( str_replace( '-', ' ', $s ) );
			$created       = $o->get_date_created();
			$diff          = $created ? ( time() - $created->getTimestamp() ) : 0;
			if ( $diff < 3600 )        { $ago = round( $diff / 60 ) . ' minutes ago'; }
			elseif ( $diff < 86400 )   { $ago = round( $diff / 3600 ) . ' hours ago'; }
			else                        { $ago = round( $diff / 86400 ) . ' days ago'; }

			$first = $o->get_billing_first_name();
			$last  = $o->get_billing_last_name();
			$name  = trim( "$first $last" ) ?: __( 'Guest', 'shop-manager' );

			$recent_orders[] = [
				'id'           => $o->get_id(),
				'number'       => '#' . $o->get_order_number(),
				'customer_name'=> $name,
				'total'        => html_entity_decode( strip_tags( wc_price( $o->get_total() ) ), ENT_QUOTES | ENT_HTML5, 'UTF-8' ),
				'status'       => $s,
				'status_label' => $s_label,
				'status_color' => $s_color,
				'date'         => $ago,
			];
		}

		$payload = [
			'success'          => true,
			'kpis'             => $kpis,
			'revenue_chart'    => $revenue_chart,
			'orders_by_status' => $orders_by_status,
			'top_products'     => $top_products,
			'recent_orders'    => $recent_orders,
		];

		set_transient( $cache_key, $payload, 2 * MINUTE_IN_SECONDS );

		return new \WP_REST_Response( $payload, 200 );
	}

	/**
	 * GET /insights — return rule-based insight cards.
	 */
	public function wpkin_sm_get_insights( $_request = null ) {
		$insights     = \WPKIN_SHOP_MANAGER\Modules\InsightEngine::get_insights();
		$dismissed    = get_user_meta( get_current_user_id(), '_sm_dismissed_insights', true );
		$has_dismissed = ! empty( $dismissed ) && is_array( $dismissed ) &&
			count( array_filter( $dismissed, fn( $d ) => $d['dismissed_until'] > time() ) ) > 0;
		return new \WP_REST_Response( [ 'success' => true, 'insights' => $insights, 'has_dismissed' => $has_dismissed ], 200 );
	}

	/**
	 * POST /insights/{id}/dismiss — dismiss an insight for 24 hours.
	 */
	public function wpkin_sm_dismiss_insight( $request ) {
		$id = sanitize_key( $request->get_param( 'id' ) );
		\WPKIN_SHOP_MANAGER\Modules\InsightEngine::dismiss( $id );
		return new \WP_REST_Response( [ 'success' => true ], 200 );
	}

	/**
	 * POST /insights/reset-dismissed — clear all dismissed insights for current user.
	 */
	public function wpkin_sm_reset_dismissed_insights( $_request = null ) {
		delete_user_meta( get_current_user_id(), '_sm_dismissed_insights' );
		return new \WP_REST_Response( [ 'success' => true ], 200 );
	}

	/**
	 * Clear dashboard transient cache on new order.
	 */
	public function wpkin_sm_clear_dashboard_cache() {
		foreach ( [ 'today', 'week', 'month', 'year' ] as $p ) {
			switch ( $p ) {
				case 'today': $f = gmdate( 'Y-m-d' ); $t = gmdate( 'Y-m-d' ); break;
				case 'week':  $f = gmdate( 'Y-m-d', strtotime( 'monday this week' ) ); $t = gmdate( 'Y-m-d' ); break;
				case 'year':  $f = gmdate( 'Y-01-01' ); $t = gmdate( 'Y-m-d' ); break;
				default:      $f = gmdate( 'Y-m-01' ); $t = gmdate( 'Y-m-d' );
			}
			delete_transient( 'wpkin_sm_dashboard_' . $p . '_' . $f . '_' . $t );
		}
	}

	public function wpkin_sm_handle_search($request)
	{
		try {
			$search_query = trim($request->get_param('q'));
			if (empty($search_query)) {
				return new \WP_REST_Response(
					[
						'success' => false,
						'message' => 'Search query is required',
					],
					400
				);
			}

			$page = max(1, intval($request->get_param('page')));
			$per_page = max(1, intval($request->get_param('per_page')));

			$results = $this->wpkin_search_orders($search_query, $page, $per_page);

			return new \WP_REST_Response(
				[
					'success' => true,
					'results' => $results,
				]
			);
		} catch (\Exception $e) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => 'Error performing search: ' . $e->getMessage(),
				],
				500
			);
		}
	}

	/**
	 * Get products with filtering capabilities
	 */
	public function wpkin_sm_get_products(\WP_REST_Request $request)
	{
		$page     = $request->get_param('page')     ? intval($request->get_param('page'))     : 1;
		$per_page = $request->get_param('per_page') ? intval($request->get_param('per_page')) : 10;

		// Sort mapping
		$orderby_map = [
			'date'       => [ 'orderby' => 'date',       'order' => 'DESC' ],
			'price_asc'  => [ 'orderby' => 'meta_value_num', 'meta_key' => '_price', 'order' => 'ASC'  ],
			'price_desc' => [ 'orderby' => 'meta_value_num', 'meta_key' => '_price', 'order' => 'DESC' ],
			'title'      => [ 'orderby' => 'title',      'order' => 'ASC'  ],
			'popularity' => [ 'orderby' => 'meta_value_num', 'meta_key' => 'total_sales', 'order' => 'DESC' ],
		];
		$sort_key   = sanitize_text_field( $request->get_param('orderby') ?? 'date' );
		$sort_args  = $orderby_map[ $sort_key ] ?? $orderby_map['date'];

		// Basic query args — include all non-trash statuses
		$args = array_merge( [
			'post_type'      => 'product',
			'post_status'    => [ 'publish', 'draft', 'pending', 'private' ],
			'posts_per_page' => $per_page,
			'paged'          => $page,
		], $sort_args );

		// Search filter
		if ($request->get_param('search')) {
			$args['s'] = sanitize_text_field($request->get_param('search'));
		}

		// Initialize tax_query and meta_query arrays
		$args['tax_query'] = [];
		$args['meta_query'] = [];

		// Category filter
		if ($request->get_param('category')) {
			$categories = explode(',', $request->get_param('category'));
			$args['tax_query'][] = [
				'taxonomy' => 'product_cat',
				'field'    => 'term_id',
				'terms'    => array_map('intval', $categories),
			];
		}

		// Product type filter
		if ($request->get_param('product_type')) {
			$product_types = explode(',', $request->get_param('product_type'));
			$args['tax_query'][] = [
				'taxonomy' => 'product_type',
				'field'    => 'slug',
				'terms'    => array_map('sanitize_text_field', $product_types),
			];
		}

		// Tag filter
		if ($request->get_param('tag')) {
			$tags = explode(',', $request->get_param('tag'));
			$args['tax_query'][] = [
				'taxonomy' => 'product_tag',
				'field'    => 'term_id',
				'terms'    => array_map('intval', $tags),
			];
		}

		// Stock status + low stock filters — combined with OR so selecting multiple works correctly
		$stock_conditions = [];

		if ($request->get_param('stock_status')) {
			$stock_statuses       = explode(',', $request->get_param('stock_status'));
			$stock_conditions[] = [
				'key'     => '_stock_status',
				'value'   => array_map('sanitize_text_field', $stock_statuses),
				'compare' => 'IN',
			];
		}

		if ($request->get_param('low_stock') === 'yes') {
			$low_stock_threshold = (int) get_option( 'woocommerce_notify_low_stock_amount', 5 );
			$stock_conditions[]  = [
				'relation' => 'AND',
				[
					'key'     => '_manage_stock',
					'value'   => 'yes',
					'compare' => '=',
				],
				[
					'key'     => '_stock',
					'value'   => $low_stock_threshold,
					'compare' => '<=',
					'type'    => 'NUMERIC',
				],
				[
					'key'     => '_stock',
					'value'   => 0,
					'compare' => '>',
					'type'    => 'NUMERIC',
				],
			];
		}

		if (count($stock_conditions) === 1) {
			$args['meta_query'][] = $stock_conditions[0];
		} elseif (count($stock_conditions) > 1) {
			$args['meta_query'][] = array_merge(['relation' => 'OR'], $stock_conditions);
		}

		// Virtual product filter
		if ($request->get_param('is_virtual') === 'yes') {
			$args['meta_query'][] = [
				'key'     => '_virtual',
				'value'   => 'yes',
				'compare' => '=',
			];
		}

		// Downloadable product filter
		if ($request->get_param('is_downloadable') === 'yes') {
			$args['meta_query'][] = [
				'key'     => '_downloadable',
				'value'   => 'yes',
				'compare' => '=',
			];
		}

		// Brand filter (assuming you have a brand taxonomy or meta field)
		if ($request->get_param('brand')) {
			$brands = explode(',', $request->get_param('brand'));

			// If brand is a taxonomy
			if (taxonomy_exists('product_brand')) {
				$args['tax_query'][] = [
					'taxonomy' => 'product_brand',
					'field'    => 'term_id',
					'terms'    => array_map('intval', $brands),
				];
			} else {
				$args['meta_query'][] = [
					'key'     => 'brand',
					'value'   => array_map('sanitize_text_field', $brands),
					'compare' => 'IN',
				];
			}
		}

		// Price range filter
		if ($request->get_param('min_price') && $request->get_param('max_price')) {
			$args['meta_query'][] = [
				'key'     => '_price',
				'value'   => [
					floatval($request->get_param('min_price')),
					floatval($request->get_param('max_price')),
				],
				'type'    => 'NUMERIC',
				'compare' => 'BETWEEN',
			];
		} elseif ($request->get_param('min_price')) {
			$args['meta_query'][] = [
				'key'     => '_price',
				'value'   => floatval($request->get_param('min_price')),
				'type'    => 'NUMERIC',
				'compare' => '>=',
			];
		} elseif ($request->get_param('max_price')) {
			$args['meta_query'][] = [
				'key'     => '_price',
				'value'   => floatval($request->get_param('max_price')),
				'type'    => 'NUMERIC',
				'compare' => '<=',
			];
		}

		// Date range filter
		if ($request->get_param('date_from') && $request->get_param('date_to')) {
			$args['date_query'] = [
				[
					'after'     => sanitize_text_field($request->get_param('date_from')),
					'before'    => sanitize_text_field($request->get_param('date_to')),
					'inclusive' => true,
				],
			];
		}

		// If we have any filter parameters, also return filter options
		$include_filter_options = false;
		$filter_params = [
			'search',
			'category',
			'product_type',
			'stock_status',
			'brand',
			'tag',
			'min_price',
			'max_price',
			'date_from',
			'date_to',
			'is_virtual',
			'is_downloadable',
		];

		foreach ($filter_params as $param) {
			if ($request->get_param($param)) {
				$include_filter_options = true;
				break;
			}
		}

		// Run the query
		$query = new \WP_Query($args);
		$products = [];
		$total_products = $query->found_posts;

		if ($query->have_posts()) {
			while ($query->have_posts()) {
				$query->the_post();
				global $product;

				if (! $product || ! is_a($product, 'WC_Product')) {
					continue;
				}

				// Get product attributes
				$is_virtual = $product->is_virtual() ? 'yes' : 'no';
				$is_downloadable = $product->is_downloadable() ? 'yes' : 'no';

				$brand     = get_post_meta(get_the_ID(), 'brand', true);
				$thumbnail = get_the_post_thumbnail_url(get_the_ID(), 'thumbnail');

				$products[] = [
					'id'              => get_the_ID(),
					'name'            => get_the_title(),
					'sku'             => $product->get_sku(),
					'status'          => get_post_status( get_the_ID() ),
					'stock'           => $product->is_in_stock() ? 'instock' : 'outofstock',
					'stock_quantity'  => $product->get_stock_quantity(),
					'price'           => $product->get_price(),
					'type'            => $product->get_type(),
					'categories'      => wc_get_product_category_list(get_the_ID(), ', '),
					'tags'            => wc_get_product_tag_list(get_the_ID(), ', '),
					'brand'           => $brand ? $brand : __('N/A', 'shop-manager'),
					'date'            => get_the_date('Y-m-d'),
					'image'           => $thumbnail ? $thumbnail : wc_placeholder_img_src(),
					'is_virtual'      => $is_virtual,
					'is_downloadable' => $is_downloadable,
					'description'     => wp_trim_words(get_the_excerpt(), 30, '...'),
					'permalink'       => get_permalink( get_the_ID() ),
				];
			}
			wp_reset_postdata();
		}

		$response = [
			'products'    => $products,
			'total'       => (int) $total_products,
			'per_page'    => $per_page,
			'page'        => $page,
			'total_pages' => ceil($total_products / $per_page),
		];

		// Include filter options if requested or if any filter is applied
		if ($include_filter_options || $request->get_param('include_filter_options')) {
			$response['filter_options'] = $this->wpkin_get_product_filter_options();
		}

		return rest_ensure_response($response);
	}

	/**
	 * Delete products (single or bulk)
	 *
	 * @param WP_REST_Request $request Request object
	 * @return WP_REST_Response Response object
	 */
	public function wpkin_sm_duplicate_product( \WP_REST_Request $request ) {
		$id      = (int) $request->get_param( 'id' );
		$product = wc_get_product( $id );

		if ( ! $product ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => __( 'Product not found.', 'shop-manager' ) ], 404 );
		}

		// Create new product post as draft
		$new_id = wp_insert_post( [
			'post_title'   => $product->get_name() . ' (Copy)',
			'post_content' => $product->get_description(),
			'post_excerpt' => $product->get_short_description(),
			'post_status'  => 'draft',
			'post_type'    => 'product',
			'post_author'  => get_current_user_id(),
		] );

		if ( is_wp_error( $new_id ) || ! $new_id ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => __( 'Failed to duplicate product.', 'shop-manager' ) ], 500 );
		}

		// Copy all post meta
		foreach ( get_post_meta( $id ) as $key => $values ) {
			foreach ( $values as $value ) {
				add_post_meta( $new_id, $key, maybe_unserialize( $value ) );
			}
		}
		// Reset SKU to avoid conflicts
		update_post_meta( $new_id, '_sku', '' );

		// Copy all taxonomies (categories, tags, attributes etc.)
		foreach ( get_object_taxonomies( 'product' ) as $tax ) {
			$terms = wp_get_object_terms( $id, $tax, [ 'fields' => 'ids' ] );
			if ( ! is_wp_error( $terms ) ) {
				wp_set_object_terms( $new_id, $terms, $tax );
			}
		}

		// Clear product cache so WooCommerce picks up the new product properly
		wc_delete_product_transients( $new_id );
		clean_post_cache( $new_id );

		$this->log_employee_action( 'product_duplicated', [
			'product_id'   => $new_id,
			'product_name' => $product->get_name(),
			'original_id'  => $id,
		] );

		return new \WP_REST_Response( [
			'success'    => true,
			'message'    => __( 'Product duplicated successfully.', 'shop-manager' ),
			'product_id' => $new_id,
		], 200 );
	}

	public function wpkin_sm_delete_products(\WP_REST_Request $request)
	{
		$product_ids = $request->get_param('product_ids');

		if (empty($product_ids) || ! is_array($product_ids)) {
			return rest_ensure_response(
				[
					'success' => false,
					'message' => __('No products specified for deletion', 'shop-manager'),
				]
			);
		}

		$deleted = [];
		$failed = [];

		// Process each product
		foreach ($product_ids as $product_id) {
			$product_id = intval($product_id);
			$product = wc_get_product($product_id);

			if (! $product) {
				$failed[] = $product_id;
				continue;
			}

			// Check if current user can delete this product
			if (! current_user_can('delete_post', $product_id)) {
				$failed[] = $product_id;
				continue;
			}

			// Get product name before deletion for the response
			$product_name = $product->get_name();

			// Delete the product
			$result = wp_delete_post($product_id, true);

			if ($result) {
				$deleted[] = [
					'id' => $product_id,
					'name' => $product_name,
				];
				$this->log_employee_action( 'product_deleted', [
					'product_id'   => $product_id,
					'product_name' => $product_name,
				] );
			} else {
				$failed[] = $product_id;
			}
		}

		// Prepare the response
		$total_requested = count($product_ids);
		$total_deleted = count($deleted);
		$total_failed = count($failed);

		if ($total_deleted === 0) {
			return rest_ensure_response(
				[
					'success' => false,
					'message' => __('Failed to delete products', 'shop-manager'),
					'failed' => $failed,
				]
			);
		}

		// Success message based on single or bulk operation
		$message = $total_requested === 1
			? __('Product deleted successfully', 'shop-manager')
			: sprintf('%d' . __(' products deleted successfully', 'shop-manager'), $total_deleted);

		// Add note about failures if any
		if ($total_failed > 0) {
			$message .= ' ' . sprintf('%d' . __('( failed)', 'shop-manager'), $total_failed);
		}

		return rest_ensure_response(
			[
				'success' => true,
				'message' => $message,
				'deleted' => $deleted,
				'failed' => $failed,
				'total_deleted' => $total_deleted,
				'total_failed' => $total_failed,
			]
		);
	}

	/**
	 * Create a new WooCommerce product via REST API
	 *
	 * @param \WP_REST_Request $request The request object.
	 * @return array|\WP_Error Success response or error.
	 */
	public function wpkin_sm_add_product(\WP_REST_Request $request)
	{
		// Get request parameters
		$params = $request->get_params();

		// Basic validation
		if (empty($params['name'])) {
			return new \WP_Error('missing_name', __('Product name is required', 'shop-manager'), ['status' => 400]);
		}

		try {
			// Start transaction if supported
			global $wpdb;
			$wpdb->query('START TRANSACTION');

			// Prepare product data
			$product_data = [
				'post_title'   => sanitize_text_field($params['name']),
				'post_content' => isset($params['description']) ? wp_kses_post($params['description']) : '',
				'post_excerpt' => isset($params['short_description']) ? wp_kses_post($params['short_description']) : '',
				'post_status'  => isset($params['status']) ? sanitize_text_field($params['status']) : 'publish',
				'post_type'    => 'product',
			];

			// Create the product post
			$product_id = wp_insert_post($product_data, true);

			if (is_wp_error($product_id)) {
				throw new \Exception($product_id->get_error_message());
			}

			// Determine product type
			$product_type = isset($params['product_type']) ? sanitize_text_field($params['product_type']) : 'simple';
			$valid_types = ['simple', 'grouped', 'external', 'variable'];

			if (! in_array($product_type, $valid_types)) {
				throw new \Exception(__('Invalid product type. Must be one of: simple, grouped, external, variable', 'shop-manager'));
			}

			// Set product type
			wp_set_object_terms($product_id, $product_type, 'product_type');

			// Create initial product object to save the product type
			$product = wc_get_product($product_id);
			if (! $product) {
				throw new \Exception(__('Failed to create product object', 'shop-manager'));
			}

			// Save product to commit the product type
			$product->save();

			// For variable products, recreate the product object to ensure proper type
			if ($product_type === 'variable') {
				$product = new \WC_Product_Variable($product_id);
			}

			// Set product data
			if (isset($params['regular_price'])) {
				$regular_price = wc_format_decimal($params['regular_price']);
				if ($regular_price < 0) {
					throw new \Exception(__('Regular price cannot be negative', 'shop-manager'));
				}
				$product->set_regular_price($regular_price);
			}

			if (isset($params['regular_price'])) {
				$sale_price = wc_format_decimal($params['sale_price']);

				// Validate sale price is not greater than regular price if both are set
				if (isset($params['regular_price']) && $sale_price > wc_format_decimal($params['regular_price'])) {
					throw new \Exception(__('Sale price cannot be greater than regular price', 'shop-manager'));
				}

				$product->set_sale_price($sale_price);
			}

			// Sale date range
			if (! empty($params['sale_date_from'])) {
				$product->set_date_on_sale_from(sanitize_text_field($params['sale_date_from']));
			}

			if (! empty($params['sale_date_to'])) {
				$product->set_date_on_sale_to(sanitize_text_field($params['sale_date_to']));
			}

			// SKU
			if (isset($params['sku'])) {
				$sku = trim(sanitize_text_field($params['sku']));

				// Only check for duplicates if SKU is not empty
				if ($sku !== '') {
					// Check if SKU is unique
					$existing_product = wc_get_product_id_by_sku($sku);
					if ($existing_product && $existing_product !== $product_id) {
						throw new \Exception(sprintf(__('Product SKU must be unique. %s is already in use', 'shop-manager'), $sku));
					}
				}

				$product->set_sku($sku);
			}

			// GTIN/UPC/EAN/ISBN
			if (isset($params['global_unique_id'])) {
				$gtin = sanitize_text_field($params['global_unique_id']);
				// Use the correct meta key for GTIN
				$product->update_meta_data('_global_unique_id', $gtin);
			}

			// Inventory
			if (isset($params['manage_stock'])) {
				$manage_stock = (bool) ($params['manage_stock'] === 'yes' || $params['manage_stock'] === true);
				$product->set_manage_stock($manage_stock);

				if ($manage_stock) {
					if (isset($params['stock_quantity'])) {
						$stock_quantity = absint($params['stock_quantity']);
						$product->set_stock_quantity($stock_quantity);
					}

					if (isset($params['backorders'])) {
						$backorders = sanitize_text_field($params['backorders']);
						$valid_backorders = ['no', 'notify', 'yes'];

						if (! in_array($backorders, $valid_backorders)) {
							throw new \Exception(__('Invalid backorders value. Must be one of: no, notify, yes', 'shop-manager'));
						}

						$product->set_backorders($backorders);
					}
				}
			}

			if (isset($params['stock_status'])) {
				$stock_status = sanitize_text_field($params['stock_status']);
				$valid_statuses = ['instock', 'outofstock', 'onbackorder'];

				if (! in_array($stock_status, $valid_statuses)) {
					throw new \Exception(__('Invalid stock status. Must be one of: instock, outofstock, onbackorder', 'shop-manager'));
				}

				$product->set_stock_status($stock_status);
			}

			// Sold individually
			if (isset($params['sold_individually'])) {
				$product->set_sold_individually($params['sold_individually'] === 'yes' || $params['sold_individually'] === true);
			}

			// Shipping
			if (isset($params['weight'])) {
				$product->set_weight(wc_format_decimal(sanitize_text_field($params['weight'])));
			}

			if (isset($params['length'])) {
				$product->set_length(wc_format_decimal(sanitize_text_field($params['length'])));
			}

			if (isset($params['width'])) {
				$product->set_width(wc_format_decimal(sanitize_text_field($params['width'])));
			}

			if (isset($params['height'])) {
				$product->set_height(wc_format_decimal(sanitize_text_field($params['height'])));
			}

			if (isset($params['shipping_class_id'])) {
				$shipping_class_id = absint($params['shipping_class_id']);

				// Verify shipping class exists
				if ($shipping_class_id > 0 && ! term_exists($shipping_class_id, 'product_shipping_class')) {
					throw new \Exception(__('Invalid shipping class ID', 'shop-manager'));
				}

				$product->set_shipping_class_id($shipping_class_id);
			}

			// Virtual
			if (isset($params['virtual'])) {
				$product->set_virtual($params['virtual'] === 'yes' || $params['virtual'] === true);
			}

			// Downloadable
			if (isset($params['downloadable'])) {
				$is_downloadable = $params['downloadable'] === 'yes' || $params['downloadable'] === true;
				$product->set_downloadable($is_downloadable);

				if ($is_downloadable) {
					// Downloadable files
					if (isset($params['downloads']) && is_array($params['downloads'])) {
						$downloads = [];

						foreach ($params['downloads'] as $download) {
							if (empty($download['name']) || empty($download['file'])) {
								continue;
							}

							$download_id = md5($download['file']);
							$downloads[$download_id] = [
								'id'   => $download_id,
								'name' => wc_clean($download['name']),
								'file' => wc_clean($download['file']),
							];
						}

						$product->set_downloads($downloads);
					}

					if ( array_key_exists( 'download_limit', $params ) ) {
						$download_limit = $params['download_limit'] ? absint($params['download_limit']) : '';
						$product->set_download_limit($download_limit);
					}

					if ( array_key_exists( 'download_expiry', $params ) ) {
						$download_expiry = $params['download_expiry'] ? absint($params['download_expiry']) : '';
						$product->set_download_expiry($download_expiry);
					}
				}
			}

			// Visibility
			if (isset($params['catalog_visibility'])) {
				$visibility = sanitize_text_field($params['catalog_visibility']);
				$valid_visibilities = ['visible', 'catalog', 'search', 'hidden'];

				if (! in_array($visibility, $valid_visibilities)) {
					throw new \Exception(__('Invalid catalog visibility. Must be one of: visible, catalog, search, hidden', 'shop-manager'));
				}

				$product->set_catalog_visibility($visibility);
			}

			// Featured
			if (isset($params['featured'])) {
				$product->set_featured($params['featured'] === 'yes' || $params['featured'] === true);
			}

			// Tax status and class
			if (isset($params['tax_status'])) {
				$tax_status = sanitize_text_field($params['tax_status']);
				$valid_tax_statuses = ['taxable', 'shipping', 'none'];

				if (! in_array($tax_status, $valid_tax_statuses)) {
					throw new \Exception(__('Invalid tax status. Must be one of: taxable, shipping, none', 'shop-manager'));
				}

				$product->set_tax_status($tax_status);
			}

			if (isset($params['tax_class'])) {
				// No validation needed as empty is valid and custom classes can exist
				$product->set_tax_class(sanitize_text_field($params['tax_class']));
			}

			// External/Affiliate product
			if ($product_type === 'external') {
				if (empty($params['product_url'])) {
					throw new \Exception(__('External product URL is required for external products', 'shop-manager'));
				}
				// Store key data before converting product type
				$regular_price = $product->get_regular_price();
				$sale_price = $product->get_sale_price();
				$sku = $product->get_sku();

				// Re-fetch the product as an External product
				$product = new \WC_Product_External($product_id);

				// Now set the meta data for external products
				update_post_meta($product_id, '_product_url', esc_url_raw($params['product_url']));

				if (isset($params['button_text'])) {
					update_post_meta($product_id, '_button_text', sanitize_text_field($params['button_text']));
				}

				// Re-apply price and SKU data to the external product
				if (isset($params['regular_price'])) {
					$product->set_regular_price(wc_format_decimal($params['regular_price']));
					update_post_meta($product_id, '_regular_price', wc_format_decimal($params['regular_price']));
					update_post_meta($product_id, '_price', wc_format_decimal($params['regular_price']));
				} elseif (! empty($regular_price)) {
					// Re-apply the previously set regular price
					$product->set_regular_price($regular_price);
					update_post_meta($product_id, '_regular_price', $regular_price);
					update_post_meta($product_id, '_price', $regular_price);
				}

				if (isset($params['sale_price'])) {
					$product->set_sale_price(wc_format_decimal($params['sale_price']));
					update_post_meta($product_id, '_sale_price', wc_format_decimal($params['sale_price']));

					// If sale price is set and less than regular price, use it as the active price
					if ($params['sale_price'] < $params['regular_price']) {
						update_post_meta($product_id, '_price', wc_format_decimal($params['sale_price']));
					}
				} elseif (! empty($sale_price)) {
					// Re-apply the previously set sale price
					$product->set_sale_price($sale_price);
					update_post_meta($product_id, '_sale_price', $sale_price);

					// If sale price is less than regular price, use it as the active price
					if ($sale_price < $regular_price) {
						update_post_meta($product_id, '_price', $sale_price);
					}
				}

				// Re-apply SKU
				if (isset($params['sku'])) {
					$product->set_sku(sanitize_text_field($params['sku']));
					update_post_meta($product_id, '_sku', sanitize_text_field($params['sku']));
				} elseif (! empty($sku)) {
					$product->set_sku($sku);
					update_post_meta($product_id, '_sku', $sku);
				}

				// Make sure other important data like status is preserved
				if (isset($params['stock_status'])) {
					$product->set_stock_status(sanitize_text_field($params['stock_status']));
				}
			}

			// Grouped products
			if ($product_type === 'grouped' && isset($params['grouped_products']) && is_array($params['grouped_products'])) {
				// Store SKU before converting product type
				$sku = $product->get_sku();

				// Convert to grouped product
				$product = new \WC_Product_Grouped($product_id);

				$grouped_products = array_map('absint', $params['grouped_products']);

				// Verify all products exist and aren't the current product
				foreach ($grouped_products as $key => $grouped_product_id) {
					if ($grouped_product_id === $product_id) {
						throw new \Exception(__('A product cannot be grouped with itself', 'shop-manager'));
					}

					if (! wc_get_product($grouped_product_id)) {
						throw new \Exception(sprintf(__('Product #%d does not exist', 'shop-manager'), $grouped_product_id));
					}
				}

				// Set grouped products using meta update (most reliable method)
				update_post_meta($product_id, '_children', $grouped_products);

				// Re-apply SKU - using both methods for maximum compatibility
				if (isset($params['sku'])) {
					$sku_value = sanitize_text_field($params['sku']);
					$product->set_sku($sku_value); // API method
					update_post_meta($product_id, '_sku', $sku_value); // Direct update
				} elseif (! empty($sku)) {
					// Re-apply the previously set SKU
					$product->set_sku($sku); // API method
					update_post_meta($product_id, '_sku', $sku); // Direct update
				}

				// Also ensure other key fields are reapplied if they were set

				// Featured status
				if (isset($params['featured'])) {
					$product->set_featured($params['featured'] === 'yes' || $params['featured'] === true);
				}

				// Visibility
				if (isset($params['catalog_visibility'])) {
					$product->set_catalog_visibility(sanitize_text_field($params['catalog_visibility']));
				}
			}

			// Linked products
			if (isset($params['upsell_ids']) && is_array($params['upsell_ids'])) {
				$upsell_ids = array_map('absint', $params['upsell_ids']);

				// Remove this product if it's in the list
				$upsell_ids = array_diff($upsell_ids, [$product_id]);

				$product->set_upsell_ids($upsell_ids);
			}

			if (isset($params['cross_sell_ids']) && is_array($params['cross_sell_ids'])) {
				$cross_sell_ids = array_map('absint', $params['cross_sell_ids']);

				// Remove this product if it's in the list
				$cross_sell_ids = array_diff($cross_sell_ids, [$product_id]);

				$product->set_cross_sell_ids($cross_sell_ids);
			}

			// Menu order
			if (isset($params['menu_order'])) {
				$product->set_menu_order(intval($params['menu_order']));
			}

			// Purchase note
			if (isset($params['purchase_note'])) {
				$product->set_purchase_note(wp_kses_post($params['purchase_note']));
			}

			// Reviews
			if (isset($params['reviews_allowed'])) {
				$product->set_reviews_allowed($params['reviews_allowed'] === 'yes' || $params['reviews_allowed'] === true);
			}

			// Process attributes
			if (isset($params['attributes']) && is_array($params['attributes'])) {
				$attributes = [];

				foreach ($params['attributes'] as $key => $attribute_data) {
					if (empty($attribute_data['name'])) {
						continue;
					}

					$attribute_id = isset($attribute_data['id']) ? absint($attribute_data['id']) : 0;
					$attribute_name = wc_clean($attribute_data['name']);
					$is_taxonomy = isset($attribute_data['is_taxonomy']) ? (bool) $attribute_data['is_taxonomy'] : false;

					if ($is_taxonomy) {
						// For taxonomy attributes, get the taxonomy name
						if ($attribute_id > 0) {
							$taxonomy_name = wc_attribute_taxonomy_name_by_id($attribute_id);
							if ($taxonomy_name) {
								$attribute_name = $taxonomy_name;
							} else {
								continue;
							}
						} else {
							// If no ID but is taxonomy, try to find by name
							$attribute_name = wc_attribute_taxonomy_name($attribute_name);
							if (! taxonomy_exists($attribute_name)) {
								continue;
							}
						}
					}

					// Get the options
					$options = isset($attribute_data['options']) ? $attribute_data['options'] : [];
					if (! is_array($options)) {
						$options = explode('|', $options);
					}
					$options = array_map('wc_clean', $options);

					// For taxonomy attributes, ensure terms exist or create them
					if ($is_taxonomy) {
						$taxonomy = wc_clean($attribute_name);
						$term_ids = [];

						foreach ($options as $option) {
							$term = get_term_by('name', $option, $taxonomy);
							if ($term) {
								$term_ids[] = $term->term_id;
							} else {
								// Create the term
								$term_data = wp_insert_term($option, $taxonomy);
								if (! is_wp_error($term_data)) {
									$term_ids[] = $term_data['term_id'];
								}
							}
						}

						// Use term IDs as options for taxonomy attributes
						$options = $term_ids;
					}

					// Create the attribute object
					$attribute_object = new \WC_Product_Attribute();
					$attribute_object->set_id($attribute_id);
					$attribute_object->set_name($attribute_name);
					$attribute_object->set_options($options);
					$attribute_object->set_position(isset($attribute_data['position']) ? absint($attribute_data['position']) : $key);
					$attribute_object->set_visible(isset($attribute_data['visible']) ? (bool) $attribute_data['visible'] : true);
					$attribute_object->set_variation(isset($attribute_data['variation']) ? (bool) $attribute_data['variation'] : false);

					$attributes[] = $attribute_object;
				}

				// Set the attributes on the product
				$product->set_attributes($attributes);
			}

			// Default attributes for variable products
			if ($product_type === 'variable' && isset($params['default_attributes']) && is_array($params['default_attributes'])) {
				$default_attributes = [];

				foreach ($params['default_attributes'] as $default_attr) {
					if (empty($default_attr['name']) || !isset($default_attr['option']) || empty($default_attr['option'])) {
						continue;
					}

					// Get the attribute name and value
					$attr_name = $default_attr['name'];
					$attr_value = wc_clean($default_attr['option']);

					// Get product attributes
					$product_attributes = $product->get_attributes();
					$matching_attribute = null;
					$is_taxonomy = false;

					// First, try to find a matching attribute
					foreach ($product_attributes as $product_attribute) {
						if ($product_attribute->is_taxonomy()) {
							// For taxonomy attributes
							$taxonomy = $product_attribute->get_taxonomy();
							$taxonomy_label = str_replace('pa_', '', $taxonomy);

							// Compare case-insensitively
							if (
								strtolower($taxonomy) === strtolower($attr_name) ||
								strtolower($taxonomy_label) === strtolower($attr_name) ||
								strtolower('pa_' . $attr_name) === strtolower($taxonomy)
							) {
								$matching_attribute = $product_attribute;
								$is_taxonomy = true;
								$attr_name = $taxonomy; // Use the actual taxonomy name
								break;
							}
						} else {
							// For custom attributes
							$original_name = $product_attribute->get_name();

							// Compare case-insensitively
							if (
								strtolower($original_name) === strtolower($attr_name) ||
								sanitize_title($original_name) === sanitize_title($attr_name)
							) {
								$matching_attribute = $product_attribute;
								$attr_name = sanitize_title($original_name); // Use sanitized name for custom attributes
								break;
							}
						}
					}

					// If we found a matching attribute, validate the option
					if ($matching_attribute) {
						$options = $matching_attribute->get_options();
						$option_found = false;

						if ($is_taxonomy) {
							// For taxonomy attributes, we need to find the term
							$taxonomy = $matching_attribute->get_taxonomy();
							$term = get_term_by('name', $attr_value, $taxonomy);

							if ($term) {
								// Use the term slug as the value
								$attr_value = $term->slug;
								$option_found = true;
							} else {
								// Try to find by slug
								$term = get_term_by('slug', sanitize_title($attr_value), $taxonomy);
								if ($term) {
									$attr_value = $term->slug;
									$option_found = true;
								} else {
									// Try to create the term if it doesn't exist
									$term_data = wp_insert_term(wc_clean($attr_value), $taxonomy);
									if (!is_wp_error($term_data)) {
										$term = get_term_by('id', $term_data['term_id'], $taxonomy);
										if ($term) {
											$attr_value = $term->slug;
											$option_found = true;
										}
									}
								}
							}
						} else {
							// For custom attributes, check if the option exists
							foreach ($options as $option) {
								if (
									$option === $attr_value ||
									sanitize_title($option) === sanitize_title($attr_value)
								) {
									$option_found = true;
									break;
								}
							}
						}

						// Only add if the option was found
						if ($option_found) {
							$default_attributes[$attr_name] = $attr_value;
						}
					}
				}

				$product->set_default_attributes($default_attributes);
			}

			// Set taxonomies
			// Categories
			if (isset($params['categories']) && is_array($params['categories']) && !empty($params['categories'])) {
				$category_ids = [];

				// Process category objects to get IDs
				foreach ($params['categories'] as $category) {
					if (is_array($category) && isset($category['id'])) {
						$category_ids[] = absint($category['id']);
					} elseif (is_numeric($category)) {
						// Handle the case where it might just be an ID
						$category_ids[] = absint($category);
					}
				}

				// Validate categories exist
				foreach ($category_ids as $key => $category_id) {
					if (! term_exists($category_id, 'product_cat')) {
						unset($category_ids[$key]);
					}
				}

				// Make sure we're using the correct WooCommerce method
				$product->set_category_ids($category_ids);
			} else {
				// No categories selected, set default category
				$default_category_id = get_option('default_product_cat');
				
				// If no default category is set in WooCommerce, try to get the first available category
				if (!$default_category_id) {
					$product_categories = get_terms([
						'taxonomy' => 'product_cat',
						'hide_empty' => false,
						'number' => 1,
						'orderby' => 'count',
						'order' => 'DESC'
					]);
					
					if (!empty($product_categories) && !is_wp_error($product_categories)) {
						$default_category_id = $product_categories[0]->term_id;
					}
				}
				
				// Set the default category if we found one
				if ($default_category_id) {
					$product->set_category_ids([$default_category_id]);
				}
			}

			// Tags
			if (isset($params['tags']) && is_array($params['tags'])) {
				$tag_ids = [];

				// Process tag objects to get IDs
				foreach ($params['tags'] as $tag) {
					if (is_array($tag) && isset($tag['id'])) {
						$tag_ids[] = absint($tag['id']);
					} elseif (is_numeric($tag)) {
						// Handle the case where it might just be an ID
						$tag_ids[] = absint($tag);
					} elseif (is_string($tag) && ! is_numeric($tag)) {
						// Create the tag if it's a string name
						$term = get_term_by('name', $tag, 'product_tag');
						if ($term) {
							$tag_ids[] = $term->term_id;
						} else {
							$new_term = wp_insert_term($tag, 'product_tag');
							if (! is_wp_error($new_term)) {
								$tag_ids[] = $new_term['term_id'];
							}
						}
					}
				}

				$product->set_tag_ids($tag_ids);
			}

			// Brands (custom taxonomy)
			if (isset($params['brands']) && is_array($params['brands']) && taxonomy_exists('product_brand')) {
				$brand_ids = array_map('intval', $params['brands']);

				// Validate brands exist
				foreach ($brand_ids as $key => $brand_id) {
					if (! term_exists($brand_id, 'product_brand')) {
						unset($brand_ids[$key]);
					}
				}

				wp_set_object_terms($product_id, $brand_ids, 'product_brand');
			}

			// Set product images
			if (isset($params['image_id'])) {
				$image_id = absint($params['image_id']);

				// Verify the image exists
				if ($image_id > 0 && ! wp_get_attachment_url($image_id)) {
					throw new \Exception(__('Featured image does not exist', 'shop-manager'));
				}

				$product->set_image_id($image_id);
			}

			if (isset($params['gallery_image_ids']) && is_array($params['gallery_image_ids'])) {
				$gallery_ids = array_map('absint', $params['gallery_image_ids']);

				// Verify each gallery image exists
				foreach ($gallery_ids as $key => $gallery_id) {
					if (! wp_get_attachment_url($gallery_id)) {
						unset($gallery_ids[$key]);
					}
				}

				$product->set_gallery_image_ids($gallery_ids);
			}

			// Additional meta fields
			if (isset($params['meta_data']) && is_array($params['meta_data'])) {
				foreach ($params['meta_data'] as $meta) {
					if (! empty($meta['key'])) {
						$product->update_meta_data(
							sanitize_text_field($meta['key']),
							wp_kses_post($meta['value'] ?? '')
						);
					}
				}
			}

			// Save the product with all properties
			$product->save();

			// Create variations for variable products - MOVED AFTER SAVING PRODUCT
			if ($product_type === 'variable' && isset($params['variations']) && is_array($params['variations'])) {
				// Refresh the product object to ensure it's recognized as variable
				$product = wc_get_product($product_id);

				// Double-check the product type is actually variable
				if ($product->get_type() !== 'variable') {
					throw new \Exception(__('Failed to set product type as variable', 'shop-manager'));
				}

				foreach ($params['variations'] as $variation_data) {
					$variation_id = $this->wpkin_create_product_variation($product_id, $variation_data);
					if (is_wp_error($variation_id)) {
						throw new \Exception($variation_id->get_error_message());
					}
				}

				// Update parent variable product with min/max prices
				\WC_Product_Variable::sync($product_id);
			}

			// Commit transaction
			$wpdb->query('COMMIT');

			$this->log_employee_action( 'product_created', [
				'product_id'   => $product_id,
				'product_name' => sanitize_text_field( $params['name'] ),
			] );

			// Return success response
			return [
				'success' => true,
				'product_id' => $product_id,
				'product_url' => get_permalink($product_id),
				'edit_url' => get_edit_post_link($product_id, 'raw'),
			];
		} catch (\Exception $e) {
			// Rollback transaction
			$wpdb->query('ROLLBACK');

			// Return error response
			return new \WP_Error(
				'product_creation_failed',
				$e->getMessage(),
				['status' => 500]
			);
		}
	}

	/**
	 * Update a WooCommerce product via REST API
	 *
	 * @param \WP_REST_Request $request The request object.
	 * @return array|\WP_Error Success response or error.
	 */
	public function wpkin_sm_update_product(\WP_REST_Request $request)
	{
		// Get request parameters
		$params = $request->get_params();
		$product_id = isset($params['id']) ? intval($params['id']) : 0;

		// Validate product ID
		if (! $product_id) {
			return new \WP_Error('missing_id', __('Product ID is required', 'shop-manager'), ['status' => 400]);
		}

		// Get the product
		$product = wc_get_product($product_id);
		if (! $product) {
			return new \WP_Error('invalid_product', __('Product not found', 'shop-manager'), ['status' => 404]);
		}

		try {
			// Start transaction if supported
			global $wpdb;
			$wpdb->query('START TRANSACTION');

			// Update basic product data
			$product_data = [
				'ID' => $product_id,
				'post_title' => isset($params['name']) ? sanitize_text_field($params['name']) : $product->get_name(),
				'post_content' => isset($params['description']) ? wp_kses_post($params['description']) : $product->get_description(),
				'post_excerpt' => isset($params['short_description']) ? wp_kses_post($params['short_description']) : $product->get_short_description(),
				'post_status' => isset($params['status']) ? sanitize_text_field($params['status']) : $product->get_status(),
			];

			// Update the product post
			wp_update_post($product_data, true);

			// Determine if product type changed
			$current_product_type = $product->get_type();
			$new_product_type = isset($params['product_type']) ? sanitize_text_field($params['product_type']) : $current_product_type;
			$valid_types = ['simple', 'grouped', 'external', 'variable'];

			if (! in_array($new_product_type, $valid_types)) {
				throw new \Exception(__('Invalid product type. Must be one of: simple, grouped, external, variable', 'shop-manager'));
			}

			// If product type changed, update it
			if ($new_product_type !== $current_product_type) {
				wp_set_object_terms($product_id, $new_product_type, 'product_type');

				// Reload the product with the new type
				if ($new_product_type === 'variable') {
					$product = new \WC_Product_Variable($product_id);
				} elseif ($new_product_type === 'grouped') {
					$product = new \WC_Product_Grouped($product_id);
				} elseif ($new_product_type === 'external') {
					$product = new \WC_Product_External($product_id);
				} else {
					$product = new \WC_Product_Simple($product_id);
				}
			}

			// Update product data
			if (isset($params['regular_price'])) {
				$regular_price = wc_format_decimal($params['regular_price']);
				if ($regular_price < 0) {
					throw new \Exception(__('Regular price cannot be negative', 'shop-manager'));
				}
				$product->set_regular_price($regular_price);
			}

			if (isset($params['regular_price'])) {
				$sale_price = wc_format_decimal($params['sale_price']);

				// Validate sale price is not greater than regular price if both are set
				if (isset($params['regular_price']) && $sale_price > wc_format_decimal($params['regular_price'])) {
					throw new \Exception(__('Sale price cannot be greater than regular price', 'shop-manager'));
				}

				$product->set_sale_price($sale_price);
			}

			$sale_date_from = $params['sale_date_from'] ? sanitize_text_field($params['sale_date_from']) : '';
			$sale_date_to   = $params['sale_date_to'] ? sanitize_text_field($params['sale_date_to']) : '';

			$product->set_date_on_sale_from($sale_date_from);
			$product->set_date_on_sale_to($sale_date_to);

			// SKU
			if (isset($params['sku'])) {
				$sku = trim(sanitize_text_field($params['sku']));

				// Only check for duplicates if SKU is not empty and has changed
				if ($sku !== '' && $sku !== $product->get_sku()) {
					// Check if SKU is unique
					$existing_product = wc_get_product_id_by_sku($sku);
					if ($existing_product && $existing_product !== $product_id) {
						throw new \Exception(sprintf(__('Product SKU must be unique. %s is already in use', 'shop-manager'), $sku));
					}
				}

				$product->set_sku($sku);
			}

			// GTIN/UPC/EAN/ISBN
			if (isset($params['global_unique_id'])) {
				$gtin = sanitize_text_field($params['global_unique_id']);
				// Use the correct meta key for GTIN
				$product->update_meta_data('_global_unique_id', $gtin);
			}

			// Inventory
			if (isset($params['manage_stock'])) {
				$manage_stock = (bool) ($params['manage_stock'] === 'yes' || $params['manage_stock'] === true);
				$product->set_manage_stock($manage_stock);

				if ($manage_stock) {
					if (isset($params['stock_quantity'])) {
						$stock_quantity = absint($params['stock_quantity']);
						$product->set_stock_quantity($stock_quantity);
					}

					if (isset($params['backorders'])) {
						$backorders = sanitize_text_field($params['backorders']);
						$valid_backorders = ['no', 'notify', 'yes'];

						if (! in_array($backorders, $valid_backorders)) {
							throw new \Exception(__('Invalid backorders value. Must be one of: no, notify, yes', 'shop-manager'));
						}

						$product->set_backorders($backorders);
					}
				}
			}
			if (isset($params['stock_status'])) {
				$stock_status = sanitize_text_field($params['stock_status']);
				$valid_statuses = ['instock', 'outofstock', 'onbackorder'];

				if (! in_array($stock_status, $valid_statuses)) {
					throw new \Exception(__('Invalid stock status. Must be one of: instock, outofstock, onbackorder', 'shop-manager'));
				}

				$product->set_stock_status($stock_status);
			}

			// Sold individually
			if (isset($params['sold_individually'])) {
				$product->set_sold_individually($params['sold_individually'] === 'yes' || $params['sold_individually'] === true);
			}

			// Shipping
			if (isset($params['weight'])) {
				$product->set_weight(wc_format_decimal(sanitize_text_field($params['weight'])));
			}

			if (isset($params['length'])) {
				$product->set_length(wc_format_decimal(sanitize_text_field($params['length'])));
			}

			if (isset($params['width'])) {
				$product->set_width(wc_format_decimal(sanitize_text_field($params['width'])));
			}

			if (isset($params['height'])) {
				$product->set_height(wc_format_decimal(sanitize_text_field($params['height'])));
			}

			if (isset($params['shipping_class_id'])) {
				$shipping_class_id = absint($params['shipping_class_id']);

				// Verify shipping class exists
				if ($shipping_class_id > 0 && ! term_exists($shipping_class_id, 'product_shipping_class')) {
					throw new \Exception(__('Invalid shipping class ID', 'shop-manager'));
				}

				$product->set_shipping_class_id($shipping_class_id);
			}

			// Virtual
			if (isset($params['virtual'])) {
				$product->set_virtual($params['virtual'] === 'yes' || $params['virtual'] === true);
			}

			// Downloadable
			if (isset($params['downloadable'])) {
				$is_downloadable = $params['downloadable'] === 'yes' || $params['downloadable'] === true;
				$product->set_downloadable($is_downloadable);

				if ($is_downloadable) {
					// Downloadable files
					if (isset($params['downloads']) && is_array($params['downloads'])) {
						$downloads = [];

						foreach ($params['downloads'] as $download) {
							if (empty($download['name']) || empty($download['file'])) {
								continue;
							}

							$download_id = md5($download['file']);
							$downloads[$download_id] = [
								'id' => $download_id,
								'name' => wc_clean($download['name']),
								'file' => wc_clean($download['file']),
							];
						}

						$product->set_downloads($downloads);
					}

					if ( array_key_exists( 'download_limit', $params ) ) {
						$download_limit = $params['download_limit'] ? absint($params['download_limit']) : '';
						$product->set_download_limit($download_limit);
					}

					if ( array_key_exists( 'download_expiry', $params ) ) {
						$download_expiry = $params['download_expiry'] ? absint($params['download_expiry']) : '';
						$product->set_download_expiry($download_expiry);
					}
				}
			}

			// Visibility
			if (isset($params['catalog_visibility'])) {
				$visibility = sanitize_text_field($params['catalog_visibility']);
				$valid_visibilities = ['visible', 'catalog', 'search', 'hidden'];

				if (! in_array($visibility, $valid_visibilities)) {
					throw new \Exception(__('Invalid catalog visibility. Must be one of: visible, catalog, search, hidden', 'shop-manager'));
				}

				$product->set_catalog_visibility($visibility);
			}

			// Featured
			if (isset($params['featured'])) {
				$product->set_featured($params['featured'] === 'yes' || $params['featured'] === true);
			}

			// Tax status and class
			if (isset($params['tax_status'])) {
				$tax_status = sanitize_text_field($params['tax_status']);
				$valid_tax_statuses = ['taxable', 'shipping', 'none'];

				if (! in_array($tax_status, $valid_tax_statuses)) {
					throw new \Exception(__('Invalid tax status. Must be one of: taxable, shipping, none', 'shop-manager'));
				}

				$product->set_tax_status($tax_status);
			}

			if (isset($params['tax_class'])) {
				// No validation needed as empty is valid and custom classes can exist
				$product->set_tax_class(sanitize_text_field($params['tax_class']));
			}

			// External/Affiliate product
			if ($new_product_type === 'external') {
				if (empty($params['product_url'])) {
					throw new \Exception(__('External product URL is required for external products', 'shop-manager'));
				}
				// Store key data before converting product type
				$regular_price = $product->get_regular_price();
				$sale_price = $product->get_sale_price();
				$sku = $product->get_sku();

				// Re-fetch the product as an External product
				$product = new \WC_Product_External($product_id);

				// Now set the meta data for external products
				update_post_meta($product_id, '_product_url', esc_url_raw($params['product_url']));

				if (isset($params['button_text'])) {
					update_post_meta($product_id, '_button_text', sanitize_text_field($params['button_text']));
				}

				// Re-apply price and SKU data to the external product
				if (isset($params['regular_price'])) {
					$product->set_regular_price(wc_format_decimal($params['regular_price']));
					update_post_meta($product_id, '_regular_price', wc_format_decimal($params['regular_price']));
					update_post_meta($product_id, '_price', wc_format_decimal($params['regular_price']));
				} elseif (! empty($regular_price)) {
					// Re-apply the previously set regular price
					$product->set_regular_price($regular_price);
					update_post_meta($product_id, '_regular_price', $regular_price);
					update_post_meta($product_id, '_price', $regular_price);
				}

				if (isset($params['sale_price'])) {
					$product->set_sale_price(wc_format_decimal($params['sale_price']));
					update_post_meta($product_id, '_sale_price', wc_format_decimal($params['sale_price']));

					// If sale price is set and less than regular price, use it as the active price
					if ($params['sale_price'] < $params['regular_price']) {
						update_post_meta($product_id, '_price', wc_format_decimal($params['sale_price']));
					}
				} elseif (! empty($sale_price)) {
					// Re-apply the previously set sale price
					$product->set_sale_price($sale_price);
					update_post_meta($product_id, '_sale_price', $sale_price);

					// If sale price is less than regular price, use it as the active price
					if ($sale_price < $regular_price) {
						update_post_meta($product_id, '_price', $sale_price);
					}
				}

				// Re-apply SKU
				if (isset($params['sku'])) {
					$product->set_sku(sanitize_text_field($params['sku']));
					update_post_meta($product_id, '_sku', sanitize_text_field($params['sku']));
				} elseif (! empty($sku)) {
					$product->set_sku($sku);
					update_post_meta($product_id, '_sku', $sku);
				}

				// Make sure other important data like status is preserved
				if (isset($params['stock_status'])) {
					$product->set_stock_status(sanitize_text_field($params['stock_status']));
				}
			}

			// Grouped products
			if ($new_product_type === 'grouped' && isset($params['grouped_products']) && is_array($params['grouped_products'])) {
				// Store SKU before converting product type
				$sku = $product->get_sku();

				// Convert to grouped product
				$product = new \WC_Product_Grouped($product_id);

				$grouped_products = array_map('absint', $params['grouped_products']);

				// Verify all products exist and aren't the current product
				foreach ($grouped_products as $key => $grouped_product_id) {
					if ($grouped_product_id === $product_id) {
						throw new \Exception(__('A product cannot be grouped with itself', 'shop-manager'));
					}

					if (! wc_get_product($grouped_product_id)) {
						throw new \Exception(sprintf(__('Product #%d does not exist', 'shop-manager'), $grouped_product_id));
					}
				}

				// Set grouped products using meta update (most reliable method)
				update_post_meta($product_id, '_children', $grouped_products);

				// Re-apply SKU - using both methods for maximum compatibility
				if (isset($params['sku'])) {
					$sku_value = sanitize_text_field($params['sku']);
					$product->set_sku($sku_value); // API method
					update_post_meta($product_id, '_sku', $sku_value); // Direct update
				} elseif (! empty($sku)) {
					// Re-apply the previously set SKU
					$product->set_sku($sku); // API method
					update_post_meta($product_id, '_sku', $sku); // Direct update
				}

				// Also ensure other key fields are reapplied if they were set

				// Featured status
				if (isset($params['featured'])) {
					$product->set_featured($params['featured'] === 'yes' || $params['featured'] === true);
				}

				// Visibility
				if (isset($params['catalog_visibility'])) {
					$product->set_catalog_visibility(sanitize_text_field($params['catalog_visibility']));
				}
			}

			// Linked products
			if (isset($params['upsell_ids']) && is_array($params['upsell_ids'])) {
				$upsell_ids = array_map('absint', $params['upsell_ids']);

				// Remove this product if it's in the list
				$upsell_ids = array_diff($upsell_ids, [$product_id]);

				$product->set_upsell_ids($upsell_ids);
			}

			if (isset($params['cross_sell_ids']) && is_array($params['cross_sell_ids'])) {
				$cross_sell_ids = array_map('absint', $params['cross_sell_ids']);

				// Remove this product if it's in the list
				$cross_sell_ids = array_diff($cross_sell_ids, [$product_id]);

				$product->set_cross_sell_ids($cross_sell_ids);
			}

			// Menu order
			if (isset($params['menu_order'])) {
				$product->set_menu_order(intval($params['menu_order']));
			}

			// Purchase note
			if (isset($params['purchase_note'])) {
				$product->set_purchase_note(wp_kses_post($params['purchase_note']));
			}

			// Reviews
			if (isset($params['reviews_allowed'])) {
				$product->set_reviews_allowed($params['reviews_allowed'] === 'yes' || $params['reviews_allowed'] === true);
			}

			// Process attributes
			if (isset($params['attributes']) && is_array($params['attributes'])) {
				$attributes = [];
				foreach ($params['attributes'] as $key => $attribute_data) {
					if (empty($attribute_data['name'])) {
						continue;
					}

					$attribute_id = isset($attribute_data['id']) ? absint($attribute_data['id']) : 0;
					$attribute_name = wc_clean($attribute_data['name']);

					// IMPORTANT: Determine if this is a taxonomy attribute based on ID
					$is_taxonomy = false;

					// If it has an ID greater than 0, it's a taxonomy attribute
					if ($attribute_id > 0) {
						$is_taxonomy = true;
					}
					// Otherwise check the is_taxonomy flag if set
					elseif (isset($attribute_data['is_taxonomy'])) {
						// Convert various forms of "true" to boolean true
						if (
							$attribute_data['is_taxonomy'] === true ||
							$attribute_data['is_taxonomy'] === '1' ||
							$attribute_data['is_taxonomy'] === 1 ||
							$attribute_data['is_taxonomy'] === 'true'
						) {
							$is_taxonomy = true;
						}
					}

					if ($is_taxonomy) {
						// For taxonomy attributes, get the taxonomy name
						if ($attribute_id > 0) {
							$taxonomy_name = wc_attribute_taxonomy_name_by_id($attribute_id);
							if ($taxonomy_name) {
								$attribute_name = $taxonomy_name;
							} else {
								$is_taxonomy = false; // Fallback to custom attribute
							}
						} else {
							// Try to find taxonomy by name
							$attribute_taxonomy_name = wc_attribute_taxonomy_name($attribute_name);
							if (taxonomy_exists($attribute_taxonomy_name)) {
								$attribute_name = $attribute_taxonomy_name;
							} else {
								$is_taxonomy = false; // Fallback to custom attribute
							}
						}
					}

					// Get the options
					$options = isset($attribute_data['options']) ? $attribute_data['options'] : [];
					if (! is_array($options)) {
						$options = explode('|', $options);
					}

					// Clean options
					$options = array_map('wc_clean', array_filter($options));

					// For taxonomy attributes, ensure terms exist
					if ($is_taxonomy && ! empty($options)) {
						$taxonomy = $attribute_name;
						$term_ids = [];

						foreach ($options as $option) {
							// Skip empty options
							if (empty($option)) {
								continue;
							}

							// First try to get the term by name
							$term = get_term_by('name', $option, $taxonomy);

							if ($term) {
								$term_ids[] = $term->term_id;
							} else {
								// Try by slug
								$term = get_term_by('slug', sanitize_title($option), $taxonomy);

								if ($term) {
									$term_ids[] = $term->term_id;
								} else {
									// Create the term
									$term_data = wp_insert_term(wc_clean($option), $taxonomy);
									if (! is_wp_error($term_data)) {
										$term_ids[] = $term_data['term_id'];
									}
								}
							}
						}

						// Use term IDs as options for taxonomy attributes
						if (! empty($term_ids)) {
							$options = $term_ids;
						}
					}

					// Create the attribute object
					$attribute_object = new \WC_Product_Attribute();
					$attribute_object->set_id($attribute_id);
					$attribute_object->set_name($attribute_name);
					$attribute_object->set_options($options);
					$attribute_object->set_position(isset($attribute_data['position']) ? absint($attribute_data['position']) : $key);
					$attribute_object->set_visible(isset($attribute_data['visible']) ? (bool) $attribute_data['visible'] : true);
					$attribute_object->set_variation(isset($attribute_data['variation']) ? (bool) $attribute_data['variation'] : false);

					$attributes[] = $attribute_object;
				}

				// Set the attributes on the product
				$product->set_attributes($attributes);
			}

			// Default attributes for variable products
			if ($new_product_type === 'variable' && isset($params['default_attributes']) && is_array($params['default_attributes'])) {
				$default_attributes = [];

				foreach ($params['default_attributes'] as $default_attr) {
					if (empty($default_attr['name']) || !isset($default_attr['option']) || empty($default_attr['option'])) {
						continue;
					}

					// Get the attribute name and value
					$attr_name = $default_attr['name'];
					$attr_value = wc_clean($default_attr['option']);

					// Get product attributes
					$product_attributes = $product->get_attributes();
					$matching_attribute = null;
					$is_taxonomy = false;

					// First, try to find a matching attribute
					foreach ($product_attributes as $product_attribute) {
						if ($product_attribute->is_taxonomy()) {
							// For taxonomy attributes
							$taxonomy = $product_attribute->get_taxonomy();
							$taxonomy_label = str_replace('pa_', '', $taxonomy);

							// Compare case-insensitively
							if (
								strtolower($taxonomy) === strtolower($attr_name) ||
								strtolower($taxonomy_label) === strtolower($attr_name) ||
								strtolower('pa_' . $attr_name) === strtolower($taxonomy)
							) {
								$matching_attribute = $product_attribute;
								$is_taxonomy = true;
								$attr_name = $taxonomy; // Use the actual taxonomy name
								break;
							}
						} else {
							// For custom attributes
							$original_name = $product_attribute->get_name();

							// Compare case-insensitively
							if (
								strtolower($original_name) === strtolower($attr_name) ||
								sanitize_title($original_name) === sanitize_title($attr_name)
							) {
								$matching_attribute = $product_attribute;
								$attr_name = sanitize_title($original_name); // Use sanitized name for custom attributes
								break;
							}
						}
					}

					// If we found a matching attribute, validate the option
					if ($matching_attribute) {
						$options = $matching_attribute->get_options();
						$option_found = false;

						if ($is_taxonomy) {
							// For taxonomy attributes, we need to find the term
							$taxonomy = $matching_attribute->get_taxonomy();
							$term = get_term_by('name', $attr_value, $taxonomy);

							if ($term) {
								// Use the term slug as the value
								$attr_value = $term->slug;
								$option_found = true;
							} else {
								// Try to find by slug
								$term = get_term_by('slug', sanitize_title($attr_value), $taxonomy);
								if ($term) {
									$attr_value = $term->slug;
									$option_found = true;
								} else {
									// Try to create the term if it doesn't exist
									$term_data = wp_insert_term(wc_clean($attr_value), $taxonomy);
									if (!is_wp_error($term_data)) {
										$term = get_term_by('id', $term_data['term_id'], $taxonomy);
										if ($term) {
											$attr_value = $term->slug;
											$option_found = true;
										}
									}
								}
							}
						} else {
							// For custom attributes, check if the option exists
							foreach ($options as $option) {
								if (
									$option === $attr_value ||
									sanitize_title($option) === sanitize_title($attr_value)
								) {
									$option_found = true;
									break;
								}
							}
						}

						// Only add if the option was found
						if ($option_found) {
							$default_attributes[$attr_name] = $attr_value;
						}
					}
				}

				$product->set_default_attributes($default_attributes);
			}

			// Set product images
			if (isset($params['images']) && is_array($params['images'])) {
				$images = $params['images'];

				// Check if we have any images
				if (! empty($images)) {
					// First image is featured image
					$featured_image = $images[0];
					if (isset($featured_image['id'])) {
						$featured_image_id = absint($featured_image['id']);

						// Verify the image exists
						if ($featured_image_id > 0 && ! wp_get_attachment_url($featured_image_id)) {
							throw new \Exception("Warning: Featured image ID {$featured_image_id} does not exist");
						} else {
							$product->set_image_id($featured_image_id);
						}
					}

					// Remaining images are gallery
					if (count($images) > 1) {
						$gallery_ids = [];

						for ($i = 1; $i < count($images); $i++) {
							if (isset($images[$i]['id'])) {
								$gallery_id = absint($images[$i]['id']);

								// Verify the image exists
								if ($gallery_id > 0 && wp_get_attachment_url($gallery_id)) {
									$gallery_ids[] = $gallery_id;
								}
							}
						}

						$product->set_gallery_image_ids($gallery_ids);
					} else {
						// Clear gallery if no gallery images provided
						$product->set_gallery_image_ids([]);
					}
				} else {
					// Clear all images if none provided
					$product->set_image_id(0);
					$product->set_gallery_image_ids([]);
				}
			}

			// Set taxonomies

			// Categories
			if (isset($params['categories']) && is_array($params['categories'])) {
				$category_ids = array_map('absint', $params['categories']);

				// Validate categories exist
				foreach ($category_ids as $key => $category_id) {
					if (! term_exists($category_id, 'product_cat')) {
						unset($category_ids[$key]);
					}
				}
				// Make sure we're using the correct WooCommerce method
				$product->set_category_ids($category_ids);
			}  else {
				// No categories selected, set default category
				$default_category_id = get_option('default_product_cat');
				
				// If no default category is set in WooCommerce, try to get the first available category
				if (!$default_category_id) {
					$product_categories = get_terms([
						'taxonomy' => 'product_cat',
						'hide_empty' => false,
						'number' => 1,
						'orderby' => 'count',
						'order' => 'DESC'
					]);
					
					if (!empty($product_categories) && !is_wp_error($product_categories)) {
						$default_category_id = $product_categories[0]->term_id;
					}
				}
				
				// Set the default category if we found one
				if ($default_category_id) {
					$product->set_category_ids([$default_category_id]);
				}
			}

			// Tags
			if (isset($params['tags']) && is_array($params['tags'])) {
				$tag_ids = [];

				// Process tag objects to get IDs
				foreach ($params['tags'] as $tag) {
					if (is_array($tag) && isset($tag['id'])) {
						$tag_ids[] = absint($tag['id']);
					} elseif (is_numeric($tag)) {
						// Handle the case where it might just be an ID
						$tag_ids[] = absint($tag);
					} elseif (is_string($tag) && ! is_numeric($tag)) {
						// Create the tag if it's a string name
						$term = get_term_by('name', $tag, 'product_tag');
						if ($term) {
							$tag_ids[] = $term->term_id;
						} else {
							// Create the tag - make sure we're passing a string
							$tag_name = is_array($tag) ? (isset($tag['name']) ? $tag['name'] : '') : $tag;

							// Only proceed if we have a valid string
							if (is_string($tag_name) && ! empty($tag_name)) {
								$new_term = wp_insert_term($tag_name, 'product_tag');
								if (! is_wp_error($new_term)) {
									$tag_ids[] = $new_term['term_id'];
								}
							} else {
								throw new \Exception('Invalid tag format: ' . $tag);
							}
						}
					} else {
						throw new \Exception('Unhandled tag format: ' . $tag);
					}
				}

				$product->set_tag_ids($tag_ids);
			}

			// Brands (custom taxonomy)
			if (isset($params['brands']) && is_array($params['brands']) && taxonomy_exists('product_brand')) {
				$brand_ids = array_map('intval', $params['brands']);

				// Validate brands exist
				foreach ($brand_ids as $key => $brand_id) {
					if (! term_exists($brand_id, 'product_brand')) {
						unset($brand_ids[$key]);
					}
				}

				wp_set_object_terms($product_id, $brand_ids, 'product_brand');
			}

			// Set product images
			if (isset($params['image_id'])) {
				$image_id = absint($params['image_id']);

				// Verify the image exists
				if ($image_id > 0 && ! wp_get_attachment_url($image_id)) {
					throw new \Exception(__('Featured image does not exist', 'shop-manager'));
				}

				$product->set_image_id($image_id);
			}

			if (isset($params['gallery_image_ids']) && is_array($params['gallery_image_ids'])) {
				$gallery_ids = array_map('absint', $params['gallery_image_ids']);

				// Verify each gallery image exists
				foreach ($gallery_ids as $key => $gallery_id) {
					if (! wp_get_attachment_url($gallery_id)) {
						unset($gallery_ids[$key]);
					}
				}

				$product->set_gallery_image_ids($gallery_ids);
			}

			// Additional meta fields
			if (isset($params['meta_data']) && is_array($params['meta_data'])) {
				foreach ($params['meta_data'] as $meta) {
					if (! empty($meta['key'])) {
						$product->update_meta_data(
							sanitize_text_field($meta['key']),
							wp_kses_post($meta['value'] ?? '')
						);
					}
				}
			}

			// Process custom fields
			if (isset($params['custom_fields']) && is_array($params['custom_fields'])) {
				foreach ($params['custom_fields'] as $field) {
					if (! empty($field['name'])) {
						$meta_key = '_' . sanitize_title($field['name']);
						$meta_value = isset($field['value']) ? wp_kses_post($field['value']) : '';
						$product->update_meta_data($meta_key, $meta_value);
					}
				}
			}

			// Save dynamic pricing rules if present
			if (isset($params['dynamic_pricing_rules']) && is_array($params['dynamic_pricing_rules'])) {
				$product->update_meta_data('_dynamic_pricing_rules', wp_json_encode($params['dynamic_pricing_rules']));
			}

			// Save the product with all properties
			$product->save();

			// Update variations for variable products
			if ($new_product_type === 'variable' && isset($params['variations']) && is_array($params['variations'])) {
				// Get existing variations
				$existing_variations = $product->get_children();
				$variation_ids_to_keep = [];

				// Process each variation
				foreach ($params['variations'] as $variation_data) {
					// Check if this is an existing variation (has an ID not starting with 'temp_')
					if (isset($variation_data['id']) && is_numeric($variation_data['id'])) {
						// Update existing variation
						$variation_id = intval($variation_data['id']);
						$result = $this->wpkin_update_product_variation($product_id, $variation_id, $variation_data);

						if (is_wp_error($result)) {
							throw new \Exception($result->get_error_message());
						}

						$variation_ids_to_keep[] = $variation_id;
					} else {
						// Create new variation
						$new_variation_id = $this->wpkin_create_product_variation($product_id, $variation_data);

						if (is_wp_error($new_variation_id)) {
							throw new \Exception($new_variation_id->get_error_message());
						}

						$variation_ids_to_keep[] = $new_variation_id;
					}
				}

				// Delete variations that aren't in the updated list
				$variations_to_delete = array_diff($existing_variations, $variation_ids_to_keep);

				foreach ($variations_to_delete as $variation_id) {
					// Use force delete to permanently remove variations
					$variation = wc_get_product($variation_id);
					if ($variation && $variation->get_parent_id() == $product_id) {
						$variation->delete(true);
					}
				}

				// Update parent variable product with min/max prices
				\WC_Product_Variable::sync($product_id);
			}

			// Commit transaction
			$wpdb->query('COMMIT');

			$this->log_employee_action( 'product_edited', [
				'product_id'   => $product_id,
				'product_name' => sanitize_text_field( $params['name'] ?? '' ),
			] );

			// Return success response
			return [
				'success' => true,
				'product_id' => $product_id,
				'product_url' => get_permalink($product_id),
				'edit_url' => get_edit_post_link($product_id, 'raw'),
			];
		} catch (\Exception $e) {
			// Rollback transaction
			$wpdb->query('ROLLBACK');

			// Return error response
			return new \WP_Error(
				'product_update_failed',
				$e->getMessage(),
				['status' => 500]
			);
		}
	}

	/**
	 * Get attribute terms for a specific attribute
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error Response object or error.
	 */
	public function wpkin_sm_get_attribute_terms(\WP_REST_Request $request)
	{
		$attribute_id = absint( $request->get_param('id') );

		if (! $attribute_id) {
			return new \WP_Error('invalid_attribute', __('Invalid attribute ID', 'shop-manager'), ['status' => 400]);
		}

		// Get the attribute taxonomy name
		$taxonomy = wc_attribute_taxonomy_name_by_id((int) $attribute_id);

		if (! $taxonomy) {
			return new \WP_Error('invalid_attribute', __('Attribute not found', 'shop-manager'), ['status' => 404]);
		}

		// Get all terms for this attribute
		$terms = get_terms(
			[
				'taxonomy' => $taxonomy,
				'hide_empty' => false,
			]
		);

		if (is_wp_error($terms)) {
			return $terms;
		}

		$data = [];
		foreach ($terms as $term) {
			$data[] = [
				'id' => $term->term_id,
				'name' => $term->name,
				'slug' => $term->slug,
				'count' => $term->count,
			];
		}

		return rest_ensure_response($data);
	}

	// Product Taxonomy

	/**
	 * Get taxonomy terms
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_sm_get_taxonomies($request)
	{
		$params = $request->get_params();
		$taxonomy = isset($params['taxonomy']) ? sanitize_text_field($params['taxonomy']) : 'product_cat';

		$args = [
			'taxonomy'   => $taxonomy,
			'orderby'    => 'menu_order',
			'order'      => 'ASC',
			'hide_empty' => false,
		];

		$terms = get_terms($args);
		$default_category = get_option('default_product_cat', 0);

		$formatted_terms = [];

		if (! is_wp_error($terms)) {
			foreach ($terms as $term) {
				$thumbnail_id = get_term_meta($term->term_id, 'thumbnail_id', true);
				$thumbnail_url = '';

				if ($thumbnail_id) {
					$thumbnail_url = wp_get_attachment_image_url($thumbnail_id, 'thumbnail');
				}

				$display_type = get_term_meta($term->term_id, 'display_type', true);

				$formatted_terms[] = [
					'term_id'       => $term->term_id,
					'name'          => $term->name,
					'slug'          => $term->slug,
					'description'   => $term->description,
					'parent'        => $term->parent,
					'count'         => $term->count,
					'thumbnail_id'  => $thumbnail_id,
					'thumbnail_url' => $thumbnail_url,
					'display_type'  => $display_type,
					'is_default'    => ($taxonomy === 'product_cat' && $term->term_id == $default_category),
				];
			}
		}

		return rest_ensure_response($formatted_terms);
	}

	/**
	 * Add or update taxonomy term
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_sm_add_taxonomy($request)
	{
		$params = $request->get_params();

		$name = sanitize_text_field($params['name']);
		$slug = isset($params['slug']) && ! empty($params['slug']) ? sanitize_title($params['slug']) : '';
		$parent = isset($params['parent']) ? intval($params['parent']) : 0;
		$description = isset($params['description']) ? sanitize_textarea_field($params['description']) : '';
		$display_type = isset($params['display_type']) ? sanitize_text_field($params['display_type']) : '';
		$taxonomy = isset($params['taxonomy']) ? sanitize_text_field($params['taxonomy']) : 'product_cat';

		$args = [
			'description' => $description,
			'parent'      => $parent,
			'slug'        => $slug,
		];

		// Check if we're updating an existing term
		if (isset($params['term_id']) && ! empty($params['term_id'])) {
			$term_id = intval($params['term_id']);
			$result = wp_update_term(
				$term_id,
				$taxonomy,
				[
					'name' => $name,
					'slug' => $slug,
					'description' => $description,
					'parent' => $parent,
				]
			);

			if (is_wp_error($result)) {
				return rest_ensure_response(
					[
						'success' => false,
						'message' => $result->get_error_message(),
					]
				);
			}

			$term_id = $result['term_id'];
		} else {
			// Create new term
			$result = wp_insert_term($name, $taxonomy, $args);

			if (is_wp_error($result)) {
				return rest_ensure_response(
					[
						'success' => false,
						'message' => $result->get_error_message(),
					]
				);
			}

			$term_id = $result['term_id'];
		}

		// Update display type for product categories
		if ($taxonomy === 'product_cat' && ! empty($display_type)) {
			update_term_meta($term_id, 'display_type', $display_type);
		}

		// Handle thumbnail
		if (isset($_FILES['thumbnail']) && ! empty($_FILES['thumbnail'])) {
			require_once ABSPATH . 'wp-admin/includes/image.php';
			require_once ABSPATH . 'wp-admin/includes/file.php';
			require_once ABSPATH . 'wp-admin/includes/media.php';

			$attachment_id = media_handle_upload('thumbnail', 0);

			if (! is_wp_error($attachment_id)) {
				update_term_meta($term_id, 'thumbnail_id', $attachment_id);
			}
		} elseif (isset($params['thumbnail_id']) && ! empty($params['thumbnail_id'])) {
			update_term_meta($term_id, 'thumbnail_id', intval($params['thumbnail_id']));
		}

		$is_update = isset( $params['term_id'] ) && ! empty( $params['term_id'] );
		$this->log_employee_action(
			$is_update ? 'taxonomy_updated' : 'taxonomy_created',
			[ 'type' => $taxonomy, 'name' => $name, 'term_id' => $term_id ]
		);

		return rest_ensure_response(
			[
				'success' => true,
				'term_id' => $term_id,
				'message' => $is_update ? 'Term updated successfully' : 'Term created successfully',
			]
		);
	}

	/**
	 * Delete taxonomy terms
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_sm_delete_taxonomies($request)
	{
		$params = $request->get_params();

		if (! isset($params['term_ids']) || ! is_array($params['term_ids']) || empty($params['term_ids'])) {
			return rest_ensure_response(
				[
					'success' => false,
					'message' => 'No terms specified for deletion',
				]
			);
		}

		$term_ids = array_map('intval', $params['term_ids']);
		$taxonomy = isset($params['taxonomy']) ? sanitize_text_field($params['taxonomy']) : 'product_cat';
		$default_category = ($taxonomy === 'product_cat') ? get_option('default_product_cat', 0) : 0;

		$errors = [];
		$deleted = 0;

		foreach ($term_ids as $term_id) {
			// Don't allow deleting the default category
			if ($taxonomy === 'product_cat' && $term_id === $default_category) {
				$errors[] = 'Cannot delete the default category. Please set another category as default first.';
				continue;
			}

			$result = wp_delete_term($term_id, $taxonomy);

			if (is_wp_error($result)) {
				$errors[] = $result->get_error_message();
			} elseif ($result) {
				++$deleted;
				$this->log_employee_action( 'taxonomy_deleted', [
					'type'    => $taxonomy,
					'term_id' => $term_id,
				] );
			}
		}

		if (! empty($errors)) {
			return rest_ensure_response(
				[
					'success' => $deleted > 0,
					'message' => $deleted . ' terms deleted. Errors: ' . implode(', ', $errors),
					'deleted' => $deleted,
				]
			);
		}

		return rest_ensure_response(
			[
				'success' => true,
				'message' => $deleted . ' terms deleted successfully',
				'deleted' => $deleted,
			]
		);
	}

	/**
	 * Set default product category
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_sm_set_default_category($request)
	{
		$params = $request->get_params();

		if (! isset($params['term_id']) || empty($params['term_id'])) {
			return rest_ensure_response(
				[
					'success' => false,
					'message' => 'No category specified',
				]
			);
		}

		$term_id = intval($params['term_id']);
		$taxonomy = isset($params['taxonomy']) ? sanitize_text_field($params['taxonomy']) : 'product_cat';

		// Only product_cat can be set as default
		if ($taxonomy !== 'product_cat') {
			return rest_ensure_response(
				[
					'success' => false,
					'message' => 'Only product categories can be set as default',
				]
			);
		}

		// Check if the term exists
		$term = get_term($term_id, $taxonomy);
		if (is_wp_error($term) || ! $term) {
			return rest_ensure_response(
				[
					'success' => false,
					'message' => 'Category does not exist',
				]
			);
		}

		update_option('default_product_cat', $term_id);

		$this->log_employee_action( 'taxonomy_default_set', [
			'type'    => 'product_cat',
			'term_id' => $term_id,
			'name'    => $term->name,
		] );

		return rest_ensure_response(
			[
				'success' => true,
				'message' => 'Default category updated successfully',
			]
		);
	}

	/**
	 * Update taxonomy term order
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response
	 */
	public function wpkin_sm_update_taxonomy_order($request)
	{
		$params = $request->get_params();

		if (! isset($params['term_ids']) || ! is_array($params['term_ids']) || empty($params['term_ids'])) {
			return rest_ensure_response(
				[
					'success' => false,
					'message' => 'No terms specified for reordering',
				]
			);
		}

		$term_ids = array_map('intval', $params['term_ids']);

		// Update the menu_order for each term
		foreach ($term_ids as $index => $term_id) {
			update_term_meta($term_id, 'order', $index);
		}

		return rest_ensure_response(
			[
				'success' => true,
				'message' => 'Term order updated successfully',
			]
		);
	}

	// ─────────────────────────────────────────────────────────────────────────
	// Customer Management
	// ─────────────────────────────────────────────────────────────────────────

	/**
	 * Build a single customer summary array from a WP_User object.
	 * Triggers lazy backfill of auto-tags on first read.
	 */
	private function wpkin_format_customer( $user ) {
		$customer = new \WC_Customer( $user->ID );
		$email    = $user->user_email;
		$hash     = md5( strtolower( trim( $email ) ) );

		// Use 'customer' => email so guest orders on the same email are included
		$all_order_ids = wc_get_orders( [
			'customer' => $email,
			'limit'    => -1,
			'return'   => 'ids',
		] );
		$total_orders = count( $all_order_ids );

		$total_spent = 0.0;
		foreach ( $all_order_ids as $oid ) {
			$o = wc_get_order( $oid );
			if ( $o && in_array( $o->get_status(), [ 'completed', 'processing' ], true ) ) {
				$total_spent += (float) $o->get_total();
			}
		}

		// Last order date (all statuses)
		$last_orders = wc_get_orders( [
			'customer' => $email,
			'limit'    => 1,
			'orderby'  => 'date',
			'order'    => 'DESC',
		] );
		$last_order_date = '';
		if ( ! empty( $last_orders ) ) {
			$last_order_date = $last_orders[0]->get_date_created()
				? $last_orders[0]->get_date_created()->date( 'Y-m-d H:i:s' )
				: '';
		}

		// Lazy backfill: calculate auto-tags on first read if not yet stored
		\WPKIN_SHOP_MANAGER\Modules\CustomerTagger::get_or_calculate( $user->ID );

		// Return merged auto + manual tags for display
		$tags = \WPKIN_SHOP_MANAGER\Modules\CustomerTagger::get_display_tags( $user->ID );

		return [
			'id'               => $user->ID,
			'name'             => trim( $user->first_name . ' ' . $user->last_name ) ?: $user->display_name,
			'email'            => $email,
			'avatar'           => 'https://www.gravatar.com/avatar/' . $hash . '?s=40&d=identicon',
			'total_orders'     => (int) $total_orders,
			'total_spent'      => wc_price( $total_spent ),
			'total_spent_raw'  => (float) $total_spent,
			'last_order_date'  => $last_order_date,
			'registered_date'  => $user->user_registered,
			'country'          => $customer->get_billing_country(),
			'city'             => $customer->get_billing_city(),
			'tags'             => $tags,
		];
	}

	/**
	 * GET /customers — paginated customer list with search & filters.
	 */
	public function wpkin_get_customers( $request ) {
		$page       = max( 1, (int) $request->get_param( 'page' ) ?: 1 );
		$per_page   = min( 100, max( 1, (int) $request->get_param( 'per_page' ) ?: 20 ) );
		$search     = sanitize_text_field( $request->get_param( 'search' ) ?: '' );
		$country    = sanitize_text_field( $request->get_param( 'country' ) ?: '' );
		$tag_filter = sanitize_text_field( $request->get_param( 'tag' ) ?: '' );

		// Exclude WordPress/WooCommerce staff roles; include customers, subscribers,
		// and any custom front-end roles (wholesaler, distributor, etc.)
		$staff_roles = apply_filters( 'wpkin_sm_exclude_customer_roles', [
			'administrator',
			'editor',
			'author',
			'contributor',
			'shop_manager',
			'wpseo_manager',
			'wpseo_editor',
		] );

		$args = [
			'number'       => $per_page,
			'paged'        => $page,
			'orderby'      => 'registered',
			'order'        => 'DESC',
			'count_total'  => true,
			'role__not_in' => $staff_roles,
		];

		if ( $search ) {
			$args['search']         = '*' . $search . '*';
			$args['search_columns'] = [ 'user_login', 'user_email', 'display_name', 'user_nicename' ];
		}

		$user_query = new \WP_User_Query( $args );
		$users      = $user_query->get_results();
		$total      = $user_query->get_total();

		$customers = [];
		foreach ( $users as $user ) {
			$c = $this->wpkin_format_customer( $user );

			// Filter by country (post-query since WP_User_Query doesn't support meta-based country filter well)
			if ( $country && $c['country'] !== $country ) {
				continue;
			}

			// Filter by tag
			if ( $tag_filter && ! in_array( $tag_filter, $c['tags'], true ) ) {
				continue;
			}

			$customers[] = $c;
		}

		// Count how many customers still need their first tag calculation.
		// After this page's lazy backfill runs, the number will decrease.
		$pending_count = \WPKIN_SHOP_MANAGER\Modules\CustomerTagger::count_untagged();

		return new \WP_REST_Response( [
			'success'       => true,
			'customers'     => $customers,
			'total'         => (int) $total,
			'page'          => $page,
			'per_page'      => $per_page,
			'total_pages'   => (int) ceil( $total / $per_page ),
			'pending_count' => (int) $pending_count,
		], 200 );
	}

	/**
	 * GET /customers/{id} — single customer profile with stats.
	 */
	public function wpkin_get_customer_profile( $request ) {
		$id   = (int) $request->get_param( 'id' );
		$user = get_user_by( 'id', $id );

		if ( ! $user ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => __( 'Customer not found.', 'shop-manager' ) ], 404 );
		}

		$customer      = new \WC_Customer( $id );
		$base          = $this->wpkin_format_customer( $user );
		$customer_key  = $user->user_email ?: $id;

		// Stats — use email key so guest orders on the same email are included
		$all_order_ids = wc_get_orders( [
			'customer' => $customer_key,
			'limit'    => -1,
			'return'   => 'ids',
		] );
		$order_count = count( $all_order_ids );

		$total_spent  = 0.0;
		$refund_count = 0;
		foreach ( $all_order_ids as $oid ) {
			$o = wc_get_order( $oid );
			if ( ! $o ) {
				continue;
			}
			if ( in_array( $o->get_status(), [ 'completed', 'processing' ], true ) ) {
				$total_spent += (float) $o->get_total();
			}
			if ( $o->get_status() === 'refunded' ) {
				$refund_count++;
			}
		}

		// First order date
		$first_orders = wc_get_orders( [
			'customer' => $customer_key,
			'limit'    => 1,
			'orderby'  => 'date',
			'order'    => 'ASC',
		] );
		$first_order_date = '';
		if ( ! empty( $first_orders ) ) {
			$first_order_date = $first_orders[0]->get_date_created()
				? $first_orders[0]->get_date_created()->date( 'Y-m-d H:i:s' )
				: '';
		}

		$avg_order_value = $order_count > 0 ? $total_spent / $order_count : 0;

		$stats = [
			'total_spent'      => wc_price( $total_spent ),
			'total_orders'     => $order_count,
			'avg_order_value'  => wc_price( $avg_order_value ),
			'refund_count'     => $refund_count,
			'first_order_date' => $first_order_date,
		];

		// Billing & shipping
		$billing = [
			'first_name' => $customer->get_billing_first_name(),
			'last_name'  => $customer->get_billing_last_name(),
			'company'    => $customer->get_billing_company(),
			'address_1'  => $customer->get_billing_address_1(),
			'address_2'  => $customer->get_billing_address_2(),
			'city'       => $customer->get_billing_city(),
			'state'      => $customer->get_billing_state(),
			'postcode'   => $customer->get_billing_postcode(),
			'country'    => $customer->get_billing_country(),
			'phone'      => $customer->get_billing_phone(),
			'email'      => $customer->get_billing_email(),
		];

		$shipping = [
			'first_name' => $customer->get_shipping_first_name(),
			'last_name'  => $customer->get_shipping_last_name(),
			'company'    => $customer->get_shipping_company(),
			'address_1'  => $customer->get_shipping_address_1(),
			'address_2'  => $customer->get_shipping_address_2(),
			'city'       => $customer->get_shipping_city(),
			'state'      => $customer->get_shipping_state(),
			'postcode'   => $customer->get_shipping_postcode(),
			'country'    => $customer->get_shipping_country(),
		];

		return new \WP_REST_Response( [
			'success'  => true,
			'customer' => array_merge( $base, [
				'billing'  => $billing,
				'shipping' => $shipping,
				'stats'    => $stats,
			] ),
		], 200 );
	}

	/**
	 * PUT /customers/{id} — update billing/shipping address.
	 */
	public function wpkin_update_customer( $request ) {
		$id   = (int) $request->get_param( 'id' );
		$user = get_user_by( 'id', $id );

		if ( ! $user ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => __( 'Customer not found.', 'shop-manager' ) ], 404 );
		}

		$data     = $request->get_json_params();
		$customer = new \WC_Customer( $id );

		$billing_fields  = [ 'first_name', 'last_name', 'company', 'address_1', 'address_2', 'city', 'state', 'postcode', 'country', 'phone', 'email' ];
		$shipping_fields = [ 'first_name', 'last_name', 'company', 'address_1', 'address_2', 'city', 'state', 'postcode', 'country' ];

		if ( isset( $data['billing'] ) && is_array( $data['billing'] ) ) {
			foreach ( $billing_fields as $field ) {
				if ( isset( $data['billing'][ $field ] ) ) {
					$method = 'set_billing_' . $field;
					$customer->$method( sanitize_text_field( $data['billing'][ $field ] ) );
				}
			}
		}

		if ( isset( $data['shipping'] ) && is_array( $data['shipping'] ) ) {
			foreach ( $shipping_fields as $field ) {
				if ( isset( $data['shipping'][ $field ] ) ) {
					$method = 'set_shipping_' . $field;
					$customer->$method( sanitize_text_field( $data['shipping'][ $field ] ) );
				}
			}
		}

		$customer->save();

		$this->log_employee_action( 'customer_updated', [ 'customer_id' => $id ] );

		return new \WP_REST_Response( [ 'success' => true, 'message' => __( 'Customer updated.', 'shop-manager' ) ], 200 );
	}

	/**
	 * GET /customers/{id}/orders — recent order history.
	 */
	public function wpkin_get_customer_order_history( $request ) {
		$id    = (int) $request->get_param( 'id' );
		$limit = min( 50, max( 1, (int) $request->get_param( 'limit' ) ?: 10 ) );
		$user  = get_user_by( 'id', $id );

		$orders = wc_get_orders( [
			'customer' => $user ? $user->user_email : $id,
			'limit'    => $limit,
			'orderby'  => 'date',
			'order'    => 'DESC',
		] );

		$result = [];
		foreach ( $orders as $order ) {
			$result[] = [
				'id'          => $order->get_id(),
				'date'        => $order->get_date_created() ? $order->get_date_created()->date( 'Y-m-d H:i:s' ) : '',
				'status'      => $order->get_status(),
				'status_label'=> wc_get_order_status_name( $order->get_status() ),
				'total'       => wc_price( $order->get_total() ),
				'items_count' => count( $order->get_items() ),
			];
		}

		return new \WP_REST_Response( [ 'success' => true, 'orders' => $result ], 200 );
	}

	/**
	 * GET /customers/{id}/notes
	 */
	public function wpkin_get_customer_notes( $request ) {
		$id    = (int) $request->get_param( 'id' );
		$notes = get_user_meta( $id, '_sm_customer_notes', true );
		if ( ! is_array( $notes ) ) {
			$notes = [];
		}
		usort( $notes, fn( $a, $b ) => strcmp( $b['created_at'], $a['created_at'] ) );
		return new \WP_REST_Response( [ 'success' => true, 'notes' => $notes ], 200 );
	}

	/**
	 * POST /customers/{id}/notes
	 */
	public function wpkin_add_customer_note( $request ) {
		$id   = (int) $request->get_param( 'id' );
		$data = $request->get_json_params();
		$text = isset( $data['text'] ) ? sanitize_textarea_field( $data['text'] ) : '';

		if ( ! $text ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => __( 'Note text is required.', 'shop-manager' ) ], 400 );
		}

		$current_user = wp_get_current_user();
		$notes        = get_user_meta( $id, '_sm_customer_notes', true );
		if ( ! is_array( $notes ) ) {
			$notes = [];
		}

		$new_note = [
			'id'               => uniqid( 'note_' ),
			'text'             => $text,
			'created_by_name'  => $current_user->display_name ?: $current_user->user_login,
			'created_at'       => current_time( 'Y-m-d H:i:s' ),
		];

		array_unshift( $notes, $new_note );
		update_user_meta( $id, '_sm_customer_notes', $notes );

		$this->log_employee_action( 'customer_note_added', [ 'customer_id' => $id ] );

		return new \WP_REST_Response( [ 'success' => true, 'note' => $new_note ], 201 );
	}

	/**
	 * PUT /customers/{id}/tags — update manual tags (never overwrites auto-tags).
	 */
	public function wpkin_update_customer_tags( $request ) {
		$id   = (int) $request->get_param( 'id' );
		$data = $request->get_json_params();

		if ( ! get_user_by( 'id', $id ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => __( 'Customer not found.', 'shop-manager' ) ], 404 );
		}

		$tags = isset( $data['tags'] ) && is_array( $data['tags'] )
			? array_values( array_map( 'sanitize_text_field', $data['tags'] ) )
			: [];

		update_user_meta( $id, '_sm_customer_tags_manual', $tags );

		$this->log_employee_action( 'customer_tags_updated', [ 'customer_id' => $id ] );

		$display_tags = \WPKIN_SHOP_MANAGER\Modules\CustomerTagger::get_display_tags( $id );

		return new \WP_REST_Response( [ 'success' => true, 'tags' => $display_tags ], 200 );
	}

	/**
	 * POST /customers/{id}/tags/refresh — force re-calculate auto-tags for one customer.
	 */
	public function wpkin_refresh_customer_tags( $request ) {
		$id = (int) $request->get_param( 'id' );

		if ( ! get_user_by( 'id', $id ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => __( 'Customer not found.', 'shop-manager' ) ], 404 );
		}

		$auto_tags    = \WPKIN_SHOP_MANAGER\Modules\CustomerTagger::recalculate( $id );
		$display_tags = \WPKIN_SHOP_MANAGER\Modules\CustomerTagger::get_display_tags( $id );

		return new \WP_REST_Response( [ 'success' => true, 'auto_tags' => $auto_tags, 'tags' => $display_tags ], 200 );
	}

	/**
	 * POST /customers/tags/refresh-all — recalculate tags for all non-staff customers.
	 */
	public function wpkin_refresh_all_customer_tags( $_request = null ) {
		$staff_roles = apply_filters( 'wpkin_sm_exclude_customer_roles', [
			'administrator', 'editor', 'author', 'contributor',
			'shop_manager', 'wpseo_manager', 'wpseo_editor',
		] );

		$user_ids = ( new \WP_User_Query( [
			'fields'       => 'ID',
			'number'       => -1,
			'role__not_in' => $staff_roles,
			'count_total'  => false,
		] ) )->get_results();

		$count = 0;
		foreach ( $user_ids as $uid ) {
			\WPKIN_SHOP_MANAGER\Modules\CustomerTagger::recalculate( (int) $uid );
			$count++;
		}

		return new \WP_REST_Response( [ 'success' => true, 'refreshed' => $count ], 200 );
	}

	/**
	 * Get product reviews with filtering, sorting, and pagination
	 *
	 * @param $request The request object.
	 * @return mixed The response.
	 */
	public function wpkin_sm_get_reviews($request)
	{
		// Get parameters
		$page = isset($request['page']) ? absint($request['page']) : 1;
		$per_page = isset($request['per_page']) ? absint($request['per_page']) : 10;
		$status = isset($request['status']) ? sanitize_text_field($request['status']) : 'all';
		$search = isset($request['search']) ? sanitize_text_field($request['search']) : '';
		$product_ids = isset($request['product']) ? array_map('absint', explode(',', $request['product'])) : [];
		$ratings = isset($request['rating']) ? array_map('absint', explode(',', $request['rating'])) : [];

		// Get sorting parameters
		$orderby = isset($request['orderby']) ? sanitize_text_field($request['orderby']) : 'date';
		$order = isset($request['order']) ? sanitize_text_field($request['order']) : 'desc';

		// Calculate offset
		$offset = ($page - 1) * $per_page;

		// Build query args
		$args = [
			'post_type'      => 'product',
			'number'         => $per_page,
			'offset'         => $offset,
			'post_status'    => 'publish',
		];

		// Add status filter
		if ($status !== 'all') {
			if ($status === 'pending') {
				$args['status'] = 'hold';
			} elseif ($status === 'approved') {
				$args['status'] = 'approve';
			} else {
				$args['status'] = $status;
			}
		} else {
			// For 'all' tab, include both approved and pending reviews
			$args['status'] = ['approve', 'hold'];
		}

		// Add search filter
		if (! empty($search)) {
			$args['search'] = $search;
		}

		// Add product filter
		if (! empty($product_ids)) {
			$args['post__in'] = $product_ids;
		}

		// Add sorting
		switch ($orderby) {
			case 'date':
				$args['orderby'] = 'comment_date';
				$args['order'] = $order;
				break;
			case 'author':
				$args['orderby'] = 'comment_author';
				$args['order'] = $order;
				break;
			case 'rating':
				$args['meta_key'] = 'rating';
				$args['orderby'] = 'meta_value_num';
				$args['order'] = $order;
				break;
			case 'product':
				// We'll sort by product name after fetching the reviews
				$args['orderby'] = 'comment_date';
				$args['order'] = 'desc';
				break;
			default:
				$args['orderby'] = 'comment_date';
				$args['order'] = 'desc';
				break;
		}

		// Get reviews
		$reviews_query = new \WP_Comment_Query();
		$reviews = $reviews_query->query($args);

		// Get total count for pagination
		$count_args = $args;
		$count_args['count'] = true;
		$count_args['offset'] = 0;
		$count_args['number'] = 0;
		$total = $reviews_query->query($count_args);

		// Format reviews for response
		$formatted_reviews = [];
		foreach ($reviews as $review) {
			// Skip if not a product review
			if (get_post_type($review->comment_post_ID) !== 'product') {
				continue;
			}

			// Get product
			$product = wc_get_product($review->comment_post_ID);
			if (! $product) {
				continue;
			}

			// Get review rating
			$rating = get_comment_meta($review->comment_ID, 'rating', true);

			// Filter by rating if specified
			if (! empty($ratings) && ! in_array((int) $rating, $ratings)) {
				continue;
			}

			// Get review status
			$status = wp_get_comment_status($review->comment_ID);
			if ($status === 'approved') {
				$status = 'approved';
			} elseif ($status === 'unapproved') {
				$status = 'pending';
			}

			// Get reply if exists
			$reply = null;
			$reply_date = null;
			$replies = get_comments(
				[
					'parent' => $review->comment_ID,
					'status' => 'approve',
					'number' => 1,
				]
			);

			if (! empty($replies)) {
				$reply = $replies[0]->comment_content;
				$reply_date = date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($replies[0]->comment_date));
			}

			// Format review data
			$formatted_reviews[] = [
				'id'          => $review->comment_ID,
				'author'      => $review->comment_author,
				'email'       => $review->comment_author_email,
				'content'     => $review->comment_content,
				'date'        => date_i18n(get_option('date_format'), strtotime($review->comment_date)),
				'rating'      => (int) $rating,
				'status'      => $status,
				'product'     => $product->get_name(),
				'product_id'  => $product->get_id(),
				'product_url' => get_edit_post_link($product->get_id()),
				'reply'       => $reply,
				'reply_date'  => $reply_date,
			];
		}

		// Sort by product name if needed
		if ($orderby === 'product') {
			usort(
				$formatted_reviews,
				function ($a, $b) use ($order) {
					if ($order === 'asc') {
						return strcmp($a['product'], $b['product']);
					} else {
						return strcmp($b['product'], $a['product']);
					}
				}
			);
		}

		// Get all products for filter dropdown
		$products = wc_get_products(
			[
				'limit'  => -1,
				'status' => 'publish',
				'return' => 'ids',
			]
		);

		$product_options = [];
		foreach ($products as $product_id) {
			$product = wc_get_product($product_id);
			if ($product) {
				$product_options[] = [
					'id'   => $product_id,
					'name' => $product->get_name(),
				];
			}
		}

		// Return response
		return rest_ensure_response(
			[
				'reviews'  => $formatted_reviews,
				'total'    => $total,
				'products' => $product_options,
			]
		);
	}

	/**
	 * Get counts of reviews by status
	 *
	 * @return WP_REST_Response The response.
	 */
	public function wpkin_sm_get_review_counts()
	{
		global $wpdb;

		// Get counts for different statuses
		$counts = [
			'all' => 0,
			'pending' => 0,
			'approved' => 0,
			'spam' => 0,
			'trash' => 0,
		];

		// Get product IDs — use prepare() to satisfy wpdb coding standards.
		$product_ids = $wpdb->get_col(
			$wpdb->prepare(
				"SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND post_status = %s",
				'product',
				'publish'
			)
		);

		if ( empty( $product_ids ) ) {
			return rest_ensure_response( [ 'counts' => $counts ] );
		}

		// Cast every ID to int before building the IN() list.
		$product_ids     = array_map( 'intval', $product_ids );
		$placeholders    = implode( ',', array_fill( 0, count( $product_ids ), '%d' ) );

		$approved_count = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$wpdb->comments} WHERE comment_post_ID IN ({$placeholders}) AND comment_approved = %s",
				array_merge( $product_ids, [ '1' ] )
			)
		);

		$pending_count = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$wpdb->comments} WHERE comment_post_ID IN ({$placeholders}) AND comment_approved = %s",
				array_merge( $product_ids, [ '0' ] )
			)
		);

		$spam_count = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$wpdb->comments} WHERE comment_post_ID IN ({$placeholders}) AND comment_approved = %s",
				array_merge( $product_ids, [ 'spam' ] )
			)
		);

		$trash_count = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$wpdb->comments} WHERE comment_post_ID IN ({$placeholders}) AND comment_approved = %s",
				array_merge( $product_ids, [ 'trash' ] )
			)
		);

		// Update counts
		$counts['approved'] = (int) $approved_count;
		$counts['pending'] = (int) $pending_count;
		$counts['spam'] = (int) $spam_count;
		$counts['trash'] = (int) $trash_count;
		$counts['all'] = $counts['approved'] + $counts['pending']; // All includes approved and pending

		return rest_ensure_response(['counts' => $counts]);
	}

	/**
	 * Update review status (approve, unapprove, spam, trash)
	 *
	 * @param WP_REST_Request $request The request object.
	 * @return WP_REST_Response The response.
	 */
	public function wpkin_sm_update_review_status($request)
	{
		$review_ids = isset($request['review_ids']) ? array_map('absint', $request['review_ids']) : [];
		$status = isset($request['status']) ? sanitize_text_field($request['status']) : '';

		if (empty($review_ids) || empty($status)) {
			return rest_ensure_response(
				[
					'success' => false,
					'message' => __('Missing required parameters', 'shop-manager'),
				]
			);
		}

		$updated = 0;
		$errors = 0;

		foreach ($review_ids as $review_id) {
			$result = false;

			switch ($status) {
				case 'approved':
					$result = wp_set_comment_status($review_id, 'approve');
					break;
				case 'pending':
					$result = wp_set_comment_status($review_id, 'hold');
					break;
				case 'spam':
					$result = wp_spam_comment($review_id);
					break;
				case 'trash':
					$result = wp_trash_comment($review_id);
					break;
			}

			if ($result) {
				++$updated;
			} else {
				++$errors;
			}
		}

		if ($updated > 0) {
			$this->log_employee_action( 'review_status_updated', [
				'review_ids' => $review_ids,
				'status'     => $status,
			] );

			$message = sprintf(
				_n(
					'%d review updated successfully.',
					'%d reviews updated successfully.',
					$updated,
					'shop-manager'
				),
				$updated
			);

			if ($errors > 0) {
				$message .= ' ' . sprintf(
					_n(
						'%d review could not be updated.',
						'%d reviews could not be updated.',
						$errors,
						'shop-manager'
					),
					$errors
				);
			}

			return rest_ensure_response(
				[
					'success' => true,
					'message' => $message,
				]
			);
		}

		return rest_ensure_response(
			[
				'success' => false,
				'message' => __('Failed to update review status', 'shop-manager'),
			]
		);
	}

	/**
	 * Reply to a product review
	 *
	 * @param WP_REST_Request $request The request object.
	 * @return WP_REST_Response The response.
	 */
	public function wpkin_sm_reply_to_review($request)
	{
		$review_id = isset($request['review_id']) ? absint($request['review_id']) : 0;
		$content = isset($request['content']) ? sanitize_textarea_field($request['content']) : '';

		if (empty($review_id) || empty($content)) {
			return rest_ensure_response(
				[
					'success' => false,
					'message' => __('Missing required parameters', 'shop-manager'),
				]
			);
		}

		// Get the original review
		$review = get_comment($review_id);
		if (! $review) {
			return rest_ensure_response(
				[
					'success' => false,
					'message' => __('Review not found', 'shop-manager'),
				]
			);
		}

		// Check if a reply already exists
		$existing_replies = get_comments(
			[
				'parent' => $review_id,
				'status' => 'approve',
				'number' => 1,
			]
		);

		if (! empty($existing_replies)) {
			// Update existing reply
			$reply_id = $existing_replies[0]->comment_ID;
			$result = wp_update_comment(
				[
					'comment_ID'      => $reply_id,
					'comment_content' => $content,
				]
			);
			if ($result) {
				$this->log_employee_action( 'review_replied', [
					'review_id'  => $review_id,
					'product_id' => (int) $review->comment_post_ID,
				] );
				return rest_ensure_response(
					[
						'success' => true,
						'message' => __('Reply updated successfully', 'shop-manager'),
					]
				);
			} else {
				return rest_ensure_response(
					[
						'success' => false,
						'message' => __('Failed to update reply', 'shop-manager'),
					]
				);
			}
		} else {
			// Create new reply
			$current_user = wp_get_current_user();

			$reply_data = [
				'comment_post_ID'      => $review->comment_post_ID,
				'comment_author'       => $current_user->display_name,
				'comment_author_email' => $current_user->user_email,
				'comment_author_url'   => '',
				'comment_content'      => $content,
				'comment_type'         => 'comment',
				'comment_parent'       => $review_id,
				'user_id'              => $current_user->ID,
				'comment_approved'     => 1,
			];

			$reply_id = wp_insert_comment($reply_data);

			if ($reply_id) {
				$this->log_employee_action( 'review_replied', [
					'review_id'  => $review_id,
					'product_id' => (int) $review->comment_post_ID,
				] );
				return rest_ensure_response(
					[
						'success' => true,
						'message' => __('Reply added successfully', 'shop-manager'),
					]
				);
			} else {
				return rest_ensure_response(
					[
						'success' => false,
						'message' => __('Failed to add reply', 'shop-manager'),
					]
				);
			}
		}
	}

	/**
	 * Resend a WooCommerce order email.
	 */
	public function wpkin_resend_order_email( $request ) {
		$order_id   = (int) $request->get_param( 'id' );
		$email_type = sanitize_key( $request->get_param( 'email_type' ) ?: 'customer_invoice' );

		$order = wc_get_order( $order_id );
		if ( ! $order ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'Order not found.' ], 404 );
		}

		$this->wpkin_send_order_email( $order, $email_type );
		$this->log_order_action(
			$order_id,
			'order_email_resent',
			[ 'email_type' => $email_type ],
			sprintf( __( '%s email sent.', 'shop-manager' ), str_replace( '_', ' ', $email_type ) )
		);

		return rest_ensure_response( [ 'success' => true, 'message' => __( 'Email sent successfully.', 'shop-manager' ) ] );
	}

	public function wpkin_bulk_resend_email( $request ) {
		$ids        = array_filter( array_map( 'intval', (array) $request->get_param( 'ids' ) ) );
		$email_type = sanitize_key( $request->get_param( 'email_type' ) ?: 'customer_invoice' );

		if ( empty( $ids ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'No order IDs provided.' ], 400 );
		}

		WC()->payment_gateways();
		WC()->shipping();

		$sent = 0;
		foreach ( $ids as $order_id ) {
			$order = wc_get_order( $order_id );
			if ( $order ) {
				$this->wpkin_send_order_email( $order, $email_type );
				$this->log_order_action( $order_id, 'order_email_resent', [ 'email_type' => $email_type ] );
				$sent++;
			}
		}

		return rest_ensure_response( [
			'success' => true,
			'message' => sprintf( _n( '%d email sent.', '%d emails sent.', $sent, 'shop-manager' ), $sent ),
		] );
	}

	/**
	 * Send a single WooCommerce order email — mirrors WC's own resend logic exactly.
	 */
	/**
	 * Log any employee action to the activity table.
	 * Silently no-ops for non-oxi_sm users (admins, etc.).
	 */
	private function log_employee_action( string $action, array $details = [] ): void {
		$user = wp_get_current_user();
		if ( ! $user->ID ) {
			return;
		}
		$oxi_roles = \WPKIN_SHOP_MANAGER\Modules\EmployeeManager::get_oxi_roles();
		if ( empty( array_intersect( $oxi_roles, (array) $user->roles ) ) ) {
			return;
		}
		\WPKIN_SHOP_MANAGER\Modules\EmployeeManager::log_activity( $user->ID, $action, $details );
	}

	/**
	 * Log employee/role management actions — records for any authenticated user
	 * (admin or employee) since both can manage employees and roles from the dashboard.
	 */
	private function log_management_action( string $action, array $details = [] ): void {
		$user = wp_get_current_user();
		if ( ! $user->ID ) {
			return;
		}
		\WPKIN_SHOP_MANAGER\Modules\EmployeeManager::log_activity( $user->ID, $action, $details );
	}

	/**
	 * Log an employee order action and (optionally) add a WooCommerce order note.
	 */
	private function log_order_action( int $order_id, string $action, array $extra = [], ?string $note_text = null ): void {
		$this->log_employee_action( $action, array_merge( [ 'order_id' => $order_id ], $extra ) );
		if ( $note_text ) {
			$order = wc_get_order( $order_id );
			if ( $order ) {
				$order->add_order_note( $note_text, 0, true );
				$order->save();
			}
		}
	}

	private function wpkin_send_order_email( $order, string $email_type ): void {
		WC()->payment_gateways();
		WC()->shipping();

		$mailer = WC()->mailer();

		if ( 'customer_invoice' === $email_type ) {
			// WC convenience method handles everything including enabled check bypass.
			$mailer->customer_invoice( $order );
			return;
		}

		if ( 'new_order' === $email_type ) {
			// WC_Email_New_Order blocks resend unless this filter returns true.
			$new_order_email = $mailer->emails['WC_Email_New_Order'] ?? null;
			if ( $new_order_email instanceof \WC_Email_New_Order ) {
				add_filter( 'woocommerce_new_order_email_allows_resend', '__return_true' );
				$new_order_email->trigger( $order->get_id(), $order, true );
				remove_filter( 'woocommerce_new_order_email_allows_resend', '__return_true' );
			}
			return;
		}

		// All other emails: find by id property and trigger with order object.
		foreach ( $mailer->get_emails() as $email ) {
			if ( isset( $email->id ) && $email->id === $email_type && method_exists( $email, 'trigger' ) ) {
				$email->trigger( $order->get_id(), $order );
				break;
			}
		}
	}

	// ─── Employee Management ─────────────────────────────────────────────────

	/**
	 * Format a WP_User as an employee object for API responses.
	 */
	private function wpkin_format_employee( \WP_User $user ): array {
		global $wpdb;

		$oxi_role_labels = \WPKIN_SHOP_MANAGER\Modules\EmployeeManager::get_role_labels();
		$oxi_roles       = \WPKIN_SHOP_MANAGER\Modules\EmployeeManager::get_oxi_roles();
		$role            = '';
		foreach ( $oxi_roles as $r ) {
			if ( in_array( $r, (array) $user->roles, true ) ) {
				$role = $r;
				break;
			}
		}

		$today_start    = gmdate( 'Y-m-d' );
		$week_start     = gmdate( 'Y-m-d', strtotime( 'monday this week' ) );
		$month_start    = gmdate( 'Y-m-01' );
		$activity_table = $wpdb->prefix . 'oxi_sm_activity_log';
		$orders_today   = 0;
		$orders_week    = 0;
		$orders_month   = 0;
		$last_active    = null;

		$suppress = $wpdb->suppress_errors( true );
		$table_ok = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $activity_table ) ) === $activity_table;

		if ( $table_ok ) {
			$orders_today = (int) $wpdb->get_var(
				$wpdb->prepare(
					"SELECT COUNT(*) FROM {$activity_table} WHERE user_id = %d AND action = 'order_status_changed' AND created_at >= %s",
					$user->ID,
					$today_start . ' 00:00:00'
				)
			);

			$orders_week = (int) $wpdb->get_var(
				$wpdb->prepare(
					"SELECT COUNT(*) FROM {$activity_table} WHERE user_id = %d AND action = 'order_status_changed' AND created_at >= %s",
					$user->ID,
					$week_start . ' 00:00:00'
				)
			);

			$orders_month = (int) $wpdb->get_var(
				$wpdb->prepare(
					"SELECT COUNT(*) FROM {$activity_table} WHERE user_id = %d AND action = 'order_status_changed' AND created_at >= %s",
					$user->ID,
					$month_start . ' 00:00:00'
				)
			);

			$last_active = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT created_at FROM {$activity_table} WHERE user_id = %d ORDER BY created_at DESC LIMIT 1",
					$user->ID
				)
			);
		}
		$wpdb->suppress_errors( $suppress );

		return [
			'id'                    => $user->ID,
			'name'                  => $user->display_name,
			'email'                 => $user->user_email,
			'role'                  => $role,
			'role_label'            => $oxi_role_labels[ $role ] ?? $role,
			'avatar'                => get_avatar_url( $user->ID ),
			'registered'            => $user->user_registered,
			'last_active'           => $last_active,
			'stats' => [
				'orders_processed_today' => $orders_today,
				'orders_processed_week'  => $orders_week,
				'orders_processed_month' => $orders_month,
			],
			'permissions'           => \WPKIN_SHOP_MANAGER\Modules\EmployeeManager::get_user_oxi_permissions( $user ),
		];
	}

	/**
	 * GET /employees — list all employees (users with oxi_sm_* roles).
	 */
	public function wpkin_get_employees( \WP_REST_Request $request ): \WP_REST_Response {
		$oxi_roles = \WPKIN_SHOP_MANAGER\Modules\EmployeeManager::get_oxi_roles();
		$page      = max( 1, (int) ( $request->get_param( 'page' ) ?? 1 ) );
		$per_page  = max( 1, min( 100, (int) ( $request->get_param( 'per_page' ) ?? 20 ) ) );
		$search    = sanitize_text_field( $request->get_param( 'search' ) ?? '' );
		$role      = sanitize_key( $request->get_param( 'role' ) ?? '' );

		$query_args = [
			'role__in' => $role && in_array( $role, $oxi_roles, true ) ? [ $role ] : $oxi_roles,
			'number'   => $per_page,
			'offset'   => ( $page - 1 ) * $per_page,
			'orderby'  => 'registered',
			'order'    => 'DESC',
		];

		if ( $search !== '' ) {
			$query_args['search']         = '*' . $search . '*';
			$query_args['search_columns'] = [ 'user_login', 'user_email', 'display_name' ];
		}

		$user_query = new \WP_User_Query( $query_args );
		$total      = $user_query->get_total();
		$employees  = array_map( [ $this, 'wpkin_format_employee' ], $user_query->get_results() );

		return rest_ensure_response( [
			'success'    => true,
			'employees'  => $employees,
			'total'      => $total,
			'page'       => $page,
			'per_page'   => $per_page,
			'total_pages' => (int) ceil( $total / $per_page ),
		] );
	}

	/**
	 * GET /employees/{id} — single employee profile + stats.
	 */
	public function wpkin_get_employee( \WP_REST_Request $request ): \WP_REST_Response {
		$id   = (int) $request->get_param( 'id' );
		$user = get_userdata( $id );

		if ( ! $user ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'Employee not found.' ], 404 );
		}

		$oxi_roles = \WPKIN_SHOP_MANAGER\Modules\EmployeeManager::get_oxi_roles();
		if ( empty( array_intersect( $oxi_roles, (array) $user->roles ) ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'User is not an employee.' ], 403 );
		}

		return rest_ensure_response( [
			'success'  => true,
			'employee' => $this->wpkin_format_employee( $user ),
		] );
	}

	/**
	 * POST /employees — create employee (name, email, role, send_email).
	 */
	public function wpkin_create_employee( \WP_REST_Request $request ): \WP_REST_Response {
		$data  = $request->get_json_params();
		$name  = sanitize_text_field( $data['name']  ?? '' );
		$email = sanitize_email( $data['email']       ?? '' );
		$role  = sanitize_key( $data['role']          ?? '' );
		$send  = (bool) ( $data['send_welcome_email'] ?? true );

		if ( ! $name || ! $email || ! $role ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'name, email and role are required.' ], 400 );
		}

		if ( ! is_email( $email ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'Invalid email address.' ], 400 );
		}

		$oxi_roles = \WPKIN_SHOP_MANAGER\Modules\EmployeeManager::get_oxi_roles();
		if ( ! in_array( $role, $oxi_roles, true ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'Invalid employee role.' ], 400 );
		}

		if ( email_exists( $email ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'An account with this email already exists.' ], 409 );
		}

		$password = wp_generate_password( 12, true );
		$username = sanitize_user( strtolower( str_replace( ' ', '.', $name ) ) . '_' . wp_rand( 100, 999 ) );

		$user_id = wp_create_user( $username, $password, $email );

		if ( is_wp_error( $user_id ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => $user_id->get_error_message() ], 500 );
		}

		$user = get_userdata( $user_id );
		$user->set_role( $role );
		wp_update_user( [ 'ID' => $user_id, 'display_name' => $name ] );

		if ( $send ) {
			$role_labels = \WPKIN_SHOP_MANAGER\Modules\EmployeeManager::get_role_labels();
			$site_name   = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
			$key         = get_password_reset_key( $user );
			$setup_url   = ! is_wp_error( $key )
				? add_query_arg(
					[
						'sm_action' => 'set-password',
						'sm_key'    => $key,
						'sm_login'  => $user->user_login,
					],
					home_url( '/sm-dashboard/' )
				)
				: home_url( '/sm-dashboard/' );

			$subject = sprintf( __( 'Welcome to the team — %s', 'shop-manager' ), $site_name );
			$message  = sprintf( "Hi %s,\r\n\r\n", $name );
			$message .= sprintf( "Your account has been created on %s as %s.\r\n\r\n", $site_name, $role_labels[ $role ] ?? $role );
			$message .= "Click the link below to set your password and access the dashboard:\r\n\r\n";
			$message .= $setup_url . "\r\n\r\n";
			$message .= "This link will expire in 24 hours.\r\n\r\n";
			$message .= $site_name;
			wp_mail( $email, $subject, $message );
		}

		$this->log_management_action( 'employee_created', [
			'employee_id'   => $user_id,
			'employee_name' => $name,
			'role'          => $role,
		] );

		return new \WP_REST_Response( [
			'success'  => true,
			'message'  => 'Employee created successfully.',
			'employee' => $this->wpkin_format_employee( get_userdata( $user_id ) ),
		], 201 );
	}

	/**
	 * PUT /employees/{id} — update role or display_name.
	 */
	public function wpkin_update_employee( \WP_REST_Request $request ): \WP_REST_Response {
		$id   = (int) $request->get_param( 'id' );
		$user = get_userdata( $id );

		if ( ! $user ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'Employee not found.' ], 404 );
		}

		$oxi_roles = \WPKIN_SHOP_MANAGER\Modules\EmployeeManager::get_oxi_roles();
		if ( empty( array_intersect( $oxi_roles, (array) $user->roles ) ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'User is not an employee.' ], 403 );
		}

		$data        = $request->get_json_params();
		$update_args = [ 'ID' => $id ];

		if ( ! empty( $data['name'] ) ) {
			$update_args['display_name'] = sanitize_text_field( $data['name'] );
		}

		if ( ! empty( $data['role'] ) && in_array( $data['role'], $oxi_roles, true ) ) {
			$user->set_role( sanitize_key( $data['role'] ) );
		}

		wp_update_user( $update_args );

		$log_details = [ 'employee_id' => $id, 'employee_name' => $user->display_name ];
		if ( ! empty( $data['role'] ) ) {
			$log_details['role'] = $data['role'];
		}
		if ( ! empty( $data['name'] ) ) {
			$log_details['new_name'] = $data['name'];
		}
		$this->log_management_action( 'employee_updated', $log_details );

		return rest_ensure_response( [
			'success'  => true,
			'message'  => 'Employee updated.',
			'employee' => $this->wpkin_format_employee( get_userdata( $id ) ),
		] );
	}

	/**
	 * POST /employees/{id}/reset-password — send a password reset email.
	 */
	public function wpkin_reset_employee_password( \WP_REST_Request $request ): \WP_REST_Response {
		$id   = (int) $request->get_param( 'id' );
		$user = get_userdata( $id );

		if ( ! $user ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'Employee not found.' ], 404 );
		}

		$oxi_roles = \WPKIN_SHOP_MANAGER\Modules\EmployeeManager::get_oxi_roles();
		if ( empty( array_intersect( $oxi_roles, (array) $user->roles ) ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'User is not an employee.' ], 403 );
		}

		$key = get_password_reset_key( $user );
		if ( is_wp_error( $key ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'Failed to generate reset link.' ], 500 );
		}

		$reset_link = add_query_arg(
			[
				'sm_action' => 'set-password',
				'sm_key'    => $key,
				'sm_login'  => $user->user_login,
			],
			home_url( '/sm-dashboard/' )
		);

		$site_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
		$subject   = sprintf( '[%s] Password Reset Request', $site_name );

		$message  = sprintf( "Hi %s,\r\n\r\n", $user->display_name ?: $user->user_login );
		$message .= "A password reset was requested for your account on {$site_name}.\r\n\r\n";
		$message .= "Click the link below to set a new password:\r\n\r\n";
		$message .= $reset_link . "\r\n\r\n";
		$message .= "This link will expire in 24 hours.\r\n\r\n";
		$message .= "If you did not request this, please ignore this email.\r\n";

		$sent = wp_mail( $user->user_email, $subject, $message );

		if ( ! $sent ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'Failed to send email. Please check your mail configuration.' ], 500 );
		}

		$this->log_management_action( 'employee_password_reset', [
			'employee_id'   => $id,
			'employee_name' => $user->display_name ?: $user->user_login,
		] );

		return rest_ensure_response( [ 'success' => true ] );
	}

	/**
	 * DELETE /employees/{id} — delete user account.
	 */
	public function wpkin_delete_employee( \WP_REST_Request $request ): \WP_REST_Response {
		$id   = (int) $request->get_param( 'id' );
		$user = get_userdata( $id );

		if ( ! $user ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'Employee not found.' ], 404 );
		}

		$oxi_roles = \WPKIN_SHOP_MANAGER\Modules\EmployeeManager::get_oxi_roles();
		if ( empty( array_intersect( $oxi_roles, (array) $user->roles ) ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'User is not an employee.' ], 403 );
		}

		$this->log_management_action( 'employee_deleted', [
			'employee_id'   => $id,
			'employee_name' => $user->display_name ?: $user->user_login,
		] );

		require_once ABSPATH . 'wp-admin/includes/user.php';
		wp_delete_user( $id );

		return rest_ensure_response( [ 'success' => true, 'message' => 'Employee deleted.' ] );
	}

	/**
	 * GET /employees/{id}/activity — last 20 activity log entries.
	 */
	public function wpkin_get_employee_activity( \WP_REST_Request $request ): \WP_REST_Response {
		global $wpdb;

		$id       = (int) $request->get_param( 'id' );
		$per_page = max( 1, min( 100, (int) ( $request->get_param( 'per_page' ) ?? 20 ) ) );
		$page     = max( 1, (int) ( $request->get_param( 'page' ) ?? 1 ) );
		$offset   = ( $page - 1 ) * $per_page;
		$table    = $wpdb->prefix . 'oxi_sm_activity_log';

		$total = (int) $wpdb->get_var(
			$wpdb->prepare( "SELECT COUNT(*) FROM {$table} WHERE user_id = %d", $id )
		);

		$rows = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT id, action, details, created_at FROM {$table} WHERE user_id = %d ORDER BY created_at DESC LIMIT %d OFFSET %d",
				$id,
				$per_page,
				$offset
			),
			ARRAY_A
		);

		foreach ( $rows as &$row ) {
			$row['details'] = json_decode( $row['details'], true ) ?: [];
		}
		unset( $row );

		return rest_ensure_response( [
			'success'     => true,
			'activity'    => $rows,
			'total'       => $total,
			'page'        => $page,
			'per_page'    => $per_page,
			'total_pages' => (int) ceil( $total / $per_page ),
		] );
	}

	public function wpkin_get_employee_performance_summary( \WP_REST_Request $request ): \WP_REST_Response {
		global $wpdb;

		$user_id = (int) $request->get_param( 'id' );
		$force   = $request->get_param( 'force' ) === 'true';
		$table   = $wpdb->prefix . 'oxi_sm_activity_log';

		// Load AI settings
		$saved    = get_option( 'wpkin_sm_admin_settings', [] );
		$ai       = $saved['ai_settings'] ?? [];
		$provider = sanitize_text_field( $ai['provider'] ?? 'claude' );
		$model    = sanitize_text_field( $ai['model']    ?? '' );
		$raw_key  = $this->wpkin_decrypt_api_key( $ai['api_key_encrypted'] ?? '' );
		$temp     = (float) ( $ai['temperature'] ?? 0.7 );

		if ( $raw_key === '' ) {
			return rest_ensure_response( [
				'success'        => true,
				'ai_configured'  => false,
				'summary'        => null,
				'stats'          => null,
				'generated_at'   => null,
			] );
		}

		$transient_key = 'sm_emp_perf_' . $user_id;

		if ( ! $force ) {
			$cached = get_transient( $transient_key );
			if ( $cached !== false ) {
				return rest_ensure_response( $cached );
			}
		}

		// Fetch last 7 days of activity
		$since = gmdate( 'Y-m-d H:i:s', strtotime( '-7 days' ) );

		$logs = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT action, details, created_at FROM {$table} WHERE user_id = %d AND created_at >= %s ORDER BY created_at DESC LIMIT 100",
				$user_id,
				$since
			),
			ARRAY_A
		);

		if ( empty( $logs ) ) {
			return rest_ensure_response( [
				'success'        => true,
				'ai_configured'  => true,
				'summary'        => null,
				'stats'          => null,
				'generated_at'   => null,
			] );
		}

		// Aggregate stats
		$today = gmdate( 'Y-m-d' );
		$stats = [
			'total_actions'     => count( $logs ),
			'orders_processed'  => 0,
			'orders_today'      => 0,
			'completed_orders'  => 0,
			'status_changes'    => 0,
			'refunds_triggered' => 0,
			'cancellations'     => 0,
			'products_edited'   => 0,
			'customers_served'  => 0,
		];

		$log_lines = [];

		foreach ( $logs as $log ) {
			$action  = $log['action'];
			$details = json_decode( $log['details'] ?? '{}', true ) ?: [];
			$time    = gmdate( 'D M j g:ia', strtotime( $log['created_at'] ) );

			switch ( $action ) {
				case 'order_status_changed':
					$stats['orders_processed']++;
					$stats['status_changes']++;
					if ( gmdate( 'Y-m-d', strtotime( $log['created_at'] ) ) === $today ) {
						$stats['orders_today']++;
					}
					$old = $details['old_status'] ?? '';
					$new = $details['new_status'] ?? '';
					if ( $new === 'completed' ) {
						$stats['completed_orders']++;
					}
					if ( $new === 'refunded' ) {
						$stats['refunds_triggered']++;
					}
					if ( $new === 'cancelled' ) {
						$stats['cancellations']++;
					}
					$log_lines[] = "[{$time}] Changed order #{$details['order_id']} status: {$old} → {$new}";
					break;
				case 'order_updated':
					$stats['orders_processed']++;
					if ( gmdate( 'Y-m-d', strtotime( $log['created_at'] ) ) === $today ) {
						$stats['orders_today']++;
					}
					$log_lines[] = "[{$time}] Updated order #{$details['order_id']}";
					break;
				case 'order_email_resent':
					$log_lines[] = "[{$time}] Resent {$details['email_type']} email for order #{$details['order_id']}";
					break;
				case 'order_invoice_generated':
					$log_lines[] = "[{$time}] Generated invoice for order #{$details['order_id']}";
					break;
				case 'order_trashed':
				case 'order_deleted':
					$log_lines[] = "[{$time}] Deleted order #{$details['order_id']}";
					break;
				case 'product_edited':
				case 'product_created':
					$stats['products_edited']++;
					$log_lines[] = "[{$time}] " . ( $action === 'product_created' ? 'Created' : 'Edited' ) . " product: {$details['product_name']}";
					break;
				case 'customer_updated':
				case 'customer_note_added':
				case 'customer_tags_updated':
					$stats['customers_served']++;
					$log_lines[] = "[{$time}] Updated customer #{$details['customer_id']}";
					break;
				default:
					$log_lines[] = "[{$time}] " . str_replace( '_', ' ', $action );
					break;
			}
		}

		// Build AI prompt
		$user      = get_userdata( $user_id );
		$name      = $user ? $user->display_name : "Employee #{$user_id}";
		$log_text  = implode( "\n", array_slice( $log_lines, 0, 60 ) );

		$prompt = "You are generating a weekly performance summary for a WooCommerce store employee.\n\n"
			. "Employee: {$name}\n"
			. "Period: Last 7 days\n"
			. "Total actions: {$stats['total_actions']}\n"
			. "Orders processed or updated: {$stats['orders_processed']}\n"
			. "Orders processed today: {$stats['orders_today']}\n"
			. "Orders completed: {$stats['completed_orders']}\n"
			. "Order status changes: {$stats['status_changes']}\n"
			. "Refunds triggered: {$stats['refunds_triggered']}\n"
			. "Cancellations: {$stats['cancellations']}\n"
			. "Products edited or created: {$stats['products_edited']}\n"
			. "Customers served: {$stats['customers_served']}\n\n"
			. "Activity log:\n{$log_text}\n\n"
			. "Write a 2-3 sentence performance summary for {$name}. Be specific about what they did this week. "
			. "Mention any standout numbers. End with a short, genuine observation or encouragement. "
			. "Plain text only — no markdown, no bullet points, no headers.";

		$ai_text = $this->wpkin_call_ai_provider( $provider, $model, $raw_key, $prompt, 300, $temp );

		if ( is_wp_error( $ai_text ) ) {
			return new \WP_REST_Response( [
				'success' => false,
				'message' => $ai_text->get_error_message(),
			], 500 );
		}

		$result = [
			'success'        => true,
			'ai_configured'  => true,
			'summary'        => sanitize_textarea_field( trim( $ai_text ) ),
			'stats'          => $stats,
			'generated_at'   => current_time( 'c' ),
			'period_days'    => 7,
		];

		set_transient( $transient_key, $result, HOUR_IN_SECONDS );

		return rest_ensure_response( $result );
	}

	// ─── Employee Roles ───────────────────────────────────────────────────────

	private function wpkin_get_all_employee_role_data(): array {
		$settings = get_option( 'wpkin_sm_admin_settings', [] );
		$em       = $settings['employee_management'] ?? [];

		// Full capability skeleton — all keys default to false
		$base = [
			'oxi_sm_view_dashboard'   => false,
			'oxi_sm_view_orders'      => false, 'oxi_sm_create_orders'    => false, 'oxi_sm_edit_orders'       => false, 'oxi_sm_delete_orders'  => false, 'oxi_sm_export_orders'      => false,
			'oxi_sm_view_products'    => false, 'oxi_sm_create_products'  => false, 'oxi_sm_edit_products'     => false, 'oxi_sm_delete_products' => false, 'oxi_sm_manage_categories' => false,
			'oxi_sm_view_customers'   => false, 'oxi_sm_edit_customers'   => false, 'oxi_sm_delete_customers'  => false,
			'oxi_sm_view_employees'   => false, 'oxi_sm_create_employees' => false, 'oxi_sm_edit_employees'    => false, 'oxi_sm_delete_employees' => false,
			'oxi_sm_view_analytics'   => false, 'oxi_sm_export_analytics' => false,
		];

		// Factory defaults for each built-in role
		$default_caps = [
			'oxi_sm_fulfillment'     => array_merge( $base, [ 'oxi_sm_view_orders' => true, 'oxi_sm_edit_orders' => true ] ),
			'oxi_sm_product_manager' => array_merge( $base, [ 'oxi_sm_view_products' => true, 'oxi_sm_edit_products' => true ] ),
			'oxi_sm_accountant'      => array_merge( $base, [ 'oxi_sm_view_analytics' => true ] ),
			'oxi_sm_manager'         => array_merge( $base, [ 'oxi_sm_view_orders' => true, 'oxi_sm_edit_orders' => true, 'oxi_sm_view_products' => true, 'oxi_sm_edit_products' => true, 'oxi_sm_view_customers' => true, 'oxi_sm_view_analytics' => true ] ),
		];

		// Saved capability overrides for default roles (written by the edit endpoint)
		$saved_default_caps = $em['default_role_caps'] ?? [];

		$role_labels = \WPKIN_SHOP_MANAGER\Modules\EmployeeManager::get_role_labels();
		$hidden      = $em['hidden_default_roles'] ?? [];
		$custom      = $em['custom_roles'] ?? [];

		// Count users per role in one query
		$all_keys    = array_merge( array_keys( $default_caps ), array_column( $custom, 'key' ) );
		$role_counts = [];
		foreach ( $all_keys as $rk ) {
			$role_counts[ $rk ] = count( get_users( [ 'role' => $rk, 'fields' => 'ID', 'number' => -1 ] ) );
		}

		$roles = [];

		foreach ( $default_caps as $key => $caps ) {
			$effective = isset( $saved_default_caps[ $key ] )
				? array_merge( $caps, $saved_default_caps[ $key ] )
				: $caps;

			$roles[] = [
				'key'            => $key,
				'name'           => $role_labels[ $key ] ?? $key,
				'capabilities'   => $effective,
				'is_default'     => true,
				'hidden'         => in_array( $key, $hidden, true ),
				'employee_count' => $role_counts[ $key ] ?? 0,
			];
		}

		foreach ( $custom as $role ) {
			$roles[] = [
				'key'            => $role['key'],
				'name'           => $role['name'],
				'capabilities'   => $role['capabilities'],
				'is_default'     => false,
				'hidden'         => (bool) ( $role['hidden'] ?? false ),
				'employee_count' => $role_counts[ $role['key'] ] ?? 0,
			];
		}

		return $roles;
	}

	public function wpkin_get_employee_roles(): \WP_REST_Response {
		return rest_ensure_response( [
			'success' => true,
			'roles'   => $this->wpkin_get_all_employee_role_data(),
		] );
	}

	public function wpkin_create_employee_role( \WP_REST_Request $request ): \WP_REST_Response {
		$data = $request->get_json_params();
		$name = sanitize_text_field( $data['name'] ?? '' );

		if ( empty( $name ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'Role name is required.' ], 400 );
		}

		$settings     = get_option( 'wpkin_sm_admin_settings', [] );
		$custom_roles = $settings['employee_management']['custom_roles'] ?? [];

		// Duplicate name check (case-insensitive)
		$existing_names = array_map( fn( $r ) => strtolower( $r['name'] ), $custom_roles );
		if ( in_array( strtolower( $name ), $existing_names, true ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'A role with this name already exists.' ], 409 );
		}

		$raw_caps = $data['capabilities'] ?? [];
		$allowed  = [
				'oxi_sm_view_dashboard',
				'oxi_sm_orders_access',
				'oxi_sm_view_orders', 'oxi_sm_create_orders', 'oxi_sm_edit_orders', 'oxi_sm_delete_orders', 'oxi_sm_export_orders',
				'oxi_sm_orders_status_change', 'oxi_sm_orders_trash', 'oxi_sm_orders_restore', 'oxi_sm_orders_invoice', 'oxi_sm_orders_resend_email',
				'oxi_sm_products_access',
				'oxi_sm_view_products', 'oxi_sm_create_products', 'oxi_sm_edit_products', 'oxi_sm_duplicate_products', 'oxi_sm_delete_products', 'oxi_sm_export_products',
				'oxi_sm_manage_categories',
				'oxi_sm_categories_access', 'oxi_sm_categories_view', 'oxi_sm_categories_add', 'oxi_sm_categories_edit', 'oxi_sm_categories_delete',
				'oxi_sm_tags_access', 'oxi_sm_tags_view', 'oxi_sm_tags_add', 'oxi_sm_tags_edit', 'oxi_sm_tags_delete',
				'oxi_sm_brands_access', 'oxi_sm_brands_view', 'oxi_sm_brands_add', 'oxi_sm_brands_edit', 'oxi_sm_brands_delete',
				'oxi_sm_attributes_access', 'oxi_sm_attributes_view', 'oxi_sm_attributes_add', 'oxi_sm_attributes_edit', 'oxi_sm_attributes_delete',
				'oxi_sm_reviews_access', 'oxi_sm_reviews_view', 'oxi_sm_reviews_edit', 'oxi_sm_reviews_delete',
				'oxi_sm_customers_access', 'oxi_sm_view_customers', 'oxi_sm_edit_customers', 'oxi_sm_delete_customers',
				'oxi_sm_employees_access', 'oxi_sm_view_employees', 'oxi_sm_create_employees', 'oxi_sm_edit_employees', 'oxi_sm_delete_employees',
				'oxi_sm_roles_access', 'oxi_sm_roles_create', 'oxi_sm_roles_edit', 'oxi_sm_roles_toggle',
				'oxi_sm_view_analytics', 'oxi_sm_export_analytics',
				'oxi_sm_ai_chatbot_access',
			];
		$caps     = [];
		foreach ( $allowed as $cap ) {
			$caps[ $cap ] = ! empty( $raw_caps[ $cap ] );
		}

		$slug = 'oxi_sm_custom_' . sanitize_key( strtolower( str_replace( ' ', '_', $name ) ) ) . '_' . substr( uniqid(), -4 );

		add_role( $slug, $name, array_merge( [ 'read' => true ], $caps ) );

		$settings['employee_management']['custom_roles'][] = [
			'key'          => $slug,
			'name'         => $name,
			'capabilities' => $caps,
			'hidden'       => false,
		];
		update_option( 'wpkin_sm_admin_settings', $settings );

		$this->log_management_action( 'role_created', [
			'role_key'  => $slug,
			'role_name' => $name,
		] );

		return new \WP_REST_Response( [
			'success' => true,
			'message' => 'Custom role created.',
			'role'    => [
				'key'          => $slug,
				'name'         => $name,
				'capabilities' => $caps,
				'is_default'   => false,
				'hidden'       => false,
			],
		], 201 );
	}

	public function wpkin_delete_employee_role( \WP_REST_Request $request ): \WP_REST_Response {
		$key      = sanitize_key( $request->get_param( 'key' ) );
		$settings = get_option( 'wpkin_sm_admin_settings', [] );
		$em       = $settings['employee_management'] ?? [];

		// Only the 4 built-in roles can never be deleted
		$builtin = [ 'oxi_sm_fulfillment', 'oxi_sm_product_manager', 'oxi_sm_accountant', 'oxi_sm_manager' ];
		if ( in_array( $key, $builtin, true ) ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'Built-in roles cannot be deleted.' ], 403 );
		}

		// Capture role name before removal
		$role_name = '';
		foreach ( $em['custom_roles'] ?? [] as $r ) {
			if ( $r['key'] === $key ) { $role_name = $r['name']; break; }
		}

		// Strip this role from every user who has it assigned
		$affected_users = get_users( [ 'role' => $key, 'fields' => 'all' ] );
		foreach ( $affected_users as $user ) {
			$user->remove_role( $key );
		}

		// Remove the WP role definition and clean up settings
		remove_role( $key );
		$settings['employee_management']['custom_roles'] = array_values(
			array_filter( $em['custom_roles'] ?? [], fn( $r ) => $r['key'] !== $key )
		);
		update_option( 'wpkin_sm_admin_settings', $settings );

		$this->log_management_action( 'role_deleted', [
			'role_key'        => $key,
			'role_name'       => $role_name,
			'affected_users'  => count( $affected_users ),
		] );

		return rest_ensure_response( [
			'success'  => true,
			'message'  => 'Custom role deleted.',
			'affected' => count( $affected_users ),
		] );
	}

	public function wpkin_update_employee_role( \WP_REST_Request $request ): \WP_REST_Response {
		$key      = sanitize_key( $request->get_param( 'key' ) );
		$data     = $request->get_json_params();
		$raw_caps = $data['capabilities'] ?? [];

		$role_obj = get_role( $key );
		if ( ! $role_obj ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'Role not found.' ], 404 );
		}

		$allowed = [
			'oxi_sm_view_dashboard',
			'oxi_sm_orders_access',
			'oxi_sm_view_orders', 'oxi_sm_create_orders', 'oxi_sm_edit_orders', 'oxi_sm_delete_orders', 'oxi_sm_export_orders',
			'oxi_sm_orders_status_change', 'oxi_sm_orders_trash', 'oxi_sm_orders_restore', 'oxi_sm_orders_invoice', 'oxi_sm_orders_resend_email',
			'oxi_sm_products_access',
			'oxi_sm_view_products', 'oxi_sm_create_products', 'oxi_sm_edit_products', 'oxi_sm_duplicate_products', 'oxi_sm_delete_products', 'oxi_sm_export_products',
			'oxi_sm_manage_categories',
			'oxi_sm_categories_access', 'oxi_sm_categories_view', 'oxi_sm_categories_add', 'oxi_sm_categories_edit', 'oxi_sm_categories_delete',
			'oxi_sm_tags_access', 'oxi_sm_tags_view', 'oxi_sm_tags_add', 'oxi_sm_tags_edit', 'oxi_sm_tags_delete',
			'oxi_sm_brands_access', 'oxi_sm_brands_view', 'oxi_sm_brands_add', 'oxi_sm_brands_edit', 'oxi_sm_brands_delete',
			'oxi_sm_attributes_access', 'oxi_sm_attributes_view', 'oxi_sm_attributes_add', 'oxi_sm_attributes_edit', 'oxi_sm_attributes_delete',
			'oxi_sm_reviews_access', 'oxi_sm_reviews_view', 'oxi_sm_reviews_edit', 'oxi_sm_reviews_delete',
			'oxi_sm_customers_access', 'oxi_sm_view_customers', 'oxi_sm_edit_customers', 'oxi_sm_delete_customers',
			'oxi_sm_employees_access', 'oxi_sm_view_employees', 'oxi_sm_create_employees', 'oxi_sm_edit_employees', 'oxi_sm_delete_employees',
			'oxi_sm_roles_access', 'oxi_sm_roles_create', 'oxi_sm_roles_edit', 'oxi_sm_roles_toggle',
			'oxi_sm_view_analytics', 'oxi_sm_export_analytics',
			'oxi_sm_ai_chatbot_access',
		];

		$caps = [];
		foreach ( $allowed as $cap ) {
			$granted    = ! empty( $raw_caps[ $cap ] );
			$caps[$cap] = $granted;
			if ( $granted ) {
				$role_obj->add_cap( $cap, true );
			} else {
				$role_obj->remove_cap( $cap );
			}
		}

		// Persist capabilities to settings (both default and custom roles)
		$settings = get_option( 'wpkin_sm_admin_settings', [] );
		$builtin  = [ 'oxi_sm_fulfillment', 'oxi_sm_product_manager', 'oxi_sm_accountant', 'oxi_sm_manager' ];

		if ( in_array( $key, $builtin, true ) ) {
			$settings['employee_management']['default_role_caps'][ $key ] = $caps;
		} else {
			$custom = $settings['employee_management']['custom_roles'] ?? [];
			foreach ( $custom as &$r ) {
				if ( $r['key'] === $key ) {
					$r['capabilities'] = $caps;
					break;
				}
			}
			unset( $r );
			$settings['employee_management']['custom_roles'] = $custom;
		}

		update_option( 'wpkin_sm_admin_settings', $settings );

		$this->log_management_action( 'role_capabilities_updated', [
			'role_key' => $key,
		] );

		return rest_ensure_response( [ 'success' => true, 'capabilities' => $caps ] );
	}

	public function wpkin_toggle_employee_role_visibility( \WP_REST_Request $request ): \WP_REST_Response {
		$key      = sanitize_key( $request->get_param( 'key' ) );
		$settings = get_option( 'wpkin_sm_admin_settings', [] );
		$em       = $settings['employee_management'] ?? [];

		$builtin = [ 'oxi_sm_fulfillment', 'oxi_sm_product_manager', 'oxi_sm_accountant', 'oxi_sm_manager' ];

		if ( in_array( $key, $builtin, true ) ) {
			$hidden    = $em['hidden_default_roles'] ?? [];
			$now_hidden = in_array( $key, $hidden, true );
			if ( $now_hidden ) {
				$hidden = array_values( array_diff( $hidden, [ $key ] ) );
			} else {
				$hidden[] = $key;
			}
			$settings['employee_management']['hidden_default_roles'] = $hidden;
			update_option( 'wpkin_sm_admin_settings', $settings );
			$this->log_management_action( 'role_visibility_toggled', [
				'role_key' => $key,
				'hidden'   => ! $now_hidden,
			] );
			return rest_ensure_response( [ 'success' => true ] );
		}

		// Custom role — toggle hidden flag
		$custom     = $em['custom_roles'] ?? [];
		$found      = false;
		$now_hidden = false;
		foreach ( $custom as &$role ) {
			if ( $role['key'] === $key ) {
				$now_hidden     = ! ( $role['hidden'] ?? false );
				$role['hidden'] = $now_hidden;
				$found          = true;
				break;
			}
		}
		unset( $role );

		if ( ! $found ) {
			return new \WP_REST_Response( [ 'success' => false, 'message' => 'Role not found.' ], 404 );
		}

		$settings['employee_management']['custom_roles'] = $custom;
		update_option( 'wpkin_sm_admin_settings', $settings );
		$this->log_management_action( 'role_visibility_toggled', [
			'role_key' => $key,
			'hidden'   => $now_hidden,
		] );
		return rest_ensure_response( [ 'success' => true ] );
	}

	// ─── Employee Access ──────────────────────────────────────────────────────

	public function wpkin_get_employee_access(): \WP_REST_Response {
		$settings = get_option( 'wpkin_sm_admin_settings', [] );
		$config   = $settings['employee_management']['access_config'] ?? $this->wpkin_default_access_config();

		return rest_ensure_response( [
			'success' => true,
			'config'  => $config,
			'roles'   => $this->wpkin_get_all_employee_role_data(),
		] );
	}

	public function wpkin_save_employee_access( \WP_REST_Request $request ): \WP_REST_Response {
		$data    = $request->get_json_params();
		$config  = $data['config'] ?? [];

		$sections  = [ 'dashboard', 'orders', 'products', 'customers', 'employees' ];
		$sanitized = [];

		foreach ( $sections as $section ) {
			if ( isset( $config[ $section ] ) && is_array( $config[ $section ] ) ) {
				$sanitized[ $section ] = array_map( 'boolval', $config[ $section ] );
			}
		}

		$settings = get_option( 'wpkin_sm_admin_settings', [] );
		$settings['employee_management']['access_config'] = $sanitized;
		update_option( 'wpkin_sm_admin_settings', $settings );

		$this->log_management_action( 'employee_access_saved' );

		return rest_ensure_response( [ 'success' => true, 'message' => 'Access config saved.', 'config' => $sanitized ] );
	}

	private function wpkin_default_access_config(): array {
		return [
			'dashboard' => [ 'oxi_sm_fulfillment' => true,  'oxi_sm_product_manager' => true,  'oxi_sm_accountant' => true,  'oxi_sm_manager' => true  ],
			'orders'    => [ 'oxi_sm_fulfillment' => true,  'oxi_sm_product_manager' => false, 'oxi_sm_accountant' => false, 'oxi_sm_manager' => true  ],
			'products'  => [ 'oxi_sm_fulfillment' => false, 'oxi_sm_product_manager' => true,  'oxi_sm_accountant' => false, 'oxi_sm_manager' => true  ],
			'customers' => [ 'oxi_sm_fulfillment' => false, 'oxi_sm_product_manager' => false, 'oxi_sm_accountant' => false, 'oxi_sm_manager' => true  ],
			'employees' => [ 'oxi_sm_fulfillment' => false, 'oxi_sm_product_manager' => false, 'oxi_sm_accountant' => false, 'oxi_sm_manager' => false ],
		];
	}

	// ─── Permission Helpers ───────────────────────────────────────────────────

	/**
	 * Verify WP REST nonce and confirm the current user is authorized for the
	 * matched route. Shared by both free Routers and pro ProRouters.
	 *
	 * Full back-office roles (administrator / editor / shop_manager) are granted
	 * blanket access. Shop Manager employee roles must additionally hold the
	 * fine-grained capability mapped to the requested endpoint — see
	 * wpkin_route_capability_map(). This closes the broken function-level
	 * authorization where any employee role could reach every REST route
	 * regardless of its assigned module permissions.
	 */
	public function wpkin_admin_check_permissions( \WP_REST_Request $request ): bool|\WP_Error {
		$nonce = $request->get_header( 'X-WP-Nonce' ) ?: $request->get_param( '_wpnonce' );
		if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
			return new \WP_Error( 'rest_forbidden', esc_html__( 'You are not allowed to access this resource.', 'shop-manager' ), [ 'status' => 403 ] );
		}

		$forbidden = new \WP_Error( 'rest_forbidden', esc_html__( 'You are not allowed to access this resource.', 'shop-manager' ), [ 'status' => 403 ] );

		// Full back-office roles get blanket access.
		if ( $this->wpkin_admin_user_has_role( [ 'administrator', 'editor', 'shop_manager' ] ) ) {
			return true;
		}

		// From here on, only built-in Shop Manager employee roles may proceed.
		if ( ! $this->wpkin_admin_user_has_role( \WPKIN_SHOP_MANAGER\Modules\EmployeeManager::get_oxi_roles() ) ) {
			return $forbidden;
		}

		// Resolve the required capability for the matched route handler.
		$required_cap = $this->wpkin_required_capability_for_request( $request );

		// Admin-only endpoint reached by an employee → deny.
		if ( '__admin_only__' === $required_cap ) {
			return $forbidden;
		}

		// Unmapped endpoint (e.g. reference/bootstrap data or a pro route) →
		// keep the employee-role allowlist behavior for backward compatibility.
		if ( null === $required_cap ) {
			return true;
		}

		// Enforce the fine-grained capability server-side. A route may list
		// several acceptable capabilities (any-of) so that both the default
		// roles (coarse oxi_sm_view_* caps) and custom roles (granular
		// oxi_sm_*_access caps) are honored, matching the frontend gating.
		foreach ( (array) $required_cap as $cap ) {
			if ( current_user_can( $cap ) ) {
				return true;
			}
		}

		return $forbidden;
	}

	/**
	 * Determine the capability required for the route matched by this request,
	 * based on the resolved callback method name.
	 *
	 * @return string|array|null Capability slug (or any-of list),
	 *                           '__admin_only__', or null if unmapped.
	 */
	private function wpkin_required_capability_for_request( \WP_REST_Request $request ): string|array|null {
		$attributes = $request->get_attributes();
		$callback   = $attributes['callback'] ?? null;

		// Callbacks are registered as [ $this, 'method_name' ].
		$method = ( is_array( $callback ) && isset( $callback[1] ) ) ? $callback[1] : null;
		if ( ! $method ) {
			return null;
		}

		$map = $this->wpkin_route_capability_map();

		/**
		 * Allow the pro add-on (or site owners) to register capability
		 * requirements for additional routes.
		 *
		 * @param array $map Callback method name => capability slug.
		 */
		$map = apply_filters( 'wpkin_sm_route_capability_map', $map );

		return $map[ $method ] ?? null;
	}

	/**
	 * Map REST callback method names to the capability (or any-of list of
	 * capabilities) an employee must hold to reach the route.
	 *
	 * Each value may be a single capability string or an array of capabilities
	 * (the request passes if the user holds ANY of them). The any-of form keeps
	 * both the default roles — which carry the coarse `oxi_sm_view_*` caps — and
	 * custom roles — which carry the granular `oxi_sm_*_access` caps used by the
	 * frontend — working, mirroring the client-side gating in capabilities.js.
	 *
	 * Endpoints intentionally omitted here (order statuses, countries/states,
	 * dashboard bootstrap, admin settings read) are treated as shared
	 * UI-bootstrap data available to any employee role.
	 */
	private function wpkin_route_capability_map(): array {
		// Reusable any-of capability sets, aligned with src/public/config/capabilities.js.
		$orders_view    = [ 'oxi_sm_orders_access', 'oxi_sm_view_orders' ];
		$products_view  = [ 'oxi_sm_products_access', 'oxi_sm_view_products' ];
		$customers_view = [ 'oxi_sm_customers_access', 'oxi_sm_view_customers' ];
		$employees_view = [ 'oxi_sm_employees_access', 'oxi_sm_view_employees' ];
		$analytics_view = [ 'oxi_sm_view_analytics', 'oxi_sm_view_dashboard' ];

		// The taxonomy/attribute endpoints are shared across the Categories,
		// Tags, Brands and Attributes pages (differentiated at runtime by a
		// taxonomy param), so accept any product sub-module access cap.
		$taxonomy_read  = [
			'oxi_sm_categories_access', 'oxi_sm_tags_access', 'oxi_sm_brands_access',
			'oxi_sm_attributes_access', 'oxi_sm_products_access', 'oxi_sm_view_products',
		];
		$taxonomy_write = [
			'oxi_sm_categories_add', 'oxi_sm_categories_edit', 'oxi_sm_categories_delete',
			'oxi_sm_tags_add', 'oxi_sm_tags_edit', 'oxi_sm_tags_delete',
			'oxi_sm_brands_add', 'oxi_sm_brands_edit', 'oxi_sm_brands_delete',
			'oxi_sm_attributes_add', 'oxi_sm_attributes_edit', 'oxi_sm_attributes_delete',
			'oxi_sm_edit_products',
		];

		return [
			// ── Orders ──────────────────────────────────────────────
			'wpkin_get_order_list'                   => $orders_view,
			'wpkin_get_order_counts'                 => $orders_view,
			'wpkin_get_order'                        => $orders_view,
			'wpkin_get_customer_orders'              => $orders_view,
			'wpkin_get_order_filter_references'      => $orders_view,
			'wpkin_sm_handle_search'                 => $orders_view, // global search only queries orders
			'wpkin_update_order'                     => [ 'oxi_sm_edit_orders' ],
			'wpkin_update_order_status'              => [ 'oxi_sm_edit_orders', 'oxi_sm_orders_status_change' ],
			'wpkin_bulk_update_order_status'         => [ 'oxi_sm_edit_orders', 'oxi_sm_orders_status_change' ],
			'wpkin_trash_order'                      => [ 'oxi_sm_edit_orders', 'oxi_sm_orders_trash' ],
			'wpkin_bulk_trash_orders'                => [ 'oxi_sm_edit_orders', 'oxi_sm_orders_trash' ],
			'wpkin_restore_order'                    => [ 'oxi_sm_edit_orders', 'oxi_sm_orders_restore' ],
			'wpkin_bulk_restore_orders'              => [ 'oxi_sm_edit_orders', 'oxi_sm_orders_restore' ],
			'wpkin_resend_order_email'               => [ 'oxi_sm_edit_orders', 'oxi_sm_orders_resend_email' ],
			'wpkin_bulk_resend_email'                => [ 'oxi_sm_edit_orders', 'oxi_sm_orders_resend_email' ],
			'wpkin_create_wc_order'                  => [ 'oxi_sm_create_orders' ],
			'wpkin_permanently_delete_order'         => [ 'oxi_sm_delete_orders' ],
			'wpkin_bulk_delete_orders'               => [ 'oxi_sm_delete_orders' ],
			'wpkin_sm_delete_order'                  => [ 'oxi_sm_delete_orders' ],
			'wpkin_export_orders'                    => [ 'oxi_sm_export_orders', 'oxi_sm_orders_access', 'oxi_sm_view_orders' ],

			// ── Products ────────────────────────────────────────────
			'wpkin_get_products'                     => $products_view,
			'wpkin_sm_get_products'                  => $products_view,
			'wpkin_get_custom_fields'                => $products_view,
			'wpkin_sm_get_attribute_terms'           => $taxonomy_read,
			'wpkin_sm_get_taxonomies'                => $taxonomy_read,
			'wpkin_sm_add_product'                   => [ 'oxi_sm_create_products' ],
			'wpkin_sm_duplicate_product'             => [ 'oxi_sm_duplicate_products', 'oxi_sm_create_products' ],
			'wpkin_sm_update_product'                => [ 'oxi_sm_edit_products' ],
			'wpkin_save_custom_field'                => [ 'oxi_sm_edit_products', 'oxi_sm_products_access' ],
			'wpkin_sm_delete_products'               => [ 'oxi_sm_delete_products' ],
			'wpkin_sm_add_taxonomy'                  => $taxonomy_write,
			'wpkin_sm_delete_taxonomies'             => $taxonomy_write,
			'wpkin_sm_set_default_category'          => $taxonomy_write,
			'wpkin_sm_update_taxonomy_order'         => $taxonomy_write,

			// ── Reviews (products module) ───────────────────────────
			'wpkin_sm_get_reviews'                   => [ 'oxi_sm_reviews_access', 'oxi_sm_products_access', 'oxi_sm_view_products' ],
			'wpkin_sm_get_review_counts'             => [ 'oxi_sm_reviews_access', 'oxi_sm_products_access', 'oxi_sm_view_products' ],
			'wpkin_sm_update_review_status'          => [ 'oxi_sm_reviews_edit', 'oxi_sm_edit_products' ],
			'wpkin_sm_reply_to_review'               => [ 'oxi_sm_reviews_edit', 'oxi_sm_edit_products' ],

			// ── Customers ───────────────────────────────────────────
			'wpkin_get_customers'                    => $customers_view,
			'wpkin_get_customer_profile'             => $customers_view,
			'wpkin_get_customer_order_history'       => $customers_view,
			'wpkin_get_customer_notes'               => $customers_view,
			'wpkin_update_customer'                  => [ 'oxi_sm_edit_customers' ],
			'wpkin_add_customer_note'                => [ 'oxi_sm_edit_customers' ],
			'wpkin_update_customer_tags'             => [ 'oxi_sm_edit_customers' ],
			'wpkin_refresh_customer_tags'            => [ 'oxi_sm_edit_customers' ],
			'wpkin_refresh_all_customer_tags'        => [ 'oxi_sm_edit_customers' ],

			// ── Analytics / Insights ────────────────────────────────
			'wpkin_sm_get_insights'                  => $analytics_view,
			'wpkin_sm_dismiss_insight'               => $analytics_view,
			'wpkin_sm_reset_dismissed_insights'      => $analytics_view,

			// ── Employees ───────────────────────────────────────────
			'wpkin_get_employees'                    => $employees_view,
			'wpkin_get_employee'                     => $employees_view,
			'wpkin_get_employee_activity'            => $employees_view,
			'wpkin_get_employee_performance_summary' => $employees_view,
			'wpkin_create_employee'                  => [ 'oxi_sm_create_employees' ],
			'wpkin_update_employee'                  => [ 'oxi_sm_edit_employees' ],
			'wpkin_reset_employee_password'          => [ 'oxi_sm_edit_employees' ],
			'wpkin_delete_employee'                  => [ 'oxi_sm_delete_employees' ],

			// ── Roles & Access matrix ───────────────────────────────
			'wpkin_get_employee_roles'               => [ 'oxi_sm_roles_access', 'oxi_sm_employees_access', 'oxi_sm_view_employees' ],
			'wpkin_get_employee_access'              => [ 'oxi_sm_roles_access', 'oxi_sm_employees_access' ],
			'wpkin_save_employee_access'             => [ 'oxi_sm_roles_edit', 'oxi_sm_roles_access' ],
			'wpkin_create_employee_role'             => [ 'oxi_sm_roles_create', 'oxi_sm_roles_edit' ],
			'wpkin_update_employee_role'             => [ 'oxi_sm_roles_edit' ],
			'wpkin_toggle_employee_role_visibility'  => [ 'oxi_sm_roles_toggle', 'oxi_sm_roles_edit' ],
			'wpkin_delete_employee_role'             => [ 'oxi_sm_roles_edit', 'oxi_sm_delete_employees' ],

			// ── Admin-only ──────────────────────────────────────────
			'wpkin_save_admin_settings'              => '__admin_only__',
		];
	}

	/**
	 * Check whether the current user holds at least one of the supplied roles.
	 */
	public function wpkin_admin_user_has_role( array $roles ): bool {
		$user = wp_get_current_user();
		if ( empty( $user ) ) {
			return false;
		}

		foreach ( $roles as $role ) {
			if ( in_array( $role, (array) $user->roles, true ) ) {
				return true;
			}
		}
		return false;
	}
}
