<?php
// phpcs:ignoreFile

/**
 * Settings view for admin interface.
 *
 * @package Awesomemotive\Rewardswp\Views\Admin
 * @since 1.0.0
 */

namespace Awesomemotive\Rewardswp\Views\Admin;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Awesomemotive\Rewardswp\Controllers\Admin\SettingsAdminController;
use Awesomemotive\Rewardswp\Services\MemberRewardsService;
use Awesomemotive\Rewardswp\Settings\Options\Points\PointsEnabledOption;
use Awesomemotive\Rewardswp\Settings\Options\Points\PointsExpirationOption;
use Awesomemotive\Rewardswp\Settings\Options\Points\EarnActionsOption;
use Awesomemotive\Rewardswp\Settings\Options\Points\SpendActionsOption;
use Awesomemotive\Rewardswp\Settings\Options\Referrals\EnabledOption;
use Awesomemotive\Rewardswp\Settings\Options\Emails\EmailLogoOption;
use Awesomemotive\Rewardswp\Settings\Options\General\BrandColorOption;
use Awesomemotive\Rewardswp\Settings\Options\RewardsWidget\LauncherDisplayOption;
use Awesomemotive\Rewardswp\Settings\Options\RewardsWidget\LauncherTextOption;
use Awesomemotive\Rewardswp\Settings\Options\RewardsWidget\ProgramNameOption;
use Awesomemotive\Rewardswp\Settings\Options\RewardsWidget\WelcomeHeadingOption;
use Awesomemotive\Rewardswp\Views\Admin\Modals\UpgradeModalView;
use Awesomemotive\Rewardswp\Views\Admin\Components\DrawerComponentView;
use Awesomemotive\Rewardswp\Views\Admin\Parts\EarnPointsActionsDrawerView;
use Awesomemotive\Rewardswp\Views\Admin\Parts\SpendPointsActionsDrawerView;
use Awesomemotive\Rewardswp\Views\Admin\Parts\ReferralsRewardsDrawerView;
use Awesomemotive\Rewardswp\Views\Admin\Parts\PointsBrandingContentView;
use Awesomemotive\Rewardswp\Views\Admin\Parts\PointsExpiryContentView;
use Awesomemotive\Rewardswp\Views\Admin\Parts\PointsStatusContentView;
use Awesomemotive\Rewardswp\Views\Admin\Sections\LicenseSectionView;
use DI\Container;
use Awesomemotive\Rewardswp\Controllers\Admin\MainAdminController;
use Awesomemotive\Rewardswp\Abstracts\AbstractView;
use Awesomemotive\Rewardswp\Factories\ViewsFactory;
use Awesomemotive\Rewardswp\Helpers\IconHelper;
use Awesomemotive\Rewardswp\Interfaces\ViewInterface;
use Awesomemotive\Rewardswp\Services\OptionsService;
use Awesomemotive\Rewardswp\Settings\Options\Integrations\IntegrationSourceOption;
use Awesomemotive\Rewardswp\Settings\Options\Referrals\RewardsOption;
use Awesomemotive\Rewardswp\Settings\Options\Referrals\SharingOption;

use Awesomemotive\Rewardswp\Views\Admin\Parts\EasyDigitalDownloadsIntegrationContentView;
use Awesomemotive\Rewardswp\Views\Admin\Parts\GeneralSettingsContentView;
use Awesomemotive\Rewardswp\Views\Admin\Parts\ReferralsProgramStatusContentView;
use Awesomemotive\Rewardswp\Views\Admin\Parts\ReferralsTrackingContentView;
use Awesomemotive\Rewardswp\Views\Admin\Parts\RewardsWidgetSharingOptionsContentView;
use Awesomemotive\Rewardswp\Views\Admin\Parts\RewardsWidgetLauncherContentView;
use Awesomemotive\Rewardswp\Views\Admin\Parts\RewardsWidgetGeneralContentView;
use Awesomemotive\Rewardswp\Views\Admin\Parts\WooCommerceIntegrationContentView;
use function Awesomemotive\Rewardswp\Helpers\array_to_json;
use function Awesomemotive\Rewardswp\Helpers\can_access_rewardswp_feature;
use function Awesomemotive\Rewardswp\Helpers\get_option_object;
use function Awesomemotive\Rewardswp\Helpers\get_option_value;
use function Awesomemotive\Rewardswp\Helpers\get_points_currency_singular;
use function Awesomemotive\Rewardswp\Helpers\get_points_currency_plural;
use function Awesomemotive\Rewardswp\Helpers\get_rewardswp_plan_tier;
use function Awesomemotive\Rewardswp\Helpers\get_rewardswp_plan_tier_names;
use function Awesomemotive\Rewardswp\Helpers\get_lite_redemption_limit;
use function Awesomemotive\Rewardswp\Helpers\get_minimum_required_plan_for_feature;
use function Awesomemotive\Rewardswp\Helpers\get_site_currency_symbol;
use function Awesomemotive\Rewardswp\Helpers\get_upgrade_upsell_data;
use function Awesomemotive\Rewardswp\Helpers\get_upgrade_url;
use function Awesomemotive\Rewardswp\Helpers\get_view_component;
use function Awesomemotive\Rewardswp\Helpers\is_license_valid;
use function Awesomemotive\Rewardswp\Helpers\is_rewardswp_pro_plan;
use function Awesomemotive\Rewardswp\Helpers\kses;
use function Awesomemotive\Rewardswp\Helpers\svg_kses;
use function Awesomemotive\Rewardswp\Helpers\get_available_rewardswp_features;

class SettingsView extends AbstractView implements ViewInterface {
	/**
	 * Icon helper instance.
	 *
	 * @since 1.0.0
	 *
	 * @var IconHelper
	 */
	private IconHelper $icon_helper;

	/**
	 * DI container instance.
	 *
	 * @since 1.0.0
	 *
	 * @var Container
	 */
	private Container $container;

	/**
	 * Views factory instance.
	 *
	 * @since 1.0.0
	 *
	 * @var ViewsFactory
	 */
	private ViewsFactory $views_factory;

	/**
	 * Member rewards service instance.
	 *
	 * @since 1.0.0
	 *
	 * @var MemberRewardsService
	 */
	private MemberRewardsService $member_reward_service;

	/**
	 * Constructor.
	 *
	 * @since 1.0.0
	 *
	 * @param IconHelper           $icon_helper
	 * @param ViewsFactory         $views_factory
	 * @param Container            $container
	 * @param MemberRewardsService $member_reward_service
	 */
	public function __construct(
		IconHelper $icon_helper,
		ViewsFactory $views_factory,
		Container $container,
		MemberRewardsService $member_reward_service
	) {
		$this->icon_helper           = $icon_helper;
		$this->views_factory         = $views_factory;
		$this->container             = $container;
		$this->member_reward_service = $member_reward_service;
	}

	/**
	 * Render the save button.
	 *
	 * @since 1.0.0
	 *
	 * @param array $args {
	 *     Optional. Array of button arguments.
	 *
	 *     @type string $button_classes   Additional classes for the button element.
	 * }
	 * @return void
	 */
	public function render_save_button( array $args = [] ): void {
		$default_button_classes = 'rewardswp-button items-center justify-center px-4 py-2 text-sm font-medium rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 cursor-pointer text-white bg-blue-600 border border-transparent hover:bg-blue-700 focus:ring-blue-500 shrink-0 min-w-[120px] grid grid-cols-1 grid-rows-1 [grid-template-areas:stack] text-center place-items-center cursor-pointer';

		$args = wp_parse_args(
			$args,
			[
				'button_classes' => '',
			]
		);

		// Merge the default button classes with any additional classes
		$button_classes = trim( $default_button_classes . ' ' . $args['button_classes'] );
		?>

		<button
			x-on:click.prevent="saveSettings"
			type="submit"
			x-bind:disabled="isSaving || !canSave()"
			x-bind:class="{
				'cursor-not-allowed opacity-50': isSaving || !isSaving && !canSave(),
				'cursor-pointer': !isSaving && canSave()
			}"
			class="<?php echo esc_attr( $button_classes ); ?>"
		>
			<span
				class="[grid-area:stack] transition-opacity duration-200"
				x-bind:class="{ 'invisible': isSaving, 'visible': !isSaving }"
			><?php esc_html_e( 'Save Changes', 'rewardswp' ); ?></span>
			<svg
				class="animate-spin h-5 w-5 [grid-area:stack] transition-opacity duration-200 invisible"
				x-bind:class="{ 'invisible': isSaving !== true, 'visible': isSaving === true }"
				xmlns="http://www.w3.org/2000/svg"
				fill="none"
				viewBox="0 0 24 24"
			>
				<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
				<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
			</svg>
			<svg
				class="h-5 w-5 [grid-area:stack] transition-opacity duration-200 invisible"
				x-bind:class="{ 'invisible': isSaving !== 'complete', 'visible': isSaving === 'complete' }"
				xmlns="http://www.w3.org/2000/svg"
				fill="none"
				viewBox="0 0 24 24"
				stroke="currentColor"
			>
				<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
			</svg>
		</button>

		<?php
	}

	/**
	 * Render the template.
	 *
	 * @since 1.0.0
	 *
	 * @param array $args {
	 *
	 * }
	 *
	 * @return void
	 */
	public function render( array $args = [] ): void {

		// Get active tab from URL query string or default to 'general'.
		$tab_raw      = filter_input( INPUT_GET, 'tab', FILTER_UNSAFE_RAW );
		$tab_param    = is_string( $tab_raw ) ? sanitize_text_field( wp_unslash( $tab_raw ) ) : '';
		$allowed_tabs = [ 'general', 'points', 'referrals', 'rewards_widget', 'integrations' ];
		$active_tab   = in_array( $tab_param, $allowed_tabs, true ) ? $tab_param : 'general';

		$earn_actions_option  = get_option_object( EarnActionsOption::class );
		$spend_actions_option = get_option_object( SpendActionsOption::class );

		// Get spend actions, limit to 4 for Lite users in admin.
		$spend_actions = $spend_actions_option->get_value();
		if ( get_rewardswp_plan_tier() === 'lite' && is_array( $spend_actions ) && count( $spend_actions ) > 4 ) {
			$spend_actions = array_values( array_slice( $spend_actions, 0, 4 ) );
		}

		// Get rewards options for advocate and friend rewards
		$rewards_options = get_option_value( RewardsOption::class );
		$advocate_reward = empty( $rewards_options['advocate'] )
			? wp_json_encode( null )
			: array_to_json(
				array_merge(
					$rewards_options['advocate'],
					[
						'products_cache' => $this->member_reward_service->get_reward_products_included( 'advocate' ),
					]
				)
			);
		$friend_reward   = empty( $rewards_options['friend'] )
			? wp_json_encode( null )
			: array_to_json(
				array_merge(
					$rewards_options['friend'],
					[
						'products_cache' => $this->member_reward_service->get_reward_products_included( 'friend' ),
					]
				)
			);

		$args = wp_parse_args(
			$args,
			[
				'page_title' => esc_html__( 'Settings', 'rewardswp' ),
			]
		);

		// Build logo preview URL for JavaScript
		$logo_data        = get_option_value( EmailLogoOption::class );
		$attachment_id    = $logo_data['attachment_id'] ?? 0;
		$size             = $logo_data['size'] ?? 'medium';
		$logo_preview_url = '';

		if ( $attachment_id ) {
			$image_data = wp_get_attachment_image_src( $attachment_id, $size );
			if ( $image_data ) {
				$url = $image_data[0];
				if ( is_ssl() && strpos( $url, 'http://' ) === 0 ) {
					$url = str_replace( 'http://', 'https://', $url );
				}
				$logo_preview_url = esc_js( $url );
			}
		}

		// Pre-compute upsell data for all modal features.
		$upsell_points_branding    = get_upgrade_upsell_data( 'points_branding', 'settings' );
		$upsell_points_expiry      = get_upgrade_upsell_data( 'points_expiry', 'settings' );
		$upsell_redeem_options     = get_upgrade_upsell_data( 'redeem_percentage_discount', 'settings' );
		$upsell_foreground_mode    = get_upgrade_upsell_data( 'brand_foreground_mode', 'settings' );

		?>

		<script type="text/javascript">
			window.rewardswpData = {
			earnActionsDefs: <?php echo wp_json_encode( $earn_actions_option->get_action_definitions(), JSON_UNESCAPED_SLASHES ); ?>,
			spendActionsDefs: <?php echo wp_json_encode( $spend_actions_option->get_action_definitions(), JSON_UNESCAPED_SLASHES ); ?>,
			earnPointsActions: <?php echo wp_json_encode( $earn_actions_option->get_value(), JSON_UNESCAPED_SLASHES ); ?>,
			spendPointsActions: <?php echo wp_json_encode( $spend_actions, JSON_UNESCAPED_SLASHES ); ?>,
				phpData: {
					enabled: Boolean( <?php echo esc_js( get_option_value( EnabledOption::class ) ); ?> ),
					pointsEnabled: Boolean( <?php echo esc_js( get_option_value( PointsEnabledOption::class ) ); ?> ),
					pointsCurrencySingular: '<?php echo esc_js( get_points_currency_singular() ); ?>',
					pointsCurrencyPlural: '<?php echo esc_js( get_points_currency_plural() ); ?>',
					welcomeGreeting: '<?php echo esc_js( get_option_value( WelcomeHeadingOption::class ) ); ?>',
					programName: '<?php echo esc_js( get_option_value( ProgramNameOption::class ) ); ?>',
					logoAttachmentId: <?php echo esc_js( get_option_value( EmailLogoOption::class )['attachment_id'] ?? 0 ); ?>,
					logoSize: '<?php echo esc_js( get_option_value( EmailLogoOption::class )['size'] ?? 'medium' ); ?>',
					logoPreviewUrl: '<?php echo esc_js( $logo_preview_url ); ?>'
		}
	};

	window.liteRedemptionLimit = <?php echo esc_js( get_lite_redemption_limit() ); ?>;

	// Config data for Alpine store (supplements wp_localize_script from MainAdminController).
	window.rewardswpConfig = {
		planTier: '<?php echo esc_js( get_rewardswp_plan_tier() ); ?>',
		currencySymbol: '<?php echo esc_js( get_site_currency_symbol() ); ?>',
		hasProFeatures: Boolean( <?php echo esc_js( can_access_rewardswp_feature( 'points_expiry' ) ); ?> ),
		hasRewardExpiration: Boolean( <?php echo esc_js( can_access_rewardswp_feature( 'reward_expiration' ) ); ?> ),
		hasReferralRewardExpiration: Boolean( <?php echo esc_js( can_access_rewardswp_feature( 'referral_reward_expiration' ) ); ?> ),
		accessibleFeatures: <?php echo wp_json_encode( get_available_rewardswp_features() ); ?>,
	};

	window.initRewardswpSettings = function() {
				const data = window.rewardswpData.phpData;
				return {
				activeTab: 'general',
				searchQuery: '',
				showSearch: false,
				enabled: data.enabled,
				pointsEnabled: data.pointsEnabled,
				pointsCurrencySingular: data.pointsCurrencySingular,
				pointsCurrencyPlural: data.pointsCurrencyPlural,
				welcomeGreeting: data.welcomeGreeting,
				programName: data.programName,
				earnActionsDefs: window.rewardswpData.earnActionsDefs || {},
				spendActionsDefs: window.rewardswpData.spendActionsDefs || {},
				logoAttachmentId: data.logoAttachmentId,
				logoSize: data.logoSize,
				logoPreviewUrl: data.logoPreviewUrl,
				earnPointsActions: window.rewardswpData.earnPointsActions || {},
				spendPointsActions: (function() {
					var savedActions = window.rewardswpData.spendPointsActions;

					if (Array.isArray(savedActions) && savedActions.length > 0) {
						return savedActions.map(action => ({
							...action,
							enabled: Boolean(Number(action.enabled)),
							products_included: action.products_included || [],
							products_cache: action.products_cache || []
						}));
					}

					if (!savedActions) {
						return [];
					}

					var defaults = {
						'fixed_discount': {
							type: 'fixed_discount',
							enabled: true,
							points_per_dollar: 100,
							title: '<?php echo esc_js( __( 'Fixed Amount Discount', 'rewardswp' ) ); ?>',
							description: '<?php echo esc_js( __( 'Redeem points for a fixed amount discount', 'rewardswp' ) ); ?>'
						},
						'percentage_discount': {
							type: 'percentage_discount',
							enabled: true,
							points_per_percent: 100,
							title: '<?php echo esc_js( __( 'Percentage Discount', 'rewardswp' ) ); ?>',
							description: '<?php echo esc_js( __( 'Redeem points for a percentage discount', 'rewardswp' ) ); ?>'
						},
						'free_shipping': {
							type: 'free_shipping',
							enabled: true,
							points: 500,
							title: '<?php echo esc_js( __( 'Free Shipping', 'rewardswp' ) ); ?>',
							description: '<?php echo esc_js( __( 'Redeem points for free shipping', 'rewardswp' ) ); ?>'
						},
						'free_product': {
							type: 'free_product',
							enabled: true,
							points_required: 2000,
							title: '<?php echo esc_js( __( 'Free Product', 'rewardswp' ) ); ?>',
							description: '<?php echo esc_js( __( 'Redeem points for a free product', 'rewardswp' ) ); ?>'
						}
					};

					return window.rewardsWPSpendActions.convertSavedActionsToArray(savedActions, defaults);
				})(),
				rewards: {
					advocate: <?php echo wp_json_encode( $advocate_reward ); ?>,
					friend: <?php echo wp_json_encode( $friend_reward ); ?>
				},
				currencySymbol: '<?php echo esc_js( get_site_currency_symbol() ); ?>',
				getDisplayRewardTitle(reward, context) {
					if (!reward || !reward.type) return '';

					let title = '';
					switch (reward.type) {
						case 'fixed_discount':
							title = reward.reward_amount !== undefined ?
								`${<?php echo \Awesomemotive\Rewardswp\Helpers\js_money_expr( 'reward.reward_amount', 'this.currencySymbol' ); ?>} <?php echo esc_js( __( 'off entire order', 'rewardswp' ) ); ?>` :
								'<?php echo esc_js( __( 'Amount off entire order', 'rewardswp' ) ); ?>';
							break;
						case 'percentage_discount':
							title = reward.reward_amount !== undefined ?
								`${reward.reward_amount}% <?php echo esc_js( __( 'off entire order', 'rewardswp' ) ); ?>` :
								'<?php echo esc_js( __( 'Percentage off entire order', 'rewardswp' ) ); ?>';
							break;
						case 'free_shipping':
							title = '<?php echo esc_js( __( 'Free shipping', 'rewardswp' ) ); ?>';
							break;
						case 'free_product':
							title = '<?php echo esc_js( __( 'Free product', 'rewardswp' ) ); ?>';
							break;
						default:
							title = `${context.charAt(0).toUpperCase() + context.slice(1)} ${rewardswpMainVars.rewardTypes[reward.type]?.title || ''}`;
					}

					return title;
				},
				getRewardProductName(productId) {
					const context = this.drawer?.actionId || 'advocate';
					if (!this.rewards || !this.rewards[context] || !this.rewards[context].products_cache) {
						return null;
					}
					// Use == for loose comparison to handle string/number type mismatches
					const product = this.rewards[context].products_cache.find(product => product.id == productId);
					return product ? product.name : null;
			},
			isEditingSpendAction: false,
			currentSpendAction: null,

			// Upgrade modal
				upgradeModal: false,
				upgradeModalContent: {
					points_branding: {
						title: '<?php esc_html_e( 'Points Branding', 'rewardswp' ); ?>',
						message: '<?php esc_html_e( 'Customize the points currency name members see (e.g., Coin / Coins).', 'rewardswp' ); ?>',
						features: [
							'<?php esc_html_e( 'Custom singular name (e.g., Coin)', 'rewardswp' ); ?>',
							'<?php esc_html_e( 'Custom plural name (e.g., Coins)', 'rewardswp' ); ?>',
							'<?php esc_html_e( 'Keep your rewards language on-brand', 'rewardswp' ); ?>',
						],
						required_plan: <?php echo wp_json_encode( $upsell_points_branding['required_plan'] ); ?>,
						button_text: '<?php echo esc_js( $upsell_points_branding['button_text'] ); ?>',
						button_url: <?php echo wp_json_encode( $upsell_points_branding['button_url'] ); ?>,
						compare_url: <?php echo wp_json_encode( $upsell_points_branding['compare_url'] ); ?>,
					},
					points_expiry: {
						title: '<?php esc_html_e( 'Points expiry', 'rewardswp' ); ?>',
						message: '<?php esc_html_e( 'Automatically expire points after a set period to encourage redemptions.', 'rewardswp' ); ?>',
						features: [
							'<?php esc_html_e( 'Set expiry periods (30 days, 3 months, etc.)', 'rewardswp' ); ?>',
							'<?php esc_html_e( 'Encourage redemptions with expiry dates', 'rewardswp' ); ?>',
							'<?php esc_html_e( 'Automatically handle expired balances', 'rewardswp' ); ?>',
						],
						required_plan: <?php echo wp_json_encode( $upsell_points_expiry['required_plan'] ); ?>,
						button_text: '<?php echo esc_js( $upsell_points_expiry['button_text'] ); ?>',
						button_url: <?php echo wp_json_encode( $upsell_points_expiry['button_url'] ); ?>,
						compare_url: <?php echo wp_json_encode( $upsell_points_expiry['compare_url'] ); ?>,
					},
					redeem_options_limit: {
						title: '<?php esc_html_e( 'Unlimited Ways to Redeem', 'rewardswp' ); ?>',
						message: <?php echo wp_json_encode( sprintf( /* translators: %d: maximum redemption options */ __( 'You\'ve reached the limit of %d redemption options. Upgrade to add unlimited options.', 'rewardswp' ), get_lite_redemption_limit() ) ); ?>,
						features: [
							'<?php esc_html_e( 'Add unlimited redemption options', 'rewardswp' ); ?>',
							'<?php esc_html_e( 'Offer more reward types and variations', 'rewardswp' ); ?>',
							'<?php esc_html_e( 'Give members more flexibility at checkout', 'rewardswp' ); ?>',
						],
						required_plan: <?php echo wp_json_encode( $upsell_redeem_options['required_plan'] ); ?>,
						button_text: '<?php echo esc_js( $upsell_redeem_options['button_text'] ); ?>',
						button_url: <?php echo wp_json_encode( $upsell_redeem_options['button_url'] ); ?>,
						compare_url: <?php echo wp_json_encode( $upsell_redeem_options['compare_url'] ); ?>,
					},
					brand_foreground_mode: {
						title: '<?php esc_html_e( 'Customize text and icons on your brand color', 'rewardswp' ); ?>',
						message: '<?php esc_html_e( 'Choose Auto, Light, or Dark for buttons, launcher, and header text.', 'rewardswp' ); ?>',
						features: [
							'<?php esc_html_e( 'Set text and icons on your brand color to Auto, Light, or Dark', 'rewardswp' ); ?>',
							'<?php esc_html_e( 'Includes contrast warnings to keep it readable', 'rewardswp' ); ?>',
						],
						required_plan: <?php echo wp_json_encode( $upsell_foreground_mode['required_plan'] ); ?>,
						button_text: '<?php echo esc_js( $upsell_foreground_mode['button_text'] ); ?>',
						button_url: <?php echo wp_json_encode( $upsell_foreground_mode['button_url'] ); ?>,
						compare_url: <?php echo wp_json_encode( $upsell_foreground_mode['compare_url'] ); ?>,
					},
				},
				currentUpgradeModalContent: {
					title: '',
					message: '',
					features: [],
					required_plan: '',
					button_text: '',
					button_url: '',
					compare_url: ''
				},

				// Tab Navigation
				setActiveTab(tab) {
					this.activeTab = tab;
				},

				// New action defaults
				actionDefaults: {
				'purchase': {
					id: 'purchase',
					enabled: true,
					removed: false,
					points_per_dollar: 1,
					title: '<?php echo esc_js( __( 'Place an order', 'rewardswp' ) ); ?>',
					description: '<?php echo esc_js( sprintf(
						/* translators: %s: Currency symbol displayed before the number 1. */
						__( 'Earn points for every %s1 spent on purchases', 'rewardswp' ),
						get_site_currency_symbol()
					) ); ?>'
				},
					'signup': {
						id: 'signup',
						enabled: true,
						removed: false,
						points: 100,
						title: '<?php echo esc_js( __( 'Create an account', 'rewardswp' ) ); ?>',
						description: '<?php echo esc_js( __( 'Earn points for creating an account', 'rewardswp' ) ); ?>'
			},
		},

		isLicenseValid: Boolean( <?php echo esc_js( is_license_valid() ); ?> ),

			// Points Branding (Pro feature variables)
				pointsCustomPlural: '<?php echo esc_js( get_points_currency_plural() ); ?>',
				pointsCustomSingular: '<?php echo esc_js( get_points_currency_singular() ); ?>',

				// Points Expiry (Pro feature variables)
				pointsExpiryPeriod: '<?php echo esc_js( get_option_value( PointsExpirationOption::class ) ); ?>',

				// Original state for dirty tracking (serialized JSON)
				originalSettingsSerialized: null,
				// Counter to trigger Alpine reactivity on form input changes
				formChangeCounter: 0,
				// Flag to track if spend actions order was changed (via drag-and-drop)
				spendOrderChanged: false,
				// Flag to track if earn actions order was changed (via drag-and-drop)
				earnOrderChanged: false,

				fieldErrors: {},
				formHasErrors: false,
				formFeedbackMessage: null,
				formFeedbackClasses: 'text-red-500',
				rewardEditHasErrors: false,
				rewardEditFeedbackMessage: null,
				isSaving: false,
				isConfiguringReward: false,
				originalReward: null,
				setFieldError(field, message) {
					this.fieldErrors[field] = message;
				},
				clearFieldError(field) {
					delete this.fieldErrors[field];
				},
				hasFieldErrors() {
					return Object.keys(this.fieldErrors).length > 0;
				},
				setFormFeedback( message = null, type = 'error', timeout = 2000 ) {
					this.formFeedbackMessage = message || '<?php esc_html_e( 'Please resolve all issues in the form to continue.', 'rewardswp' ); ?>';
					this.formFeedbackClasses = 'success' === type
						? 'text-green-700'
						: 'text-red-500';

					this.formHasErrors = 'error' === type;

					if ( timeout < 0 ) {
						return;
					}

					setTimeout( () => {
						this.formFeedbackMessage = null;
					}, timeout );
				},
				setValidationError() {
					this.setFormFeedback( null, 'error', -1 );
				},
				cleanFormFeedback() {
					this.formFeedbackMessage = null;
					this.formFeedbackClasses = 'text-red-500';
					this.formHasErrors = false;
				},
				// Serialize form data for dirty tracking comparison
				serializeFormData() {
					const form = document.getElementById('settings-form');
					if (!form) return '';
					const formData = new FormData(form);
					// Convert to sorted entries for consistent comparison, excluding license key (has its own Connect button)
					const entries = Array.from(formData.entries())
						.filter(([key]) => !key.startsWith('rewardswp_settings[general][license]'))
						.sort((a, b) => a[0].localeCompare(b[0]));
					return JSON.stringify(entries);
				},
				// Serialize Alpine state that isn't captured in form inputs
				serializeAlpineState() {
					// Get store data for earn/spend actions (stores are the source of truth for these)
					const earnStore = Alpine.store('earnActions');
					const spendStore = Alpine.store('spendActions');
					const referralsStore = Alpine.store('referrals');

					return JSON.stringify({
						enabled: this.enabled,
						pointsEnabled: this.pointsEnabled,
						earnPointsActions: earnStore ? earnStore.enabled : this.earnPointsActions,
						spendPointsActions: spendStore ? spendStore.rewards : this.spendPointsActions,
						rewards: referralsStore ? referralsStore.rewards : this.rewards,
					});
				},
				captureOriginalSettings() {
					this.originalSettingsSerialized = this.serializeFormData() + '|' + this.serializeAlpineState();
				},
				hasSettingsChanges() {
					if (this.originalSettingsSerialized === null) return false;
					const currentSerialized = this.serializeFormData() + '|' + this.serializeAlpineState();
					return this.originalSettingsSerialized !== currentSerialized;
				},
				canSave() {
					// Reference formChangeCounter to make Alpine re-evaluate when form inputs change
					void this.formChangeCounter;
					if (this.formHasErrors || this.hasFieldErrors()) {
						return false;
					}
					// Also check if spend/earn actions order was changed via drag-and-drop
					return this.hasSettingsChanges() || this.spendOrderChanged || this.earnOrderChanged;
				},
				async saveSettings(arg = null) {

					let callbacks = null;

					if (arg && typeof arg.preventDefault === 'function') {
						arg.preventDefault();
					} else if (arg && typeof arg === 'object') {
						callbacks = arg;
					}

					this.isSaving = true;

					// If spend order was changed via drag-and-drop, apply pending order to store
					if (this.spendOrderChanged && window._pendingSpendOrder) {
						const store = Alpine.store('spendActions');
						const reorderedRewards = window._pendingSpendOrder
							.map(id => store.rewards.find(r => r.id === id))
							.filter(Boolean);

						if (reorderedRewards.length === store.rewards.length) {
							// Update the store - this will cause a visual re-render
							store.rewards.splice(0, store.rewards.length, ...reorderedRewards);
							// Increment sortIteration to force Alpine's x-for to re-render with correct order
							store.sortIteration++;
						}

						// Clear the pending order
						window._pendingSpendOrder = null;

						// Wait for Alpine to sync the store changes to hidden inputs
						await Alpine.nextTick();
						await Alpine.nextTick();
					}

					// If earn order was changed via drag-and-drop, apply order values to store
					if (this.earnOrderChanged && window._pendingEarnOrder) {
						const store = Alpine.store('earnActions');

						// Update the order property on each action based on its position in pendingEarnOrder
						// Create new objects to ensure Alpine.js reactivity is triggered
						const updatedEnabled = { ...store.enabled };
						window._pendingEarnOrder.forEach((actionId, index) => {
							if (updatedEnabled[actionId]) {
								updatedEnabled[actionId] = { ...updatedEnabled[actionId], order: index };
							}
						});

						// Apply the updated object to trigger reactivity
						store.enabled = Alpine.reactive(updatedEnabled);
						// Increment sortIteration to force x-for re-render with correct order
						store.sortIteration++;

						// Update referralOrder if referral_mirror is in pending order.
						const referralIndex = window._pendingEarnOrder.indexOf('referral_mirror');
						if (referralIndex !== -1) {
							store.referralOrder = referralIndex;
							// Manually update hidden input since Alpine's DOM update is async.
							const referralOrderInput = document.querySelector('input[name="rewardswp_settings[points][referral_mirror_order]"]');
							if (referralOrderInput) {
								referralOrderInput.value = referralIndex;
							}
						}

						// Clear the pending order
						window._pendingEarnOrder = null;

						// Wait for Alpine to sync the store changes to hidden inputs
						await Alpine.nextTick();
						await Alpine.nextTick();
					}

					const form = document.getElementById( 'settings-form' );
					const formData = new FormData( form );

					// Manually sync Alpine state for earn_actions to ensure x-model values are captured
					if (this.settings?.points?.earn_actions) {

						Object.entries(this.settings.points.earn_actions).forEach(([type, action]) => {
							if (action.points_per_dollar !== undefined) {
								const fieldName = `rewardswp_settings[points][earn_actions][${type}][points_per_dollar]`;
								formData.set(fieldName, action.points_per_dollar);
							}
						});
					}

					formData.append( 'action', 'rewardswp_save_settings' );
					formData.append( '_ajax_nonce', '<?php echo esc_js( wp_create_nonce( SettingsAdminController::AJAX_NONCE ) ); ?>' );

					fetch('<?php echo esc_js( admin_url( 'admin-ajax.php' ) ); ?>', {
						method: 'POST',
						body: formData,
					} )
					.then( ( response ) => response.json() )
					.then( ( response ) => {
						const wasSuccessful = !!response.success;
						this.setFormFeedback( response.data.message, response.success ? 'success' : 'error' );
						if (wasSuccessful) {
							this.isSaving = 'complete';

							// Show success toast notification
							window.dispatchEvent(new CustomEvent('rewardswp-toast', {
								detail: {
									message: response.data.message || '<?php esc_html_e( 'Settings saved successfully!', 'rewardswp' ); ?>',
									type: 'success'
								}
							}));

							// Reset dirty tracking after successful save
							this.captureOriginalSettings();
							this.spendOrderChanged = false;
							this.earnOrderChanged = false;

							setTimeout(() => {
								this.isSaving = false;
							}, 2000);
						} else {
							this.isSaving = false;
						}

						if (callbacks && typeof callbacks.onComplete === 'function') {
							callbacks.onComplete( wasSuccessful );
						}
					} )
					.catch( ( error ) => {
						this.setFormFeedback( '<?php esc_html_e( 'An error occurred while saving settings.', 'rewardswp' ); ?>' );
						this.isSaving = false;

						// Show error toast notification
						window.dispatchEvent(new CustomEvent('rewardswp-toast', {
							detail: {
								message: '<?php esc_html_e( 'An error occurred while saving settings.', 'rewardswp' ); ?>',
								type: 'error'
							}
						}));

						if (callbacks && typeof callbacks.onComplete === 'function') {
							callbacks.onComplete( false );
						}
					} );
				},
				// Default values for each spend action type
				getSpendActionDefaults(type) {
					const defaults = {
						'fixed_discount': {
							type: 'fixed_discount',
						enabled: true,
						custom_title: '',
						points_per_dollar: 100,
						coupon_amount: 5,
						minimum_spent: 0,
						coupon_prefix: '',
						coupon_duration: '<?php echo esc_js( SpendActionsOption::DEFAULT_COUPON_DURATION ); ?>',
						title: '<?php echo esc_js( __( 'Fixed Amount Discount', 'rewardswp' ) ); ?>',
						description: '<?php echo esc_js( __( 'Redeem points for a fixed amount discount', 'rewardswp' ) ); ?>',
						products_included: [],
						products_cache: []
					},
					'percentage_discount': {
						type: 'percentage_discount',
					enabled: true,
						custom_title: '',
						points_per_percent: 100,
						coupon_amount: 5,
						minimum_spent: 0,
						coupon_prefix: '',
						coupon_duration: '<?php echo esc_js( SpendActionsOption::DEFAULT_COUPON_DURATION ); ?>',
						title: '<?php echo esc_js( __( 'Percentage Discount', 'rewardswp' ) ); ?>',
						description: '<?php echo esc_js( __( 'Redeem points for a percentage discount', 'rewardswp' ) ); ?>',
						products_included: [],
						products_cache: []
					},
					'free_shipping': {
						type: 'free_shipping',
						enabled: true,
						custom_title: '',
						points: 500,
						minimum_spent: 0,
						coupon_prefix: '',
						coupon_duration: '<?php echo esc_js( SpendActionsOption::DEFAULT_COUPON_DURATION ); ?>',
						title: '<?php echo esc_js( __( 'Free Shipping', 'rewardswp' ) ); ?>',
						description: '<?php echo esc_js( __( 'Redeem points for free shipping', 'rewardswp' ) ); ?>',
						products_included: [],
						products_cache: []
					},
					'free_product': {
						type: 'free_product',
						enabled: true,
						custom_title: '',
						points_required: 2000,
						minimum_spent: 0,
						coupon_prefix: '',
						coupon_duration: '<?php echo esc_js( SpendActionsOption::DEFAULT_COUPON_DURATION ); ?>',
						title: '<?php echo esc_js( __( 'Free Product', 'rewardswp' ) ); ?>',
						description: '<?php echo esc_js( __( 'Redeem points for a free product', 'rewardswp' ) ); ?>',
						products_included: [],
						products_cache: []
					},
					};

					return defaults[type] || null;
				},

				// Handle spend action selection from modal
				handleSpendActionSelection(type, isUpgradeRequired) {
					if (!this.spendPointsActions) {
						this.spendPointsActions = [];
					}

					// Get action title for drawer
					const actionTitles = {
						'fixed_discount': '<?php echo esc_js( __( 'Fixed Amount Discount', 'rewardswp' ) ); ?>',
						'percentage_discount': '<?php echo esc_js( __( 'Percentage Discount', 'rewardswp' ) ); ?>',
						'free_shipping': '<?php echo esc_js( __( 'Free Shipping', 'rewardswp' ) ); ?>',
						'free_product': '<?php echo esc_js( __( 'Free Product', 'rewardswp' ) ); ?>'
					};

					if (isUpgradeRequired) {
						// Create a temporary preview action for upgrade UI
						const previewAction = this.getSpendActionDefaults(type);
						if (previewAction) {
							previewAction.id = 'preview_' + type;
							previewAction.enabled = false; // Disabled by default for preview

							// Add to array temporarily for drawer display
							this.spendPointsActions.push(previewAction);

							// Open drawer with upgrade UI
							this.drawer.open('spend', previewAction.id, actionTitles[type] || type, '', true);
						}
					} else {
						// Create new action with smart defaults
						const newAction = this.getSpendActionDefaults(type);
						if (newAction) {
							newAction.id = type + '_' + Date.now();
							this.spendPointsActions.push(newAction);

							// Open drawer immediately with the new action
							this.drawer.open('spend', newAction.id, '<?php echo esc_js( __( 'Configure', 'rewardswp' ) ); ?> ' + actionTitles[type], '', false, true);
						}
					}
			},

			// Get reward defaults based on type
				getRewardDefaults(type) {
					const rewardType = rewardswpMainVars.rewardTypes[type];
					if (!rewardType || !rewardType.defaults) {
						return null;
					}

					return {
						name: '',
						type: type,
						reward_amount: rewardType.defaults.reward_amount || 0,
						minimum_order_amount: rewardType.defaults.minimum_order_amount || 0,
						reward_expiration: rewardType.defaults.reward_expiration || 30,
						products_included: rewardType.defaults.products_included || [],
						products_cache: []
					};
			},

			getEarnAction(actionId) {
					if (!this.earnPointsActions) {
						return null;
					}

					const actions = this.earnPointsActions;

					if (Array.isArray(actions)) {
						return actions.find((action) => action && action.id === actionId) || null;
					}

					return actions[actionId] || null;
				},

				setEarnActionEnabled(actionId, enabled) {
					if (!this.earnPointsActions) {
						return;
					}

					const normalizedEnabled = Boolean(enabled);
					const actions = this.earnPointsActions;

					if (Array.isArray(actions)) {
						const index = actions.findIndex((action) => action && action.id === actionId);

						if (index === -1) {
							return;
						}

						const existing = actions[index] || {};

						actions.splice(index, 1, {
							...existing,
							enabled: normalizedEnabled,
							removed: normalizedEnabled ? false : (typeof existing.removed !== 'undefined' ? existing.removed : false)
						});

						return;
					}

					if (!actions[actionId]) {
						return;
					}

					actions[actionId].enabled = normalizedEnabled;
					if (normalizedEnabled) {
						actions[actionId].removed = false;
					}
				},

				setEarnActionRemoved(actionId, removed) {
					if (!this.earnPointsActions) {
						return;
					}

					const normalizedRemoved = Boolean(removed);
					const actions = this.earnPointsActions;

					if (Array.isArray(actions)) {
						const index = actions.findIndex((action) => action && action.id === actionId);

						if (index === -1) {
							return;
						}

						const existing = actions[index] || {};

						actions.splice(index, 1, {
							...existing,
							removed: normalizedRemoved
						});

						return;
					}

					if (!actions[actionId]) {
						return;
					}

					actions[actionId].removed = normalizedRemoved;
				},

				replaceEarnAction(actionId, replacement) {
					if (!this.earnPointsActions) {
						return;
					}

					const actions = this.earnPointsActions;
					const clone = (replacement === null || typeof replacement === 'undefined')
						? replacement
						: JSON.parse(JSON.stringify(replacement));

					if (Array.isArray(actions)) {
						const index = actions.findIndex((action) => action && action.id === actionId);

						if (index === -1) {
							if (clone !== null && typeof clone !== 'undefined') {
								actions.push(clone);
							}
							return;
						}

						if (clone === null || typeof clone === 'undefined') {
							actions.splice(index, 1);
						} else {
							actions.splice(index, 1, clone);
						}

						return;
					}

					if (clone === null || typeof clone === 'undefined') {
						delete actions[actionId];
					} else {
						actions[actionId] = clone;
					}
				},

				isEarnActionEnabled(actionId) {
					const action = this.getEarnAction(actionId);
					return !!(action && action.enabled === true && action.removed !== true);
				},

				isEarnActionVisible(actionId) {
					const action = this.getEarnAction(actionId);
					return !!(action && action.removed !== true);
				},

				// Handle earn action selection from modal
				handleEarnActionSelection(type, isUpgradeRequired) {
					const actionTitles = {
						'purchase': '<?php echo esc_js( __( 'Place an order', 'rewardswp' ) ); ?>',
						'signup': '<?php echo esc_js( __( 'Create an account', 'rewardswp' ) ); ?>',
						'referral': '<?php echo esc_js( __( 'Refer a friend', 'rewardswp' ) ); ?>',
						'product_review': '<?php echo esc_js( __( 'Leave a product review', 'rewardswp' ) ); ?>',
						'share_x': '<?php echo esc_js( __( 'Share on X', 'rewardswp' ) ); ?>',
						'share_facebook': '<?php echo esc_js( __( 'Share on Facebook', 'rewardswp' ) ); ?>',
						'share_email': '<?php echo esc_js( __( 'Share by Email', 'rewardswp' ) ); ?>',
						'blog_comment': '<?php echo esc_js( __( 'Comment on a blog post', 'rewardswp' ) ); ?>',
						'first_order': '<?php echo esc_js( __( 'First purchase bonus', 'rewardswp' ) ); ?>'
					};

					const action = this.getEarnAction(type);
					const actionTitle = actionTitles[type] || type;

					if (isUpgradeRequired) {
						// For Pro features, open drawer with upgrade UI
						if (action) {
							// Open drawer with isUpgrade = true, isNew = true
							this.drawer.open('earn', type, actionTitle, '<?php echo esc_js( __( 'Earn Points', 'rewardswp' ) ); ?>', true, true);
						}

						return;
					} else {
						// Check if already enabled (prevent duplicates)
						if (action && action.enabled === true) {
							// Already enabled, just open the drawer to edit
							this.drawer.open('earn', type, actionTitle, '<?php echo esc_js( __( 'Earn Points', 'rewardswp' ) ); ?>', false, false);
							return;
						}

						// Enable the action and open drawer with "Add" button (isNew = true)
						if (action) {
							this.setEarnActionEnabled(type, true);
							this.setEarnActionRemoved(type, false);
							// Open drawer with isUpgrade = false, isNew = true
							this.drawer.open('earn', type, actionTitle, '<?php echo esc_js( __( 'Earn Points', 'rewardswp' ) ); ?>', false, true);
							return;
						}

						// Fallback: if action definition exists but action is missing, bootstrap it from defaults.
						if (this.actionDefaults && this.actionDefaults[type]) {
							const newAction = JSON.parse(JSON.stringify(this.actionDefaults[type]));
							newAction.enabled = true;
							newAction.removed = false;

							if (Array.isArray(this.earnPointsActions)) {
								this.earnPointsActions.push(newAction);
							} else {
								this.earnPointsActions[type] = newAction;
							}

							this.drawer.open('earn', type, actionTitle, '<?php echo esc_js( __( 'Earn Points', 'rewardswp' ) ); ?>', false, true);
						}
					}
			},

			removeEarnAction(type) {
					if (this.isEarnActionEnabled(type) || this.getEarnAction(type)) {
						this.setEarnActionEnabled(type, false);
						this.setEarnActionRemoved(type, true);
						// Close drawer after removing
						this.drawer.close();
					}
				},

				editSpendAction(actionId) {
					const action = this.spendPointsActions.find(action => action.id === actionId);
					if (action) {
						this.storeOriginalValues(actionId);
						this.isEditingSpendAction = true;
						this.currentSpendAction = actionId;
					}
				},
				storeOriginalValues(actionId) {
					const action = this.spendPointsActions.find(action => action.id === actionId);
					if (action) {
						this.originalValues[actionId] = JSON.parse(JSON.stringify(action));
					}
				},
				restoreOriginalValues(actionId) {
					if (this.originalValues[actionId]) {
						const index = this.spendPointsActions.findIndex(action => action.id === actionId);
						if (index !== -1) {
							this.spendPointsActions[index] = JSON.parse(JSON.stringify(this.originalValues[actionId]));
						}
						this.originalValues[actionId] = null;
					}
				},
				toggleSpendAction(actionId, enabled) {
					const index = this.spendPointsActions.findIndex(action => action.id === actionId);
					if (index !== -1) {
						this.spendPointsActions[index].enabled = Boolean(enabled);
					}
				},
				removeSpendAction(actionId) {
					this.spendPointsActions = this.spendPointsActions.filter(action => action.id !== actionId);
				},

				// Variables needed by child components (previously in edit sections)
				earnActionErrors: {
					pointsRequired: false,
					breakpointsRequired: false
				},
				spendActionErrors: {
					pointsRequired: false,
					couponAmount: false
				},
				earnEditHasErrors: false,
				spendEditHasErrors: false,

				// Form Drawer State Management
				drawer: (() => {
					let _root = null;
					let _watch = null;
					const serialize = (value) => (typeof value === 'undefined' ? '__undefined__' : JSON.stringify(value));
					const clone = (value) => {
						if (value === null || typeof value === 'undefined') {
							return value;
						}

						return JSON.parse(JSON.stringify(value));
					};
					const drawer = {
					_init(root, watch = null) {
						_root = root;
						_watch = typeof watch === 'function' ? watch : null;
					},
					isOpen: false,
					isLoading: false,
					type: null, // 'earn', 'spend', 'referral-advocate', 'referral-friend'
					actionId: null,
					title: '',
					subtitle: '',
					errors: {},
					originalData: null,
					originalDataSerialized: null,
					currentData: null,
					currentDataSerialized: null,
					changeUnsubscribe: null,
					isUpgrade: false,
					isNew: false,

					open(type, actionId, title, subtitle = '', isUpgrade = false, isNew = false) {
						this.type = type;
						this.actionId = actionId;
						this.title = title;
						this.subtitle = subtitle;
						this.errors = {};
						this.isUpgrade = isUpgrade;
						this.isNew = isNew;

						this.teardownChangeWatcher();

						// For referral rewards, ensure the reward object exists (initialize if null)
						if (!_root) {
							console.error('Drawer not initialized before open()');
							return;
						}

						if ((type === 'referral-advocate' || type === 'referral-friend') && _root.rewards) {
							const rewardType = type === 'referral-advocate' ? 'advocate' : 'friend';
							if (!_root.rewards[rewardType]) {
								// Initialize with default structure
								_root.rewards[rewardType] = {
									type: null,
									reward_amount: '',
									minimum_order_amount: '',
									reward_expiration: 'never',
									products_included: [],
									products_cache: []
								};
							}
						}

						this.isOpen = true;
						// Store original data for comparison (unless it's an upgrade modal)
						if (!isUpgrade) {
							this.captureOriginalData();
							this.setupChangeWatcher();
						} else {
							this.currentDataSerialized = serialize(this.getCurrentData());
						}
					},

					getCurrentData() {
						if (!_root) return null;

						if (this.type === 'earn') {
							return typeof _root.getEarnAction === 'function'
								? _root.getEarnAction(this.actionId)
								: (_root.earnPointsActions ? _root.earnPointsActions[this.actionId] : null);
						}

						if (this.type === 'spend') {
							return _root.spendPointsActions
								? _root.spendPointsActions.find(a => a.id === this.actionId) || null
								: null;
						}

						if (this.type === 'referral-advocate' || this.type === 'referral-friend') {
							const rewardType = this.type === 'referral-advocate' ? 'advocate' : 'friend';
							return _root.rewards ? _root.rewards[rewardType] || null : null;
						}

						return null;
					},

					setupChangeWatcher() {
						if (!_root) return;

						this.teardownChangeWatcher();

						const compute = () => serialize(this.getCurrentData());

						this.currentDataSerialized = compute();

						if (typeof _watch === 'function') {
							this.changeUnsubscribe = _watch(compute, (value) => {
								this.currentDataSerialized = value;
							});
						} else if (typeof _root.$watch === 'function') {
							this.changeUnsubscribe = _root.$watch(compute, (value) => {
								this.currentDataSerialized = value;
							});
						} else {
							this.changeUnsubscribe = null;
						}
					},

					teardownChangeWatcher() {
						if (typeof this.changeUnsubscribe === 'function') {
							this.changeUnsubscribe();
							this.changeUnsubscribe = null;
						}
					},

					captureOriginalData() {
						if (!_root) return; // Guard against uninitialized root

						// Capture based on type
						if (this.type === 'earn') {
							const earnAction = typeof _root.getEarnAction === 'function'
								? _root.getEarnAction(this.actionId)
								: (_root.earnPointsActions ? _root.earnPointsActions[this.actionId] : null);

							this.originalData = clone(earnAction);
							this.originalDataSerialized = serialize(earnAction);
						} else if (this.type === 'spend') {
							const spendAction = _root.spendPointsActions ? _root.spendPointsActions.find(a => a.id === this.actionId) : null;
							if (spendAction) {
								this.originalData = clone(spendAction);
								this.originalDataSerialized = serialize(spendAction);
							}
						} else if (this.type === 'referral-advocate' || this.type === 'referral-friend') {
							const rewardType = this.type === 'referral-advocate' ? 'advocate' : 'friend';
							const reward = _root.rewards ? _root.rewards[rewardType] : null;
							if (reward) {
								this.originalData = clone(reward);
								this.originalDataSerialized = serialize(reward);
							}
						}

						if (!this.originalDataSerialized) {
							this.originalDataSerialized = serialize(this.originalData);
						}

						this.currentDataSerialized = this.originalDataSerialized;
					},

					hasChanges() {
						if (!_root || this.originalDataSerialized === null) return false;

						if (this.currentDataSerialized === null) {
							this.currentDataSerialized = serialize(this.getCurrentData());
						}

						return this.originalDataSerialized !== this.currentDataSerialized;
					},

					async save() {
						if (!_root) {
							console.error('Drawer not initialized');
							return;
						}

						this.isLoading = true;
						this.errors = {};

						// Validate based on type
						let isValid = true;
						if (this.type === 'earn') {
							// Reuse existing earn action validation
							const earnAction = _root.earnPointsActions ? _root.earnPointsActions[this.actionId] : null;
							isValid = _root.validateEarnAction && earnAction ? _root.validateEarnAction(earnAction) : true;
						} else if (this.type === 'spend') {
							// Reuse existing spend action validation
							const spendAction = _root.spendPointsActions ? _root.spendPointsActions.find(a => a.id === this.actionId) : null;
							isValid = _root.validateSpendAction && spendAction ? _root.validateSpendAction(spendAction) : true;
						}

						if (!isValid) {
							this.isLoading = false;
							return;
						}

						window.dispatchEvent(new CustomEvent('rewardswp:save-settings', {
							detail: {
								onComplete: (wasSuccessful) => {
									this.isLoading = false;

									if (wasSuccessful) {
										this.close(true);
									}
								}
							}
						}));
					},

					close(force = false) {
						// If this is an upgrade preview, just remove it
						if (this.isUpgrade) {
							this.removeNewAction();
							this.reset();
							return;
						}

						// If this is a new unsaved action, remove it from the array
						if (this.isNew && !force) {
							if (this.hasChanges()) {
								if (!confirm('<?php echo esc_js( __( 'Discard this new action?', 'rewardswp' ) ); ?>')) {
									return;
								}
							}
							// Remove the new action from the array
							this.removeNewAction();
							this.reset();
							return;
						}

						// For existing actions, handle unsaved changes
						if (!force && this.hasChanges()) {
							if (!confirm('<?php echo esc_js( __( 'You have unsaved changes. Are you sure you want to discard them?', 'rewardswp' ) ); ?>')) {
								return;
							}
							// Restore original values
							this.restoreOriginalData();
						}

						this.reset();
					},

					removeNewAction() {
						// Remove new or preview actions
						if (!this.isNew && !this.isUpgrade || !_root) return;

						if (this.type === 'spend' && _root.spendPointsActions) {
							const index = _root.spendPointsActions.findIndex(a => a.id === this.actionId);
							if (index !== -1) {
								_root.spendPointsActions.splice(index, 1);
							}
						} else if (this.type === 'earn') {
							// Future: handle earn actions if needed
						} else if (this.type === 'referral-advocate' || this.type === 'referral-friend') {
							const rewardType = this.type === 'referral-advocate' ? 'advocate' : 'friend';
							if (_root.rewards) {
								_root.rewards[rewardType] = null;
							}
						}
					},

					restoreOriginalData() {
						if ((!this.originalData && this.originalData !== null) || !_root) return;

						if (this.type === 'earn' && _root.earnPointsActions) {
							if (typeof _root.replaceEarnAction === 'function') {
								_root.replaceEarnAction(this.actionId, this.originalData);
							} else {
								_root.earnPointsActions[this.actionId] = clone(this.originalData);
							}
						} else if (this.type === 'spend' && _root.spendPointsActions) {
							const index = _root.spendPointsActions.findIndex(a => a.id === this.actionId);
							if (index !== -1) {
								_root.spendPointsActions[index] = clone(this.originalData);
							}
						} else if (this.type === 'referral-advocate' || this.type === 'referral-friend') {
							const rewardType = this.type === 'referral-advocate' ? 'advocate' : 'friend';
							if (_root.rewards) {
								_root.rewards[rewardType] = clone(this.originalData);
							}
						}
					},

					reset() {
						this.isOpen = false;
						this.isLoading = false;
						this.teardownChangeWatcher();
						this.type = null;
						this.actionId = null;
						this.title = '';
						this.subtitle = '';
						this.errors = {};
						this.originalData = null;
						this.originalDataSerialized = null;
						this.currentData = null;
						this.currentDataSerialized = null;
						this.isUpgrade = false;
						this.isNew = false;
						// Notify main component to re-check for changes
						window.dispatchEvent(new CustomEvent('rewardswp:drawer-closed'));
					}
					};
					return drawer;
				})(),

				};
			};
		</script>

		<div
			x-data="initRewardswpSettings()"
			x-init="
				drawer._init(this, $watch);
				activeTab = '<?php echo esc_js( $active_tab ); ?>';
				window.addEventListener('rewardswp:save-settings', async (event) => {
					// Wait for Alpine to sync x-model values to the DOM before saving
					await Alpine.nextTick();
					const detail = event && event.detail ? event.detail : null;
					saveSettings(detail);
				});
			window.addEventListener('rewardswp:change-tab', async (event) => {
				if (event.detail && event.detail.tab) {
					setActiveTab(event.detail.tab);

					// Scroll to top so the new tab content is visible.
					window.scrollTo({ top: 0 });

					// Update URL to reflect the new tab.
					const newUrl = new URL(window.location);
					newUrl.searchParams.set('tab', event.detail.tab);
					history.pushState(null, '', newUrl);

					// If we need to open the advocate drawer after changing to referrals tab
					if (event.detail.openAdvocateDrawer && event.detail.tab === 'referrals') {
						await Alpine.nextTick();
						// Dispatch event for referralsSection component to handle
						window.dispatchEvent(new CustomEvent('open-advocate-reward-drawer'));
					}
				}
			});

			// Watch pointsEnabled and notify referrals store when it changes
			$watch('pointsEnabled', (value) => {
				$nextTick(() => { formChangeCounter++; });
				window.dispatchEvent(new CustomEvent('points-program-toggled', {
					detail: { enabled: value }
				}));
			});

			// Watch Alpine state variables for dirty tracking (these don't trigger form input/change events)
			$watch('enabled', () => { $nextTick(() => { formChangeCounter++; }); });

			// Listen for drawer close and settings changes to re-check for changes
			window.addEventListener('rewardswp:drawer-closed', () => {
				$nextTick(() => { formChangeCounter++; });
			});
			window.addEventListener('rewardswp:settings-changed', () => {
				$nextTick(() => { formChangeCounter++; });
			});
			// Listen for spend actions order change (via drag-and-drop)
			window.addEventListener('rewardswp:spend-order-changed', () => {
				spendOrderChanged = true;
				$nextTick(() => { formChangeCounter++; });
			});
			// Listen for earn actions order change (via drag-and-drop)
			window.addEventListener('rewardswp:earn-order-changed', () => {
				earnOrderChanged = true;
				$nextTick(() => { formChangeCounter++; });
			});

			// Capture original settings for dirty tracking after initial load
			$nextTick(() => { captureOriginalSettings(); });
			"
			x-ref="settingsData"
		>
			<div class="rewardswp-container max-[782px]:ml-[-10px] ml-[-20px]">
				<form id="settings-form" method="post" x-on:submit="saveSettings" x-on:input="formChangeCounter++" x-on:change="formChangeCounter++" x-on:click="if ($event.target.closest('[role=switch]')) $nextTick(() => { formChangeCounter++; });">

						<?php

						do_settings_sections( OptionsService::OPTION_NAME );

						?>

						<?php
						/**
						 * Settings navigation.
						 */

						$tabs = [
							'general'        => [
								'label'    => esc_html__( 'General', 'rewardswp' ),
								'href'     => add_query_arg( [ 'page' => 'rewardswp-settings', 'tab' => 'general' ], admin_url( 'admin.php' ) ),
								'pro_only' => false,
							],
							'points'         => [
								'label'    => esc_html__( 'Points', 'rewardswp' ),
								'href'     => add_query_arg( [ 'page' => 'rewardswp-settings', 'tab' => 'points' ], admin_url( 'admin.php' ) ),
								'pro_only' => false,
							],
							'referrals'      => [
								'label'    => esc_html__( 'Referrals', 'rewardswp' ),
								'href'     => add_query_arg( [ 'page' => 'rewardswp-settings', 'tab' => 'referrals' ], admin_url( 'admin.php' ) ),
								'pro_only' => false,
							],
							'rewards_widget' => [
								'label'    => esc_html__( 'Widget', 'rewardswp' ),
								'href'     => add_query_arg( [ 'page' => 'rewardswp-settings', 'tab' => 'rewards_widget' ], admin_url( 'admin.php' ) ),
								'pro_only' => false,
							],
							'integrations'   => [
								'label'    => esc_html__( 'Integrations', 'rewardswp' ),
								'href'     => add_query_arg( [ 'page' => 'rewardswp-settings', 'tab' => 'integrations' ], admin_url( 'admin.php' ) ),
								'pro_only' => false,
							],
						];

						$common_classes   = 'px-4 py-5 text-sm whitespace-nowrap focus:outline-none focus:border-b-2 focus:border-blue-500';
						$active_classes   = 'text-blue-600 border-b-2 border-blue-500 ';
						$inactive_classes = 'text-gray-800 hover:text-gray-600';

						?>
						<div id="rewardswp-admin-settings-sentinel" class="absolute top-0 left-0 right-0"></div>

						<div class="px-8 pt-5 mx-auto max-w-7xl sr-only">
							<div class="mb-6 flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
								<h1 class="text-2xl font-semibold text-slate-900"><?php echo esc_html( $args['page_title'] ); ?></h1>
							</div>
						</div>

						<div id="rewardswp-admin-settings-header" class="transition-shadow duration-250 shadow-gray-800/10 sticky max-[601px]:top-0 max-[783px]:top-[46px] top-[32px] bg-[#f0f0f1] z-10 border-b border-gray-300">
							<div class="px-8 mx-auto max-w-7xl flex justify-between items-center">
								<nav class="flex font-semibold overflow-x-auto scrollbar" aria-label="<?php esc_attr_e( 'Tabs', 'rewardswp' ); ?>">
									<?php foreach ( $tabs as $tab_key => $tab ) : ?>
										<?php
										if ( $tab['pro_only'] && ! is_rewardswp_pro_plan() ) {
											continue;
										}
										?>
										<a
											x-on:click.prevent="setActiveTab( '<?php echo esc_js( $tab_key ); ?>' ); history.pushState(null, '', '<?php echo esc_js( $tab['href'] ); ?>')"
											x-bind:class="{ '<?php echo esc_attr( $active_classes ); ?>': activeTab === '<?php echo esc_js( $tab_key ); ?>', '<?php echo esc_attr( $inactive_classes ); ?>': activeTab !== '<?php echo esc_js( $tab_key ); ?>' }"
											href="<?php echo esc_url( $tab['href'] ); ?>"
											class="<?php echo esc_attr( $common_classes ); ?>"
										>
											<?php echo esc_html( $tab['label'] ); ?>

										</a>
									<?php endforeach; ?>
								</nav>

								<?php $this->render_save_button( [ 'button_classes' => 'max-[783px]:hidden' ] ); ?>

							</div>
						</div>

						<div class="px-8 pt-5 mx-auto max-w-7xl">

						<div
							x-show="activeTab !== 'referrals' || (activeTab === 'referrals' && !isConfiguringReward)"
							class=""
						>
							<?php $this->render_save_button( [ 'button_classes' => 'min-[783px]:hidden mb-5 place-self-end' ] ); ?>
						</div>


						<?php
						/**
						 * General section.
						 */
						?>
						<div
							x-show="activeTab === 'general'"
							id="general"
							x-cloak
						>
							<?php

							/* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Contents are escaped by the function */
							echo wp_kses(
								get_view_component(
									'section',
									[
										'title'   => esc_html__( 'License', 'rewardswp' ),
										'content' => $this->views_factory->get_view( LicenseSectionView::class )->get_contents(),
										'id'      => 'license_settings',
									]
								),
								kses()
							);

							echo wp_kses(
								get_view_component(
									'section',
									[
										'title'   => esc_html__( 'General Settings', 'rewardswp' ),
										'content' => $this->views_factory->get_view( GeneralSettingsContentView::class )->get_contents(),
										'id'      => 'general_settings',
									]
								),
								kses()
							);

							?>

						</div>

						<?php
						/**
						 * Points section.
						 */
						?>
						<div
							x-show="activeTab === 'points'"
							id="points"
							x-cloak
						>
							<?php

							echo wp_kses(
								get_view_component(
									'section',
									[
										'title'   => esc_html__( 'Points', 'rewardswp' ),
										'content' => $this->views_factory->get_view( PointsStatusContentView::class )->get_contents(),
										'id'      => 'points_status',
									]
								),
								kses()
							);

							// Points Branding Section (Shows for both Lite and Pro, content differs)
							echo wp_kses(
								get_view_component(
									'section',
									[
										'title'   => esc_html__( 'Points Branding', 'rewardswp' ),
										'content' => $this->views_factory->get_view( PointsBrandingContentView::class )->get_contents(),
										'id'      => 'points_branding',
									]
								),
								kses()
							);

							// Points Expiry Section (Shows for both Lite and Pro, content differs)
							echo wp_kses(
								get_view_component(
									'section',
									[
										'title'   => esc_html__( 'Points Expiry', 'rewardswp' ),
										'content' => $this->views_factory->get_view( PointsExpiryContentView::class )->get_contents(),
										'id'      => 'points_expiry',
									]
								),
								kses()
							);

							// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Content is escaped within the view
							echo get_view_component(
								'section',
								[
									'title'   => esc_html__( 'Earning Points', 'rewardswp' ),
									'content' => $this->views_factory->get_view( EarnPointsActionsDrawerView::class )->get_contents(),
									'id'      => 'earn_points_actions_drawer',
								]
							);

							// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Content is escaped within the view
							echo get_view_component(
								'section',
								[
									'title'   => esc_html__( 'Redeeming Points', 'rewardswp' ),
									'content' => $this->views_factory->get_view( SpendPointsActionsDrawerView::class )->get_contents(),
									'id'      => 'spend_points_actions_drawer',
								]
							);

							?>



						</div>

						<?php

						/**
						 * Referrals section.
						 */

						$sharing_options = get_option_value( SharingOption::class );

						?>
						<div
							x-ref="referrals_tab"
							x-show="activeTab === 'referrals'"
							id="referrals"
							x-cloak
							@remove-referral-reward.window="setReward($event.detail.context, null)"
							x-data="{
								enabled: <?php echo get_option_value( EnabledOption::class ) ? 'true' : 'false'; ?>,
								rewardCount: {
									advocate: '',
									friend: ''
								},
							currentContext: 'advocate',
							selectedRewardType: null,
							showingUpgradeModal: false,
							upgradeFeature: '',
								getEditingRewardTitle(reward, context) {
									if (!reward || !reward.type) return '';

									let title = '';
									switch (reward.type) {
										case 'fixed_discount':
											title = reward.reward_amount !== undefined ?
												`${<?php echo \Awesomemotive\Rewardswp\Helpers\js_money_expr( 'reward.reward_amount', 'this.currencySymbol' ); ?>} <?php echo esc_js( __( 'off', 'rewardswp' ) ); ?> ${reward.product_category ? '<?php echo esc_js( __( 'selected category', 'rewardswp' ) ); ?>' : '<?php echo esc_js( __( 'entire order', 'rewardswp' ) ); ?>'}` :
												'<?php esc_html_e( 'Amount off coupon', 'rewardswp' ); ?>';
											break;
										case 'percentage_discount':
											title = reward.reward_amount !== undefined ?
												`${reward.reward_amount}% <?php echo esc_js( __( 'off', 'rewardswp' ) ); ?> ${reward.product_category ? '<?php echo esc_js( __( 'selected category', 'rewardswp' ) ); ?>' : '<?php echo esc_js( __( 'entire order', 'rewardswp' ) ); ?>'}` :
												'<?php esc_html_e( 'Percentage off coupon', 'rewardswp' ); ?>';
											break;
										case 'free_shipping':
											title = '<?php esc_html_e( 'Free shipping coupon', 'rewardswp' ); ?>';
											break;
										case 'free_product':
											title = '<?php esc_html_e( 'Free product coupon', 'rewardswp' ); ?>';
											break;
										default:
											title = `${context.charAt(0).toUpperCase() + context.slice(1)} ${rewardswpMainVars.rewardTypes[reward.type]?.title || ''}`;
									}

									return title;
								},
								getDisplayRewardTitle(reward, context) {
									if (!reward || !reward.type) return '';

									let title = '';
									switch (reward.type) {
										case 'fixed_discount':
											title = reward.reward_amount !== undefined ?
												`${<?php echo \Awesomemotive\Rewardswp\Helpers\js_money_expr( 'reward.reward_amount', 'this.currencySymbol' ); ?>} <?php echo esc_js( __( 'off coupon', 'rewardswp' ) ); ?>` :
												'<?php esc_html_e( 'Amount off coupon', 'rewardswp' ); ?>';
											break;
										case 'percentage_discount':
											title = reward.reward_amount !== undefined ?
												`${reward.reward_amount}% <?php echo esc_js( __( 'off coupon', 'rewardswp' ) ); ?>` :
												'<?php esc_html_e( 'Percentage off coupon', 'rewardswp' ); ?>';
											break;
										case 'free_shipping':
											title = '<?php esc_html_e( 'Free shipping coupon', 'rewardswp' ); ?>';
											break;
										case 'free_product':
											title = '<?php esc_html_e( 'Free product coupon', 'rewardswp' ); ?>';
											break;
										default:
											title = `${context.charAt(0).toUpperCase() + context.slice(1)} ${rewardswpMainVars.rewardTypes[reward.type]?.title || ''}`;
									}

									return title;
								},
								async updateDisplayRewardCount(reward, context) {
									if (!reward || !reward.type) return '';

									const formData = new FormData();

									formData.append('action', 'rewardswp_get_reward_count');
									formData.append('_ajax_nonce', '<?php echo esc_js( wp_create_nonce( SettingsAdminController::AJAX_NONCE ) ); ?>');
									formData.append('recipient_type', context);
									formData.append('reward_type', reward.type);
									formData.append('reward_amount', reward.reward_amount);

									this.rewardCount[ context ] = '';

									try {
										const response = await fetch('<?php echo esc_js( admin_url( 'admin-ajax.php' ) ); ?>', {
											method: 'POST',
											body: formData,
										});

										const result = await response.json();

										this.rewardCount[ context ] = result.data.message;
									} catch (error) {
										return;
									}
								},
								onUpdateReward() {
									this.updateDisplayRewardCount( this.rewards.advocate, 'advocate' );
									this.updateDisplayRewardCount( this.rewards.friend, 'friend' );
								},
								getRewardIcon(type) {
									return rewardswpMainVars.rewardTypes[type]?.icon || '';
								},
								getRewardTypeTitle(type) {
									return rewardswpMainVars.rewardTypes[type]?.title || '<?php esc_html_e( 'Reward', 'rewardswp' ); ?>';
								},
								getRewardSetting(setting) {
									if (this.currentContext && this.rewards[this.currentContext]) {
										const value = this.rewards[this.currentContext][setting];
										if (value === null || value === '') return '';
										return value ?? this.getDefaultValue(setting, this.rewards[this.currentContext].type);
									}
									return this.getDefaultValue(setting, this.selectedRewardType);
								},
								setRewardSetting(key, value) {
									if (!this.rewards[this.currentContext]) {
										this.rewards[this.currentContext] = {};
									}
									this.rewards[this.currentContext][key] = value;

									// If the reward_amount is being updated, also update the name
									if (key === 'reward_amount') {
										const updatedName = this.getDisplayRewardTitle({
											type: this.selectedRewardType,
											reward_amount: value
										}, this.currentContext);
										this.rewards[this.currentContext].name = updatedName;
									}

									if (['reward_amount', 'minimum_order_amount'].includes(key)) {
										const sanitizedValue = String(value).replace(/[^\d.]/g, '').replace(/(\..*)\./g, '$1');
										this.rewards[this.currentContext][key] = sanitizedValue === '' ? 0 : Math.max(0, parseFloat(sanitizedValue));
									}
								},
								getDefaultValue(setting, type) {
									return rewardswpMainVars.rewardTypes[type]?.defaults?.[setting] ?? 0;
								},
								isUpdatingReward: false,
								updateReward(context) {
									this.isConfiguringReward = true;
									this.isUpdatingReward = true;
									this.currentContext = context;
									this.selectedRewardType = this.rewards[context]?.type || null;
									// Store original reward data
									this.originalReward = this.rewards[context] ? {...this.rewards[context]} : null;
									// Ensure all the reward settings are properly loaded
									if (this.rewards[context]) {
										Object.keys(this.rewards[context]).forEach(key => {
											this.setRewardSetting(key, this.rewards[context][key]);
										});
									}
								},
								setReward(context, data) {
									if (data === null) {
										this.rewards[context] = null;
										return;
									}
									this.rewards[context] = { ...(this.rewards[context] || {}), ...data };
								},
								getInputId(base) {
									return `${base}-${this.currentContext}`;
								},
							showUpgradeModal(feature) {
								this.upgradeFeature = feature;
								this.showingUpgradeModal = true;
							},
								cancelEditing() {
									this.rewardEditHasErrors = false;
									this.isConfiguringReward = false;

									if (this.isUpdatingReward && this.originalReward) {
										// Restore original reward data for updates
										this.rewards[this.currentContext] = this.originalReward;
									} else if (!this.isUpdatingReward) {
										// Remove reward data for new rewards
										delete this.rewards[this.currentContext];
									}

									this.isUpdatingReward = false;
									this.currentContext = 'advocate';
									this.selectedRewardType = null;
									this.originalReward = null;
								},
								validateRewardEdit() {
									// Trigger Choices validation only within the referrals tab and visible components
									this.rewardEditHasErrors = true;
									const container = this.$refs.referrals_tab || document;
									const choicesComponents = Array.from(container.querySelectorAll('[x-data^=\'choicesComponent\']'))
										.filter(el => el.offsetParent !== null);
									let hasErrors = false;

									choicesComponents.forEach((component) => {
										const alpineComponent = Alpine.$data(component);
										if (alpineComponent && typeof alpineComponent.validate === 'function') {
											alpineComponent.validate();
											if (alpineComponent.hasErrors) {
												hasErrors = true;
											}
										}
									});

									if ( hasErrors ) {
										return;
									}

									this.rewardEditHasErrors = false;
									this.isConfiguringReward = false;
									this.isUpdatingReward = false;
							this.originalReward = null;
							this.onUpdateReward();
						}
					}"
					x-init="
						$watch('enabled', (value) => {
							window.dispatchEvent(new CustomEvent('referrals-program-toggled', {
								detail: { enabled: value }
							}));
						})
					"
				>

								<?php
							// Note: Hidden inputs for rewards data are in ReferralsRewardsDrawerView.php
							// which properly binds to the $store.referrals.rewards Alpine store.

							echo wp_kses(
								get_view_component(
									'section',
									[
										'title'   => esc_html__( 'Referrals', 'rewardswp' ),
										'content' => $this->views_factory->get_view( ReferralsProgramStatusContentView::class )->get_contents(),
										'id'      => 'program_status',
										'additional_attributes' => 'x-show="!isConfiguringReward"',
									]
								),
								kses()
							);

							// Referral Tracking Section.
							echo wp_kses(
								get_view_component(
									'section',
									[
										'title'   => esc_html__( 'Referral Tracking', 'rewardswp' ),
										'content' => $this->views_factory->get_view( ReferralsTrackingContentView::class )->get_contents(),
										'id'      => 'referral_tracking',
										'additional_attributes' => 'x-show="!isConfiguringReward"',
									]
								),
								kses()
							);

							// Referral Rewards Section.
							echo wp_kses(
								get_view_component(
									'section',
									[
										'title'   => esc_html__( 'Referral Rewards', 'rewardswp' ),
										'content' => $this->views_factory->get_view( ReferralsRewardsDrawerView::class )->get_contents(),
										'id'      => 'referrals_rewards_drawer',
									]
								),
								kses()
							);

							?>



							<?php

							/**
							 * Fires after the Referrals settings tab content.
							 *
							 * @since 1.1.0
							 */
							do_action( 'rewardswp_settings_referrals_after' );

							?>

						</div>

						<?php
						/**
						 * Rewards Widget.
						 */
						?>
						<div
							x-show="activeTab === 'rewards_widget'"
							id="rewards_widget"
							x-cloak
							x-data="{
								enabled: <?php echo get_option_value( PointsEnabledOption::class ) ? 'true' : 'false'; ?>,
								rewards: {
									advocate: <?php echo esc_js( $advocate_reward ); ?>,
									friend: <?php echo esc_js( $friend_reward ); ?>
								},
								launcher: {
									display: '<?php echo esc_js( get_option_value( LauncherDisplayOption::class ) ); ?>',
									buttonText: '<?php echo esc_js( get_option_value( LauncherTextOption::class ) ); ?>',
								},
								sharing: {
									x: <?php echo $sharing_options['x'] ? 'true' : 'false'; ?>,
									facebook: <?php echo $sharing_options['facebook'] ? 'true' : 'false'; ?>,
									email: <?php echo $sharing_options['email'] ? 'true' : 'false'; ?>,
								},
								hasFriendReward: <?php echo ! empty( $rewards_options['friend'] ) && ! empty( $rewards_options['friend']['type'] ) ? 'true' : 'false'; ?>,
								getSharing() {
									return Object.keys( this.sharing ).filter( key => this.sharing[ key ] );
								},
								previewMemberState: 'logged_out',
								updatePreviewState(newState) {
									if (this.previewMemberState === newState) {
										return;
									}
									this.previewMemberState = newState;
									this.positionPreviewMarker();
									// Dispatch event to Alpine widget to switch state instantly (no AJAX needed)
									window.dispatchEvent(new CustomEvent('switch-preview-member-state', { detail: newState }));
								},
								positionPreviewMarker() {
									const marker = this.$refs.previewMarker;
									if (!marker) return;

									const buttonMap = {
										'logged_out': this.$refs.guestButton,
										'logged_in': this.$refs.memberButton,
										'friend': this.$refs.friendButton,
										'friend-claimed': this.$refs.friendClaimedButton,
									};
									const targetButton = buttonMap[this.previewMemberState];

									if (targetButton && targetButton.offsetParent !== null) {
										marker.style.width = targetButton.offsetWidth + 'px';
										marker.style.left = targetButton.offsetLeft + 'px';
									}
								},
							}"
						x-init="$watch('activeTab', (val) => val === 'rewards_widget' && $nextTick(() => positionPreviewMarker()))"
						x-effect="activeTab === 'rewards_widget' && $nextTick(() => positionPreviewMarker())"
						>
							<div class="@container">
								<div class="grid grid-cols-1 @[50rem]:grid-cols-12 gap-6">
									<div class="@[50rem]:col-span-6">
									<?php

									echo wp_kses(
										get_view_component(
											'section',
											[
												'title'   => esc_html__( 'General', 'rewardswp' ),
												'content' => $this->views_factory->get_view( RewardsWidgetGeneralContentView::class )->get_contents(),
												'id'      => 'display_general_options',
											]
										),
										kses()
									);

									echo wp_kses(
										get_view_component(
											'section',
											[
												'title'   => esc_html__( 'Rewards Launcher', 'rewardswp' ),
												'content' => $this->views_factory->get_view( RewardsWidgetLauncherContentView::class )->get_contents(),
												'id'      => 'rewards_launcher_options',
											]
										),
										kses()
									);

									echo wp_kses(
										get_view_component(
											'section',
											[
												'title'   => esc_html__( 'Sharing Options', 'rewardswp' ),
												'content' => $this->views_factory->get_view( RewardsWidgetSharingOptionsContentView::class )->get_contents(),
												'id'      => 'referrals_sharing_options',
												'additional_attributes' => 'x-show="!isConfiguringReward"',
											]
										),
										kses()
									);

									?>
									</div>
									<div class="@[50rem]:col-span-6 h-full sticky top-[128px] z-5">
										<!-- Widget Preview - only show when at least one program enabled -->
										<div
											x-show="$store.referrals.pointsProgramEnabled || $store.referrals.referralsProgramEnabled"
											class="relative h-[780px] border-dashed border-3 border-gray-300"
										>
											<?php
												$main_admin_controller = $this->container->get( MainAdminController::class );
												$main_admin_controller->render_settings_panel();
											?>
										</div>
										<!-- Empty State - show when no programs enabled -->
										<div
											x-show="!$store.referrals.pointsProgramEnabled && !$store.referrals.referralsProgramEnabled"
											x-cloak
											class="relative h-[780px] border-dashed border-3 border-gray-300 flex items-center justify-center"
										>
											<div class="bg-white rounded-2xl shadow-xl px-10 py-8 max-w-md w-full ring-1 ring-gray-300/50 text-center">
												<!-- Rocket Icon -->
												<div class="mx-auto flex items-center justify-center mb-4 text-gray-400">
													<?php echo wp_kses( $this->icon_helper->get_icon( 'rocket', 'size-12' ), svg_kses() ); ?>
												</div>
												<!-- Title -->
												<h3 class="text-lg font-semibold text-gray-900 mb-3">
													<?php esc_html_e( 'Almost ready', 'rewardswp' ); ?>
												</h3>
												<!-- Description -->
												<p class="text-slate-600 mb-6 text-pretty">
													<?php esc_html_e( 'Enable Points or Referrals to preview your rewards widget here.', 'rewardswp' ); ?>
												</p>
												<!-- Buttons -->
												<div class="flex gap-3 justify-center">
													<a href="<?php echo esc_url( admin_url( 'admin.php?page=rewardswp-settings&tab=points#points_status' ) ); ?>" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg shadow-sm hover:bg-gray-50 transition-colors">
														<?php esc_html_e( 'Go to Points', 'rewardswp' ); ?>
													</a>
													<a href="<?php echo esc_url( admin_url( 'admin.php?page=rewardswp-settings&tab=referrals#program_status' ) ); ?>" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg shadow-sm hover:bg-gray-50 transition-colors">
														<?php esc_html_e( 'Go to Referrals', 'rewardswp' ); ?>
													</a>
												</div>
											</div>
										</div>
										<!-- Preview Switcher - hide when no programs enabled -->
										<div x-show="$store.referrals.pointsProgramEnabled || $store.referrals.referralsProgramEnabled" class="flex justify-end mt-3">
											<div class="relative inline-flex items-center h-9 p-1 bg-gray-200 rounded-lg select-none" role="radiogroup" aria-label="<?php esc_attr_e( 'Preview mode', 'rewardswp' ); ?>">
												<button
													x-ref="guestButton"
													type="button"
													x-on:click="updatePreviewState('logged_out')"
													x-bind:class="previewMemberState === 'logged_out' ? 'text-gray-900' : 'text-gray-600 hover:text-gray-900'"
													class="relative z-20 inline-flex items-center justify-center h-7 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap"
												>
													<?php esc_html_e( 'Guest', 'rewardswp' ); ?>
												</button>
												<button
													x-ref="memberButton"
													type="button"
													x-on:click="updatePreviewState('logged_in')"
													x-bind:class="previewMemberState === 'logged_in' ? 'text-gray-900' : 'text-gray-600 hover:text-gray-900'"
													class="relative z-20 inline-flex items-center justify-center h-7 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap"
												>
													<?php esc_html_e( 'Member', 'rewardswp' ); ?>
												</button>
												<button
													x-ref="friendButton"
													x-show="hasFriendReward"
													type="button"
													x-on:click="updatePreviewState('friend')"
													x-bind:class="previewMemberState === 'friend' ? 'text-gray-900' : 'text-gray-600 hover:text-gray-900'"
													class="relative z-20 inline-flex items-center justify-center h-7 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap"
												>
													<?php esc_html_e( 'Friend', 'rewardswp' ); ?>
												</button>
												<button
													x-ref="friendClaimedButton"
													x-show="hasFriendReward"
													type="button"
													x-on:click="updatePreviewState('friend-claimed')"
													x-bind:class="previewMemberState === 'friend-claimed' ? 'text-gray-900' : 'text-gray-600 hover:text-gray-900'"
													class="relative z-20 inline-flex items-center justify-center h-7 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap"
												>
													<?php esc_html_e( 'Friend (claimed)', 'rewardswp' ); ?>
												</button>
												<div
													x-ref="previewMarker"
													class="absolute z-10 duration-200 ease-out bg-white rounded-md top-1"
													style="height: 28px;"
												></div>
											</div>
										</div>
									</div>
								</div>
							</div>
						</div>

						<?php
						/**
						 * Integrations section.
						 */

						$active_integration = get_option_value( IntegrationSourceOption::class );

						?>

						<div
							x-show="activeTab === 'integrations'"
							x-data="{
								activeIntegration: '<?php echo esc_js( $active_integration ); ?>',
							}"
							id="integrations"
							x-cloak
						>

							<?php

							echo wp_kses(
								get_view_component(
									'section',
									[
										'title'        => esc_html__( 'WooCommerce', 'rewardswp' ),
										'content'      => $this->views_factory->get_view( WooCommerceIntegrationContentView::class )->get_contents(),
										'id'           => 'integrations_woocommerce',
										'default_open' => false,
										'icon'         => $this->icon_helper->get_icon( 'woocommerce', 'w-10 h-10' ),
										'badge'        => 'woocommerce' === $active_integration ? 'active' : '',
										'collapsible'  => false,
									]
								),
								kses()
							);

							echo wp_kses(
								get_view_component(
									'section',
									[
										'title'        => esc_html__( 'Easy Digital Downloads', 'rewardswp' ),
										'content'      => $this->views_factory->get_view( EasyDigitalDownloadsIntegrationContentView::class )->get_contents(),
										'id'           => 'integrations_easy_digital_downloads',
										'default_open' => false,
										'icon'         => $this->icon_helper->get_icon( 'easy-digital-downloads', 'w-10 h-10' ),
										'badge'        => 'easy_digital_downloads' === $active_integration ? 'active' : '',
										'collapsible'  => false,
									]
								),
								kses()
							);

							/**
							 * Fires after the Integrations settings tab content.
							 *
							 * @since 1.1.0
							 */
							do_action( 'rewardswp_settings_integrations_after' );

							?>

						</div>


					</div>

					<div
						x-show="activeTab !== 'referrals' || (activeTab === 'referrals' && !isConfiguringReward)"
						class="px-5 pt-2 max-w-7xl"
					>
						<?php $this->render_save_button( [ 'button_classes' => 'min-[783px]:hidden place-self-end' ] ); ?>
					</div>

				</form>

				<div class="rewardswp-container">
					<?php
					/**
					 * Global Modals
					 */
					$this->views_factory->get_view( UpgradeModalView::class )->render();

					/**
					 * Drawer for editing actions
					 */
					$shared_drawer         = $this->views_factory->get_view( DrawerComponentView::class );
					$earn_drawer_view      = $this->views_factory->get_view( EarnPointsActionsDrawerView::class );
					$spend_drawer_view     = $this->views_factory->get_view( SpendPointsActionsDrawerView::class );
					$referrals_drawer_view = $this->views_factory->get_view( ReferralsRewardsDrawerView::class );

					if ( $shared_drawer instanceof DrawerComponentView
					&& $earn_drawer_view instanceof EarnPointsActionsDrawerView
					&& $spend_drawer_view instanceof SpendPointsActionsDrawerView
					&& $referrals_drawer_view instanceof ReferralsRewardsDrawerView ) {

						// Get all three drawer content callbacks.
						$earn_callback      = $earn_drawer_view->get_drawer_content_callback();
						$spend_callback     = $spend_drawer_view->get_drawer_content_callback();
						$referrals_callback = $referrals_drawer_view->get_drawer_content_callback();

						// Create a wrapper callback that calls all three.
						$combined_callback = function () use ( $earn_callback, $spend_callback, $referrals_callback ) {
							call_user_func( $earn_callback );
							call_user_func( $spend_callback );
							call_user_func( $referrals_callback );
						};

						$shared_drawer->render(
							[
								'alpine_var'       => 'drawer',
								'content_callback' => $combined_callback,
							]
						);
					}
					?>
				</div>
			</div>
		</div>

		<?php
	}

}
