<?php
/**
 * Member detail 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\Abstracts\AbstractView;
use Awesomemotive\Rewardswp\Interfaces\ViewInterface;
use Awesomemotive\Rewardswp\Models\Member;
use Awesomemotive\Rewardswp\Helpers\IconHelper;
use Awesomemotive\Rewardswp\Models\Reward;
use Awesomemotive\Rewardswp\Factories\ViewsFactory;
use Awesomemotive\Rewardswp\Views\Admin\Modals\AdjustPointsModalView;
use Awesomemotive\Rewardswp\Views\Admin\Modals\UpdateReferralCodeModalView;
use Awesomemotive\Rewardswp\Views\Admin\Modals\EditMemberModalView;
use Awesomemotive\Rewardswp\Views\Admin\Modals\ExcludeMemberModalView;
use Awesomemotive\Rewardswp\Views\Admin\Modals\DeleteMemberModalView;
use Awesomemotive\Rewardswp\Settings\Options\Points\PointsEnabledOption;
use Awesomemotive\Rewardswp\Settings\Options\Referrals\EnabledOption as ReferralsEnabledOption;
use function Awesomemotive\Rewardswp\Helpers\get_advocate_rewards;
use function Awesomemotive\Rewardswp\Helpers\get_referral_link_base_url;
use function Awesomemotive\Rewardswp\Helpers\get_referrals;
use function Awesomemotive\Rewardswp\Helpers\get_reward_formatted_amount;
use function Awesomemotive\Rewardswp\Helpers\get_site_currency_symbol;
use function Awesomemotive\Rewardswp\Helpers\format_currency;
use function Awesomemotive\Rewardswp\Helpers\get_option_value;
use function Awesomemotive\Rewardswp\Helpers\get_reward;
use function Awesomemotive\Rewardswp\Helpers\get_reward_display_title_from_values;
use function Awesomemotive\Rewardswp\Helpers\get_user_full_name;
use Awesomemotive\Rewardswp\Services\BirthdayService;
use Awesomemotive\Rewardswp\Services\PointsService;
use Awesomemotive\Rewardswp\Services\ReferralsService;
use Awesomemotive\Rewardswp\Views\Admin\Components\ToastView;
use function Awesomemotive\Rewardswp\Helpers\svg_kses;
use function Awesomemotive\Rewardswp\Helpers\get_points_currency_plural;
use function Awesomemotive\Rewardswp\Helpers\get_relative_date_label;

class MemberDetailView extends AbstractView implements ViewInterface {

	/**
	 * Items per page for activity tabs.
	 *
	 * @var int The number of items to be displayed for each activity tab.
	 */
	const ACTIVITY_ITEMS_PER_PAGE = 10;

	/**
	 * Icon helper instance.
	 *
	 * @var IconHelper
	 */
	private IconHelper $icon_helper;

	/**
	 * Points service instance.
	 *
	 * @var PointsService
	 */
	private PointsService $points_service;

	/**
	 * Referrals service instance.
	 *
	 * @var ReferralsService
	 */
	private ReferralsService $referrals_service;

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

	/**
	 * Birthday service instance.
	 *
	 * @var BirthdayService
	 */
	private BirthdayService $birthday_service;

	public function __construct(
		IconHelper $icon_helper,
		PointsService $points_service,
		ReferralsService $referrals_service,
		ViewsFactory $views_factory,
		BirthdayService $birthday_service
	) {
		$this->icon_helper       = $icon_helper;
		$this->points_service    = $points_service;
		$this->referrals_service = $referrals_service;
		$this->views_factory     = $views_factory;
		$this->birthday_service  = $birthday_service;
	}

	/**
	 * Render the member detail page.
	 *
	 * @since 1.0.0
	 *
	 * @param array $args {
	 *     Required. An array of arguments.
	 *
	 *     @type Member $member The Member object.
	 *     @type array  $member_data Pre-fetched/formatted data for display.
	 * }
	 *
	 * @return void
	 */
	public function render( array $args = [] ): void {
		if ( ! isset( $args['member'] ) || ! $args['member'] instanceof Member ) {
			wp_die( esc_html__( 'Error: Member data not provided.', 'rewardswp' ) );
		}

		/**
		 * Member instance.
		 *
		 * @var Member $member
		 */
		$member      = $args['member'];
		$member_data = $args['member_data'] ?? [];

		$adjust_points_nonce = wp_create_nonce( 'rewardswp_adjust_points_nonce_' . $member->id );
		// Nonce for the update referral code modal
		$update_referral_code_nonce = wp_create_nonce( 'rewardswp_update_referral_code_nonce_' . $member->id );
		// Nonce for the edit member modal
		$edit_member_nonce = wp_create_nonce( 'rewardswp_edit_member_nonce_' . $member->id );
		// Nonce for updating member status (exclude/include)
		$update_status_nonce = wp_create_nonce( 'rewardswp_update_member_status_nonce_' . $member->id );
		// Nonce for deleting a member
		$delete_member_nonce = wp_create_nonce( 'rewardswp_delete_member_nonce_' . $member->id );

		// Determine if programs are enabled
		$points_enabled    = (bool) get_option_value( PointsEnabledOption::class );
		$referrals_enabled = (bool) get_option_value( ReferralsEnabledOption::class );

		// Prepare some additional data for the UI.
		$points_balance  = $member_data['points']['available'] ?? 0;
		$lifetime_points = $member_data['points']['lifetime'] ?? 0;
		$spent_points    = $member_data['points']['spent'] ?? 0;
		$redeemed_points = $member_data['points']['redeemed'] ?? 0;
		$pending_points  = $member_data['points']['pending'] ?? 0;

		// Prepare referrals data - show em dash for successful count when no referrals, but keep actual amounts.
		$has_referrals = ( $member_data['referrals']['completed'] ?? 0 ) > 0;

		$referrals_revenue   = $member_data['referrals']['revenue_display'] ?? format_currency( 0 );
		$referrals_completed = $member_data['referrals']['completed'] ?? 0;
		$referrals_pending   = $member_data['referrals']['pending'] ?? 0;
		$referrals_claimed   = $member_data['referrals']['claimed'] ?? 0;

		// Initial points activity for Alpine
		$initial_points_activity = [];
		if ( $points_enabled ) {
			$initial_points_activity = array_map(
				function ( $point_entry ) {
					$points_value = absint( $point_entry->points );
					$is_deduction = in_array( $point_entry->type, [ 'spent', 'remove', 'expired' ], true ) || 'points_expiration' === $point_entry->source_type;
					$delta_val    = $is_deduction ? -$points_value : $points_value;
					$source_type  = $point_entry->source_type;
					$source_id    = $point_entry->source_id;

					$action_label = '';
					$target_label = '';
					$target_link  = '';

					// Determine labels based on source type.
					switch ( $source_type ) {
						case 'purchase':
							// Points earned for an order.
							$action_label = __( 'Earned', 'rewardswp' );
							if ( ! empty( $source_id ) ) {
								/* translators: %s: Order ID */
								$target_label = sprintf( __( 'Order #%s', 'rewardswp' ), $source_id );
								$target_link  = admin_url( 'post.php?post=' . $source_id . '&action=edit' );
							}
							break;

						case 'first_order':
							// First order bonus points.
							$action_label = __( 'Earned', 'rewardswp' );
							$target_label = __( 'First order bonus', 'rewardswp' );
							break;

						case 'reward_redemption':
							// Points redeemed for a reward.
							$action_label = __( 'Redeemed', 'rewardswp' );
							if ( ! empty( $source_id ) ) {
								$reward = get_reward( $source_id );
								if ( $reward ) {
									$target_label = get_reward_display_title_from_values(
										null,
										$reward->reward_type,
										(float) $reward->amount
									);
								}
							}
							break;

						case 'manual_adjustment':
							// Manual adjustment by admin.
							$action_label = __( 'Adjusted by Admin', 'rewardswp' );
							break;

						case 'referral':
						case 'referral_reward':
							// Points earned from referral.
							$action_label = __( 'Earned', 'rewardswp' );
							$target_label = __( 'Referral reward', 'rewardswp' );
							break;

						case 'refund':
							// Points deducted for a refunded order.
							$action_label = __( 'Refunded', 'rewardswp' );
							if ( ! empty( $source_id ) ) {
								/* translators: %s: Order ID */
								$target_label = sprintf( __( 'Order #%s', 'rewardswp' ), $source_id );
								$target_link  = admin_url( 'post.php?post=' . $source_id . '&action=edit' );
							}
							break;

						case 'partial_refund':
							// Points deducted for a partially refunded order.
							$action_label = __( 'Partially Refunded', 'rewardswp' );
							if ( ! empty( $source_id ) ) {
								/* translators: %s: Order ID */
								$target_label = sprintf( __( 'Order #%s', 'rewardswp' ), $source_id );
								$target_link  = admin_url( 'post.php?post=' . $source_id . '&action=edit' );
							}
							break;

						case 'points_expiration':
							// Points expired by the system cron.
							$action_label = __( 'Expired', 'rewardswp' );
							if ( ! empty( $point_entry->note_public ) ) {
								$target_label = $point_entry->note_public;
							}
							break;

						case 'birthday':
							$action_label = __( 'Earned', 'rewardswp' );
							$target_label = __( 'Birthday bonus', 'rewardswp' );
							break;

						default:
							// Fallback for other source types.
							$action_label = $is_deduction
								? __( 'Spent', 'rewardswp' )
								: __( 'Earned', 'rewardswp' );

							// Use note_public as target if available.
							if ( ! empty( $point_entry->note_public ) ) {
								$target_label = $point_entry->note_public;
							}
					}

					return [
						'id'                   => $point_entry->id,
						'type'                 => $point_entry->type,
						'source_type'          => $point_entry->source_type,
						'note_public'          => $point_entry->note_public ?: '',
						'note_internal'        => $point_entry->note_internal ?: '',
						'created_at_formatted' => get_date_from_gmt( $point_entry->created_at, 'F j, Y' ),
						'points_formatted'     => $point_entry->get_formatted_points() . ' pts',
						'created_at_raw'       => $point_entry->created_at,
						'delta'                => $delta_val,
						'action_label'         => $action_label,
						'target_label'         => $target_label,
						'target_link'          => $target_link,
						'status'               => $point_entry->status ?? 'approved',
						'date'                 => get_relative_date_label( $point_entry->created_at ),
					];
				},
				$this->points_service->get_points_entries(
					[
						'member_id' => $member->id,
						'orderby'   => 'created_at',
						'order'     => 'DESC',
					],
					self::ACTIVITY_ITEMS_PER_PAGE
				)
			);
		}

		// Initial referrals activity for Alpine referralsCard (sidebar).
		$initial_referrals_activity = [];
		if ( $referrals_enabled ) {
			$initial_referrals_activity = array_map(
				function ( $referral ) {
					$order_id   = $referral->order_id ?? null;
					$status     = $referral->status;
					$order_link = '';

					// Build status label and suffix.
					switch ( $status ) {
						case 'pending':
							$status_label = __( 'Pending', 'rewardswp' );
							if ( ! empty( $order_id ) ) {
								$order_link = $this->referrals_service->get_referred_order_link( $referral );
							}
							break;
						case 'completed':
							$status_label = __( 'Completed', 'rewardswp' );
							if ( ! empty( $order_id ) ) {
								$order_link = $this->referrals_service->get_referred_order_link( $referral );
							}
							break;
						case 'rejected':
						case 'blocked':
							$status_label = __( 'Blocked', 'rewardswp' );
							break;
						default:
							$status_label = ucfirst( $status );
					}

					// Build order label if there's an order.
					$order_label = '';
					if ( ! empty( $order_id ) ) {
						/* translators: %d is the order number */
						$order_label = sprintf( __( 'Order #%d', 'rewardswp' ), $order_id );
					}

					// Build suffix for referrals without orders.
					$suffix = '';
					if ( empty( $order_id ) ) {
						if ( ! empty( $referral->get_reward() ) || ! empty( $referral->referred_email ) ) {
							$suffix = __( 'Reward claimed · Awaiting purchase', 'rewardswp' );
						}
					}

					return [
						'id'          => $referral->id,
						'status'      => $status,
						'statusLabel' => $status_label,
						'orderLabel'  => $order_label,
						'orderLink'   => $order_link,
						'suffix'      => $suffix,
						'date'        => get_relative_date_label( $referral->created_at ),
					];
				},
				get_referrals(
					[
						'advocate_id' => $member->id,
						'orderby'     => 'created_at',
						'order'       => 'DESC',
					],
					self::ACTIVITY_ITEMS_PER_PAGE
				)
			);
		}

		// Determine initial active tab for activity section
		$initial_active_tab = 'rewards';
		if ( $points_enabled ) {
			$initial_active_tab = 'points';
		} elseif ( $referrals_enabled ) {
			$initial_active_tab = 'referrals';
		}

		// Parse birthday for Alpine data.
		$birthday_raw       = $member->get_meta( 'birthday' );
		$birthday_month_str = '';
		$birthday_day_str   = '';
		$birthday_display   = '';
		if ( ! empty( $birthday_raw ) ) {
			$parts = explode( '-', $birthday_raw );
			if ( count( $parts ) === 2 ) {
				$birthday_month_str = (string) (int) $parts[0];
				$birthday_day_str   = (string) (int) $parts[1];
			}
			$birthday_display = $this->birthday_service->format_birthday_for_display( $birthday_raw );
		}

		$alpine_data_params = [
			'memberId'               => $member->id,
			'activityItemsPerPage'   => self::ACTIVITY_ITEMS_PER_PAGE,
			'ajaxurl'                => admin_url( 'admin-ajax.php' ),
			'editMemberNonce'        => $edit_member_nonce,
			'initialFullName'        => trim( $member->get_full_name() ),
			'initialEmail'           => $member->email,
			'initialGravatarUrl'     => $member_data['gravatar_url_large'] ?? '',
			'initialMemberStatus'    => $member->status,
			'initialMemberTypeHtml'  => $member_data['member_type_html'] ?? '',
			'updateStatusNonce'      => $update_status_nonce,
			'deleteMemberNonce'      => $delete_member_nonce,
			'initialActiveTab'       => $initial_active_tab,
			'initialBirthdayMonth'   => $birthday_month_str,
			'initialBirthdayDay'     => $birthday_day_str,
			'initialBirthdayDisplay' => $birthday_display,
		];

		if ( $points_enabled ) {
			$alpine_data_params['adjustPointsNonce']         = $adjust_points_nonce;
			$alpine_data_params['initialPointsBalance']      = $points_balance;
			$alpine_data_params['initialLifetimePoints']     = $lifetime_points;
			$alpine_data_params['initialSpentPoints']        = $spent_points;
			$alpine_data_params['initialRedeemedPoints']     = $redeemed_points;
			$alpine_data_params['initialPointsActivityJson'] = wp_json_encode( $initial_points_activity );
		}

		if ( $referrals_enabled ) {
			$alpine_data_params['initialReferralCode']     = $member->referral_code;
			$alpine_data_params['referralLinkBase']        = get_referral_link_base_url();
			$alpine_data_params['updateReferralCodeNonce'] = $update_referral_code_nonce;
		}

		?>
		<div
			class="rewardswp-container max-[782px]:ml-[-10px] ml-[-20px]"
			x-data="memberDetailView(<?php echo esc_attr( wp_json_encode( $alpine_data_params ) ); ?>)"
		>

			<?php
			/**
			 * Sticky member detail header.
			 */
			?>
			<div id="rewardswp-sticky-sentinel"></div>
			<div id="rewardswp-member-detail-view-header" class="transition-shadow duration-250 shadow-gray-800/5 sticky max-[601px]:top-0 max-[783px]:top-[46px] top-[32px] bg-[#f0f0f1] z-10 border-b border-black/10 [.is-sticky]:bg-white [.is-sticky]:shadow-lg">

				<div class="px-8 py-3 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3">
					<div class="flex items-center gap-4 transition-transform duration-300 ease-in-out">
						<?php if ( ! empty( $member_data['gravatar_url_large'] ) ) : ?>
							<img :src="currentGravatarUrl"
								alt="<?php echo esc_attr( $member->get_full_name() ); ?>"
								class="size-10 rounded-full object-cover transition-size duration-300 ease-in-out">
						<?php endif; ?>

						<div class="transition-transform duration-300 ease-in-out flex">
							<div class="flex flex-col justify-center gap-0">
								<div class="flex gap-2 items-center">
									<template x-if="currentFullName">
										<h1 class="text-xl font-semibold text-gray-900 [.is-sticky_&]:flex-shrink-0" x-text="currentFullName"></h1>
									</template>
									<div>
										<?php // echo wp_kses_post( $member_data['member_type_html'] ?? '' ); ?>
										<span x-html="currentMemberTypeHtmlBadge"></span>
									</div>
								</div>
								<p class="text-sm text-gray-500 [.is-sticky_&]:hidden2 mt-0.5 transition-opacity duration-300 ease-in-out" x-text="currentEmail">
								</p>
							</div>
						</div>
					</div>

					<div class="flex gap-4 mt-4 sm:mt-0">

						<?php
						/**
						 * DEMO - Include member button.
						 * Use the text and icon for the Exclude member feature
						 */
						?>

						<?php
						/*
						<button
							type="button"
							class="inline-flex items-center gap-2 px-4 py-2 rounded-md text-sm font-medium hover:bg-gray-200 [.is-sticky_&]:hover:bg-gray-100 cursor-pointer focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
							<?php echo $this->icon_helper->get_icon( 'include-member', 'w-4 h-4' ); ?>
							<?php esc_html_e( 'Include in program', 'rewardswp' ); ?>
						</button>
						*/
						?>

						<button
							type="button"
							x-on:click="currentMemberStatus === 'active' ?
								window.dispatchEvent(new CustomEvent('open-exclude-member-modal', { detail: { memberId: memberId, memberName: currentFullName, nonce: updateStatusNonce } })) :
								includeMember()"
							class="inline-flex items-center gap-2 px-4 py-2 rounded-md text-sm font-medium hover:bg-gray-200 [.is-sticky_&]:hover:bg-gray-100 cursor-pointer focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
							<template x-if="currentMemberStatus === 'active'">
								<?php echo wp_kses( $this->icon_helper->get_icon( 'exclude-member', 'w-4 h-4' ), svg_kses() ); ?>
							</template>
							<template x-if="currentMemberStatus === 'excluded'">
								<?php echo wp_kses( $this->icon_helper->get_icon( 'include-member', 'w-4 h-4' ), svg_kses() ); ?>
							</template>
							<span x-text="currentMemberStatus === 'active' ? '<?php esc_html_e( 'Exclude from program', 'rewardswp' ); ?>' : '<?php esc_html_e( 'Include in program', 'rewardswp' ); ?>'"></span>
						</button>

						<?php
						/**
						 * Actions menu.
						 */
						?>
						<div x-data="{ open: false }" class="relative inline-block">

							<button
								type="button"
								x-on:click="open = !open; $nextTick(() => $refs.menu?.focus())"
								x-on:keydown.arrow-down.prevent="open = true; $nextTick(() => $refs.menu?.focus())"
								x-bind:aria-expanded="open"
								aria-haspopup="menu"
								class="inline-flex cursor-pointer items-center gap-2 px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
								title="<?php esc_attr_e( 'More Actions', 'rewardswp' ); ?>">
								<?php echo wp_kses( $this->icon_helper->get_icon( 'menu-kebab', 'w-3 h-3', 'bold' ), svg_kses() ); ?>
								<?php esc_html_e( 'Actions', 'rewardswp' ); ?>
							</button>

							<?php
							/**
							 * Dropdown menu.
							 */
							?>
							<div
								x-show="open"
								x-cloak
								x-ref="menu"
								x-on:keydown.escape.window="open = false; $refs.trigger?.focus()"
								x-on:click.outside="open = false"
								tabindex="-1"
								role="menu"
								class="absolute right-0 z-50 mt-1 w-48 origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black/10 focus-visible:outline-none"
								x-transition:enter="transition ease-out duration-100"
								x-transition:enter-start="opacity-0 scale-95"
								x-transition:enter-end="opacity-100 scale-100"
								x-transition:leave="transition ease-in duration-75"
								x-transition:leave-start="opacity-100 scale-100"
								x-transition:leave-end="opacity-0 scale-95"
							>

								<?php
								/**
								 * Adjust points.
								 */
								?>
								<?php if ( $points_enabled ) : ?>
								<button
									type="button"
									class="cursor-pointer group w-full items-center text-sm text-left text-gray-700 p-1 focus:outline-none"
									role="menuitem"
									x-on:click.stop="window.dispatchEvent(new CustomEvent('open-adjust-points-modal', { detail: { memberId: memberId, memberName: currentFullName, currentBalance: currentPointsBalance, nonce: adjustPointsNonce } }))"
								>
								<span class="px-4 py-2 block rounded-md group-hover:bg-gray-100 group-focus:bg-gray-100">
									<?php esc_html_e( 'Adjust points', 'rewardswp' ); ?>
								</span>
								</button>
								<?php endif; ?>

								<?php
								/**
								 * Change referral link.
								 */
								?>
																<?php if ( $referrals_enabled ) : ?>
								<button
									type="button"
									class="cursor-pointer group w-full items-center text-sm text-left text-gray-700 p-1 focus:outline-none"
									role="menuitem"
									x-on:click="window.dispatchEvent(new CustomEvent('open-update-referral-code-modal', { detail: { memberId: memberId, currentReferralCode: currentReferralCode, nonce: updateReferralCodeNonce } }))"
								>
								<span class="px-4 py-2 block rounded-md group-hover:bg-gray-100 group-focus:bg-gray-100">
																	<?php esc_html_e( 'Change referral link', 'rewardswp' ); ?>
								</span>
								</button>
								<?php endif; ?>

								<?php
								/**
								 * Edit Member.
								 */
								?>
								<button
									type="button"
									class="cursor-pointer group w-full items-center text-sm text-left text-gray-700 p-1 focus:outline-none"
									role="menuitem"
									x-on:click="window.dispatchEvent(new CustomEvent('open-edit-member-modal', { detail: { memberId: memberId, nonce: editMemberNonce, fullName: currentFullName, email: currentEmail, birthdayMonth: currentBirthdayMonth, birthdayDay: currentBirthdayDay } }))"
								>
								<span class="px-4 py-2 block rounded-md group-hover:bg-gray-100 group-focus:bg-gray-100">
								<?php esc_html_e( 'Edit member', 'rewardswp' ); ?>
								</span>
								</button>

								<div class="border-t border-gray-200"></div>

								<?php
								/**
								 * Delete member.
								 */
								?>
								<button
									type="button"
									class="cursor-pointer group w-full items-center text-sm text-left text-red-600 p-1 focus:outline-none"
									role="menuitem"
									x-on:click="window.dispatchEvent(new CustomEvent('open-delete-member-modal', { detail: { memberId: memberId, nonce: deleteMemberNonce } }))"
								>
								<span class="px-4 py-2 block rounded-md group-hover:bg-gray-100 group-focus:bg-gray-100">
								<?php esc_html_e( 'Delete member', 'rewardswp' ); ?>
								</span>
								</button>

							</div>
						</div>


					</div>
				</div>

			</div>

			<?php
			/**
			 * Main section.
			 */
			?>
			<div class="px-8">

				<?php
				/**
				 * Quick-stats.
				 */
				?>
				<div class="bg-white rounded-lg mt-6">
					<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4">
						<?php if ( $points_enabled ) : ?>
						<div class="text-center sm:text-left px-6 py-8 border-b border-gray-200 sm:border-b-0">
							<div class="text-sm font-medium text-gray-600 tracking-wide uppercase">
								<?php
								/* translators: %s: Points currency name plural (e.g. "Points", "Coins"). */
								printf( esc_html__( '%s Available', 'rewardswp' ), esc_html( get_points_currency_plural() ) );
								?>
							</div>
							<div class="text-3xl font-bold text-gray-800 tabular-nums" x-text="currentPointsBalance.toLocaleString()"></div>
							<div class="mt-1 text-sm text-gray-500">
								<?php if ( $pending_points > 0 ) : ?>
									<?php
									printf(
										/* translators: %s: Formatted number of pending points. */
										esc_html( _n( '%s pending', '%s pending', $pending_points, 'rewardswp' ) ),
										esc_html( number_format_i18n( $pending_points ) )
									);
									?>
								<?php elseif ( $points_balance > 0 ) : ?>
									<?php esc_html_e( 'Ready to redeem', 'rewardswp' ); ?>
								<?php else : ?>
									<?php esc_html_e( 'No activity yet', 'rewardswp' ); ?>
								<?php endif; ?>
							</div>
						</div>
						<?php endif; ?>

						<div class="text-center sm:text-left px-6 py-8 border-b sm:border-b-0 sm:border-l border-gray-200">
							<div class="text-sm font-medium text-gray-600 tracking-wide uppercase"><?php esc_html_e( 'Lifetime Spend', 'rewardswp' ); ?></div>
							<div class="text-3xl font-bold text-gray-800 tabular-nums"><?php echo esc_html( format_currency( $member_data['orders']['total_spend'] ?? 0 ) ); ?></div>
							<div class="mt-1 text-sm text-gray-500">
								<?php if ( ( $member_data['orders']['order_count'] ?? 0 ) > 0 ) : ?>
									<?php
									/* translators: %d: Number of orders. */
									$order_phrase = _n(
										'%d order',
										'%d orders',
										$member_data['orders']['order_count'],
										'rewardswp'
									);

									echo esc_html(
										sprintf(
											$order_phrase,
											$member_data['orders']['order_count']
										)
									);
									?>
								<?php else : ?>
									<?php esc_html_e( 'No orders yet', 'rewardswp' ); ?>
								<?php endif; ?>
							</div>
						</div>

						<?php if ( $referrals_enabled ) : ?>
						<div class="text-center sm:text-left px-6 py-8 border-b sm:border-b-0 sm:border-l border-gray-200">
							<div class="text-sm font-medium text-gray-600 tracking-wide uppercase"><?php esc_html_e( 'Completed Referrals', 'rewardswp' ); ?></div>
							<div class="text-3xl font-bold tabular-nums text-gray-800">
								<?php if ( $has_referrals ) : ?>
									<?php echo esc_html( $referrals_completed ); ?>
								<?php else : ?>
									<span class="inline-block leading-none -mt-[2px] font-normal">—</span>
								<?php endif; ?>
							</div>
							<div class="mt-1 text-sm text-gray-500">
								<?php
								/* translators: %d: Number of pending referrals. */
								$pending_phrase = _n(
									'%d pending',
									'%d pending',
									$referrals_pending,
									'rewardswp'
								);

								echo esc_html(
									sprintf(
										$pending_phrase,
										$referrals_pending
									)
								);
								?>
							</div>
						</div>

						<div class="text-center sm:text-left px-6 py-8 sm:border-l border-gray-200">
							<div class="text-sm font-medium text-gray-600 tracking-wide uppercase"><?php esc_html_e( 'Referral Revenue', 'rewardswp' ); ?></div>
							<div class="text-3xl font-bold text-gray-800 tabular-nums"><?php echo esc_html( $referrals_revenue ); ?></div>
							<div class="mt-1 text-sm text-gray-500">
								<?php if ( $has_referrals ) : ?>
									<?php echo esc_html( $member_data['referrals']['conversion_rate'] ?? '0.0%' ) . ' ' . esc_html__( 'conversion', 'rewardswp' ); ?>
								<?php else : ?>
									<?php esc_html_e( '(lifetime)', 'rewardswp' ); ?>
								<?php endif; ?>
							</div>
						</div>
						<?php endif; ?>
					</div>
				</div>

				<div class="mt-8 grid grid-cols-1 lg:grid-cols-3 gap-8">
					<!-- Left Column (Main Content) -->
					<div class="lg:col-span-2 space-y-6">
						<!-- Member Information Card -->
						<div class="bg-white rounded-lg">
							<div class="px-4 py-5 sm:px-6 flex justify-between items-center border-b border-gray-200">
								<h3 class="text-lg leading-6 font-medium text-gray-900"><?php esc_html_e( 'Member Information', 'rewardswp' ); ?></h3>
								<button
									type="button"
									class="inline-flex items-center gap-2 px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 cursor-pointer"
									x-on:click="window.dispatchEvent(new CustomEvent('open-edit-member-modal', { detail: { memberId: memberId, nonce: editMemberNonce, fullName: currentFullName, email: currentEmail, birthdayMonth: currentBirthdayMonth, birthdayDay: currentBirthdayDay } }))"
									>
									<?php esc_html_e( 'Edit', 'rewardswp' ); ?>
								</button>

							</div>
							<div class="px-4 py-5 sm:p-6">
								<dl>
									<div class="py-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 border-b border-gray-200">
										<dt class="text-sm font-medium text-gray-500"><?php esc_html_e( 'First Seen', 'rewardswp' ); ?></dt>
										<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2"><?php echo esc_html( $member_data['activity']['first_seen_display'] ); ?></dd>
									</div>
									<div class="py-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 border-b border-gray-200">
										<dt class="text-sm font-medium text-gray-500"><?php esc_html_e( 'Last Seen', 'rewardswp' ); ?></dt>
										<dd class="mt-1 text-sm sm:mt-0 sm:col-span-2 <?php echo empty( $member_data['activity']['last_seen'] ) ? 'text-gray-400' : 'text-gray-900'; ?>"><?php echo esc_html( $member_data['activity']['last_seen_display'] ); ?></dd>
									</div>
									<div class="py-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 border-b border-gray-200">
										<dt class="text-sm font-medium text-gray-500"><?php esc_html_e( 'Last Order', 'rewardswp' ); ?></dt>
										<dd class="mt-1 text-sm sm:mt-0 sm:col-span-2 <?php echo empty( $member_data['orders']['last_order_date'] ) ? 'text-gray-400' : 'text-gray-900'; ?>"><?php echo esc_html( $member_data['orders']['last_order_display'] ); ?></dd>
									</div>
									<div class="py-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 border-b border-gray-200">
										<dt class="text-sm font-medium text-gray-500"><?php esc_html_e( 'Referred By', 'rewardswp' ); ?></dt>
										<?php
										$referred_by_none = esc_html__( 'None', 'rewardswp' );
										$referred_by      = $member_data['referred_by_display'] ?? $referred_by_none;
										$referred_class   = ( $referred_by === $referred_by_none ) ? 'text-gray-400' : 'text-gray-900';
										?>
										<dd class="mt-1 text-sm sm:mt-0 sm:col-span-2 <?php echo esc_attr( $referred_class ); ?>"><?php echo esc_html( $referred_by ); ?></dd>
									</div>
									<div class="py-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4">
										<dt class="text-sm font-medium text-gray-500"><?php esc_html_e( 'Birthday', 'rewardswp' ); ?></dt>
										<dd class="mt-1 text-sm sm:mt-0 sm:col-span-2">
											<span x-show="currentBirthdayDisplay" x-text="currentBirthdayDisplay" class="text-gray-900"></span>
											<span x-cloak x-show="!currentBirthdayDisplay" class="text-gray-400"><?php esc_html_e( 'Not set', 'rewardswp' ); ?></span>
										</dd>
									</div>
								</dl>
							</div>
						</div>

						<!-- Activity Section with Tabs -->
						<?php if ( $points_enabled || $referrals_enabled ) : ?>
						<div id="activity"
							x-data="{
								activeTab: '<?php echo esc_attr( $initial_active_tab ); ?>',
								highlighted: false,
								init() {
									const hash = window.location.hash;
									if (hash.startsWith('#activity-')) {
										const tab = hash.replace('#activity-', '');
										if (['points', 'referrals', 'rewards'].includes(tab)) {
											this.activeTab = tab;
											this.$nextTick(() => {
												this.$el.scrollIntoView({ behavior: 'smooth', block: 'start' });
											});
										}
									}
								}
							}"
							x-on:show-activity.window="
								activeTab = $event.detail.tab;
								$el.scrollIntoView({ behavior: 'smooth', block: 'start' });
								highlighted = true;
								setTimeout(() => highlighted = false, 1500);
							"
							x-bind:class="{ 'ring-2 ring-blue-500 ring-offset-2': highlighted }"
							class="bg-white rounded-lg transition-all duration-300">
							<div class="px-4 py-5 sm:px-6 flex justify-between items-center">
								<h3 class="text-lg leading-6 font-medium text-gray-900"><?php esc_html_e( 'Activity', 'rewardswp' ); ?></h3>
							</div>
							<div>
								<div class="border-b border-gray-200">
									<nav class="-mb-px flex space-x-8 px-6" aria-label="<?php esc_attr_e( 'Tabs', 'rewardswp' ); ?>">
										<?php if ( $points_enabled ) : ?>
										<button
											x-on:click="activeTab = 'points'; history.pushState(null, '', '#activity-points')"
											x-bind:class="{ 'border-blue-500 text-blue-600': activeTab === 'points', 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300': activeTab !== 'points' }"
											class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm cursor-pointer"
										>
											<?php esc_html_e( 'Points', 'rewardswp' ); ?>
										</button>
										<?php endif; ?>
										<?php if ( $referrals_enabled ) : ?>
										<button
											x-on:click="activeTab = 'referrals'; history.pushState(null, '', '#activity-referrals')"
											x-bind:class="{ 'border-blue-500 text-blue-600': activeTab === 'referrals', 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300': activeTab !== 'referrals' }"
											class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm cursor-pointer"
										>
											<?php esc_html_e( 'Referrals', 'rewardswp' ); ?>
										</button>
										<?php endif; ?>
										<button
											x-on:click="activeTab = 'rewards'; history.pushState(null, '', '#activity-rewards')"
											x-bind:class="{ 'border-blue-500 text-blue-600': activeTab === 'rewards', 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300': activeTab !== 'rewards' }"
											class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm cursor-pointer"
										>
											<?php esc_html_e( 'Rewards', 'rewardswp' ); ?>
										</button>
									</nav>
								</div>

								<div class="px-4 py-5 sm:p-6">
									<?php if ( $points_enabled ) : ?>
									<div x-show="activeTab === 'points'" x-cloak>
										<?php $this->render_points_activity( $member ); ?>
									</div>
									<?php endif; ?>
									<?php if ( $referrals_enabled ) : ?>
									<div x-show="activeTab === 'referrals'" x-cloak>
										<?php $this->render_referrals_activity( $member ); ?>
									</div>
									<?php endif; ?>
									<div x-show="activeTab === 'rewards'" x-cloak>
										<?php $this->render_rewards_activity( $member ); ?>
									</div>
								</div>
							</div>
						</div>
						<?php endif; // End of condition for rendering Activity section ?>
					</div>

					<!-- Right Column (Sidebar) -->
					<div class="lg:col-span-1 space-y-6">

						<?php if ( $points_enabled ) : ?>
						<div x-data="pointsCard" class="bg-white rounded-lg">

							<!-- Header -->
							<div class="px-4 py-5 sm:px-6 flex justify-between items-baseline">
							<h3 class="text-lg leading-6 font-medium text-gray-900">
								<?php esc_html_e( 'Points', 'rewardswp' ); ?>
							</h3>

							<button
								type="button"
								class="cursor-pointer inline-flex items-center gap-2 px-4 py-2 border border-gray-300 rounded-md shadow-sm
									text-sm font-medium text-gray-700 bg-white hover:bg-gray-50
									focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-brand-600"
								x-on:click.stop="window.dispatchEvent(new CustomEvent('open-adjust-points-modal', { detail: { memberId: memberId, memberName: currentFullName, currentBalance: currentPointsBalance, nonce: adjustPointsNonce } }))"
								title="<?php esc_html_e( 'Adjust Points', 'rewardswp' ); ?>"
							>
								<?php esc_html_e( 'Adjust', 'rewardswp' ); ?>
							</button>
							</div>

							<!-- Body -->
							<div class="px-4 pb-5 sm:p-6 sm:pt-0">

								<!-- Recent activity (handles empty state) -->
								<template x-if="recentEvents.length">

									<div class="rounded-lg bg-gray-50 p-8 text-center">

										<!-- Balance -->
										<p class="leading-tight text-4xl sm:text-5xl font-bold text-gray-800 break-words" x-text="balance.toLocaleString()"></p>
										<p class="text-sm text-gray-500">
											<?php
											/* translators: %s: Points currency name plural (e.g. "Points", "Coins"). */
											printf( esc_html__( '%s available', 'rewardswp' ), esc_html( get_points_currency_plural() ) );
											?>
										</p>
										<template x-if="pending > 0">
											<p class="text-sm text-gray-400 mt-0.5"
											   x-text="pending.toLocaleString() + ' pending'"></p>
										</template>

										<!-- Stats -->
										<dl class="grid grid-cols-2 gap-x-8 gap-y-4 mt-6 mx-auto">
											<template x-for="stat in visibleStats" x-bind:key="stat.label">
												<div>
													<dt class="text-xs font-medium uppercase tracking-wider text-gray-500"
														x-text="stat.label"></dt>
													<dd class="text-lg font-semibold text-gray-900" x-text="stat.value"></dd>
												</div>
											</template>
										</dl>

										<div>
											<div class="border-t border-gray-200 w-3/4 mx-auto mt-8"></div>
											<div class="mt-6 text-left">

											<h4 class="text-xs font-medium text-gray-500 mb-2">
												<?php esc_html_e( 'Recent activity', 'rewardswp' ); ?>
											</h4>

											<!-- shared grid for alignment -->
											<div class="grid grid-cols-[max-content_1fr_max-content] gap-x-3 gap-y-1 items-baseline text-sm">
												<template x-for="e in recentEvents.slice(0, rowsToShow)" x-bind:key="e.id">
													<div class="contents">
														<span class="tabular-nums pr-1 text-right"
															x-bind:class="e.source_type === 'points_expiration' ? 'text-gray-500 line-through' : (e.status === 'pending' ? 'text-gray-500' : (e.delta>0 ? 'text-green-600' : 'text-red-600'))"
															x-text="e.delta>0 ? '+'+e.delta.toLocaleString() : e.delta.toLocaleString()"></span>

														<span class="truncate">
														<span x-text="e.action_label"></span>
														<template x-if="e.target_label">
															<span>
																<span class="text-gray-400"> · </span>
																<template x-if="e.target_link">
																	<a x-bind:href="e.target_link" class="hover:underline" x-text="e.target_label"></a>
																</template>
																<template x-if="!e.target_link">
																	<span x-text="e.target_label"></span>
																</template>
															</span>
														</template>
													</span>

														<span class="text-gray-400 text-right flex-shrink-0" x-text="e.date"></span>
													</div>
												</template>
											</div>

											<div class="mt-8 text-center">
												<a href="#activity-points"
													class="text-sm text-brand-600 hover:underline"
													x-on:click.prevent="
														$dispatch('show-activity', { tab: 'points' });
														history.pushState(null, '', '#activity-points');
													">
													<?php esc_html_e( 'View all activity →', 'rewardswp' ); ?>
												</a>
											</div>
											</div>
										</div>
									</div>
								</template>

								<template x-if="!recentEvents.length">
									<div class="rounded-lg bg-gray-50 p-4 text-center">
										<div class="inline-flex items-center gap-2 text-sm text-gray-500">
											<?php echo wp_kses( $this->icon_helper->get_icon( 'info', 'w-5 h-5 shrink-0 text-neutral-600' ), svg_kses() ); ?>
											<span><?php esc_html_e( 'No points activity recorded yet.', 'rewardswp' ); ?></span>
										</div>
									</div>
								</template>

							</div>
						</div>

						<!-- ▸ Alpine component ---------------------------------------------------->
						<script>
						document.addEventListener('alpine:init', () => {
							Alpine.data('pointsCard', () => ({

							/* ─── sample data (replace with real) ─── */
							balance:   <?php echo esc_js( $points_balance ); ?>,
			lifetime:  <?php echo esc_js( $lifetime_points ); ?>,
			spent:     <?php echo esc_js( $spent_points ); ?>,
			redeemed:  <?php echo esc_js( $redeemed_points ); ?>,
			pending:   <?php echo esc_js( $pending_points ); ?>,

			recentEvents: <?php echo wp_json_encode( array_slice( $initial_points_activity, 0, 3 ) ); ?>,
			/* ────────────────────────────────────── */

			get rowsToShow() { return window.innerWidth < 640 ? 1 : 3 },

							get visibleStats() {
								const stats = [];
								if (this.lifetime > 0) {
									stats.push({ label: 'Lifetime Earned', value: this.lifetime.toLocaleString() });
									stats.push({ label: 'Lifetime Redeemed', value: this.redeemed > 0 ? this.redeemed.toLocaleString() : '—' });
								}
								return stats;
							},

			init() {
				window.addEventListener('rewardswp-points-adjusted', (event) => {
					this.balance = event.detail.new_balance;
					this.lifetime = event.detail.new_lifetime_points;
					this.spent = event.detail.new_spent_points;
					this.redeemed = event.detail.new_redeemed_points;

					if (event.detail.new_entry) {
						this.recentEvents.unshift(event.detail.new_entry);
						if (this.recentEvents.length > 3) {
							this.recentEvents.pop();
						}
					}
				});
			}
							}));
						});
						</script>
						<?php endif; ?>

						<!-- ▸ Referrals card -->
						<?php if ( $referrals_enabled ) : ?>
						<div x-data="referralsCard" class="bg-white rounded-lg">

							<!-- Header -->
							<div class="px-4 py-5 sm:px-6 flex justify-between items-baseline">
								<h3 class="text-lg leading-6 font-medium text-gray-900">
									<?php esc_html_e( 'Referrals', 'rewardswp' ); ?>
								</h3>

								<button
									type="button"
									class="cursor-pointer inline-flex items-center gap-2 px-4 py-2 border border-gray-300 rounded-md shadow-sm
											text-sm font-medium text-gray-700 bg-white hover:bg-gray-50
											focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-brand-600"
									x-on:click.stop="window.dispatchEvent(new CustomEvent('open-update-referral-code-modal', { detail: { memberId: memberId, currentReferralCode: currentReferralCode, nonce: updateReferralCodeNonce } }))"
									title="<?php esc_html_e( 'Change Referral Link', 'rewardswp' ); ?>"
								>
									<?php esc_html_e( 'Change Link', 'rewardswp' ); ?>
								</button>
							</div>

							<!-- Body -->
							<div class="px-4 pb-5 sm:p-6 sm:pt-0">


								<template x-if="recentReferrals.length">
									<div class="rounded-lg bg-gray-50 p-8 text-center">
										<div>
											<!-- Hero stat -->
											<p class="leading-tight text-4xl sm:text-5xl font-bold text-gray-800 break-words"
												x-text="revenue"></p>
											<p class="text-sm text-gray-500"><?php esc_html_e( 'Referral revenue (lifetime)', 'rewardswp' ); ?></p>

											<!-- Successful / Pending strip -->
											<dl class="grid grid-cols-2 gap-x-8 gap-y-4 mt-6 mx-auto max-w-[280px]">
												<template x-for="stat in visibleStats" x-bind:key="stat.label">
													<div>
														<dt class="text-xs font-medium uppercase tracking-wider text-gray-500"
															x-text="stat.label"></dt>
														<dd class="text-lg font-semibold text-gray-900" x-text="stat.value"></dd>
													</div>
												</template>
											</dl>

											<!-- Recent activity  ------------------------------------->
											<div class="border-t border-gray-200 w-3/4 mx-auto mt-8"></div>

											<div class="mt-6 text-left">
												<h4 class="text-xs font-medium text-gray-500 mb-2">
													<?php esc_html_e( 'Recent activity', 'rewardswp' ); ?>
												</h4>

												<div class="grid grid-cols-[max-content_1fr_max-content] gap-x-3 gap-y-1 items-baseline text-sm">
													<template x-for="r in recentReferrals.slice(0, rowsToShow)" x-bind:key="r.id">
														<div class="contents">
															<span class="text-gray-700" x-text="r.statusLabel"></span>
															<span class="text-gray-700 truncate">
																<template x-if="r.orderLabel">
																	<span>
																		<template x-if="r.orderLink">
																			<a x-bind:href="r.orderLink" class="hover:underline" x-text="r.orderLabel"></a>
																		</template>
																		<template x-if="!r.orderLink">
																			<span x-text="r.orderLabel"></span>
																		</template>
																	</span>
																</template>
																<template x-if="r.suffix">
																	<span x-text="r.suffix"></span>
																</template>
															</span>
															<span class="text-gray-400 text-right shrink-0" x-text="r.date"></span>
														</div>
													</template>
												</div>

												<div class="mt-8 text-center">
													<a href="#activity-referrals"
														class="text-sm text-brand-600 hover:underline"
														x-on:click.prevent="
															$dispatch('show-activity', { tab: 'referrals' });
															history.pushState(null, '', '#activity-referrals');
														">
														<?php esc_html_e( 'View all activity →', 'rewardswp' ); ?>
													</a>
												</div>
											</div>
										</div>
									</div>
								</template>

								<template x-if="!recentReferrals.length">
									<div class="rounded-lg bg-gray-50 p-4 text-center">
										<div class="inline-flex items-center gap-2 text-sm text-gray-500">
											<?php echo wp_kses( $this->icon_helper->get_icon( 'info', 'w-5 h-5 shrink-0 text-neutral-600' ), svg_kses() ); ?>
											<span><?php esc_html_e( 'No referral activity recorded yet.', 'rewardswp' ); ?></span>
										</div>
									</div>
								</template>





								<div class="mt-6">
									<label for="referral-link-input-2" class="sr-only block text-sm/6 font-medium text-gray-900"><?php esc_html_e( 'Referral Link', 'rewardswp' ); ?></label>

									<div class="mt-2">
										<div class="flex rounded-md bg-white outline-1 -outline-offset-1 outline-gray-200">
											<input
												type="text"
												readonly
												name=""
												class="block min-w-0 grow px-5 py-3 text-base text-gray-900 focus:outline-none sm:text-base/6 text-ellipsis"
												id="referral-link-input-2"
												x-ref="referralLinkInput2"
												x-bind:value="referralLinkBase + currentReferralCode"
												x-on:focus="$event.target.select()"
											>
											<div class="flex py-3 pr-5">
												<button
													id="copy-link-2"
													x-on:click="isCopying = true; copyToClipboard(referralLinkBase + currentReferralCode).then((success) => { if(success) { copied = true; setTimeout(() => copied = false, 1500) } }); setTimeout(() => isCopying = false, 300)"
													class="cursor-pointer text-gray-500 hover:text-blue-600 transition-all duration-200"
													x-data="{ copied: false, isCopying: false }"
													title="<?php esc_attr_e( 'Copy referral link', 'rewardswp' ); ?>"
													aria-label="<?php esc_attr_e( 'Copy referral link to clipboard', 'rewardswp' ); ?>"
												>
													<template x-if="!copied">
														<span aria-hidden="true" x-bind:class="{ 'text-blue-600': isCopying }">
															<?php echo wp_kses( $this->icon_helper->get_icon( 'copy', 'w-5 h-5' ), svg_kses() ); ?>
														</span>
													</template>
													<template x-if="copied">
														<span aria-hidden="true" x-bind:class="{ 'text-blue-600': isCopying || copied }">
															<?php echo wp_kses( $this->icon_helper->get_icon( 'copied', 'w-5 h-5' ), svg_kses() ); ?>
														</span>
													</template>
												</button>
											</div>
										</div>
									</div>
								</div>
							</div>
						</div>

						<!-- ▸ Alpine ----------------------------------------------------------->
						<script>
						document.addEventListener('alpine:init', () => {
							Alpine.data('referralsCard', () => ({

								revenue: '<?php echo esc_js( $referrals_revenue ); ?>',
								completed: <?php echo esc_js( $referrals_completed ); ?>,
								pending: <?php echo esc_js( $referrals_pending ); ?>,
								claimed: <?php echo esc_js( $referrals_claimed ); ?>,

								recentReferrals: <?php echo wp_json_encode( $initial_referrals_activity ); ?>,

								get rowsToShow() { return window.innerWidth < 640 ? 1 : 3 },

								get visibleStats() {
									const stats = [
										{ label: 'Completed', value: this.completed },
										{ label: 'Pending', value: this.pending }
									];
									if (this.claimed > 0) {
										stats.push({ label: 'Claimed', value: this.claimed });
									}
									return stats;
								},

					}));
				});
				</script>
				<?php endif; ?>
					</div>
				</div>

			</div>

			<?php
			// Render the adjust points modal using ViewsFactory
			if ( $points_enabled ) {
				$adjust_points_modal = $this->views_factory->get_view( AdjustPointsModalView::class );
				if ( is_subclass_of( $adjust_points_modal, ViewInterface::class ) ) {
					$adjust_points_modal->render(
						[
							'member_id'       => $member->id,
							'member_name'     => $member->get_full_name() ?: $member->email,
							'current_balance' => $member_data['points']['available'] ?? 0,
							'nonce'           => $adjust_points_nonce,
						]
					);
				}
			}

			// Render the update referral code modal
			if ( $referrals_enabled ) {
				$update_referral_code_modal = $this->views_factory->get_view( UpdateReferralCodeModalView::class );
				if ( is_subclass_of( $update_referral_code_modal, ViewInterface::class ) ) {
					$update_referral_code_modal->render(
						[
							'member_id'             => $member->id,
							'current_referral_code' => $member->referral_code,
							'nonce'                 => $update_referral_code_nonce,
						]
					);
				}
			}

			// Render the edit member modal
			$edit_member_modal = $this->views_factory->get_view( EditMemberModalView::class );
			if ( is_subclass_of( $edit_member_modal, ViewInterface::class ) ) {
				$edit_member_modal->render(
					[
						'member' => $member, // Pass the whole member object
						'nonce'  => $edit_member_nonce,
					]
				);
			}

			// Render the exclude member modal
			$exclude_member_modal = $this->views_factory->get_view( ExcludeMemberModalView::class );
			if ( is_subclass_of( $exclude_member_modal, ViewInterface::class ) ) {
				// Args for ExcludeMemberModalView are passed via the Alpine event from the Exclude button
				// So, we don't need to pass member_id, member_name, nonce here during initial render.
				$exclude_member_modal->render();
			}

			// Render the delete member modal
			$delete_member_modal = $this->views_factory->get_view( DeleteMemberModalView::class );
			if ( is_subclass_of( $delete_member_modal, ViewInterface::class ) ) {
				$delete_member_modal->render(); // Data passed via Alpine event
			}
			?>

		</div>
		<?php
	}

	/**
	 * Render the points activity section.
	 *
	 * @since 1.0.0
	 *
	 * @param Member $member The member object.
	 *
	 * @return void
	 */
	private function render_points_activity( Member $member ): void {
		// Note: Initial data is now passed to Alpine's pointsActivity via wp_json_encode
		// The rendering is handled by Alpine's x-for directive.
		?>
		<div x-show="!pointsActivity || pointsActivity.length === 0" class="text-center py-12">
			<div class="mx-auto flex items-center justify-center">
				<?php echo wp_kses( $this->icon_helper->get_icon( 'points-activity', 'size-10 text-gray-400' ), svg_kses() ); ?>
			</div>
			<h3 class="mt-2 text-sm font-medium text-gray-900"><?php esc_html_e( 'No Points Activity', 'rewardswp' ); ?></h3>
			<p class="mt-1 text-sm text-gray-400"><?php esc_html_e( 'This member has no points activity yet.', 'rewardswp' ); ?></p>
		</div>

		<div x-show="pointsActivity && pointsActivity.length > 0" x-cloak>
			<div id="points-rows" class="divide-y divide-gray-50" tabindex="-1" aria-live="polite" aria-label="<?php esc_attr_e( 'Points activity list', 'rewardswp' ); ?>">
				<template x-for="(point, index) in pointsActivity" x-bind:key="point.id || index">
					<div x-bind:id="'point-' + point.id" x-bind:class="{ 'first-row': index === 0 }" class="py-3 flex items-start gap-4 transition-all duration-300">
						<!-- Delta -->
						<span class="w-16 text-right tabular-nums font-medium shrink-0"
							x-bind:class="point.source_type === 'points_expiration' ? 'text-gray-500 line-through' : (point.status === 'pending' ? 'text-gray-500' : (point.delta > 0 ? 'text-green-600' : 'text-red-600'))"
							x-text="point.delta > 0 ? '+'+point.delta.toLocaleString() : point.delta.toLocaleString()">
						</span>

						<!-- Title & Meta -->
						<div class="flex-1 min-w-0">
							<div class="text-sm text-gray-900 flex items-center gap-2">
								<span>
									<span x-text="point.action_label"></span>
									<template x-if="point.target_label">
										<span>
											<span class="text-gray-400"> · </span>
											<template x-if="point.target_link">
												<a x-bind:href="point.target_link" class="hover:underline" x-text="point.target_label"></a>
											</template>
											<template x-if="!point.target_link">
												<span x-text="point.target_label"></span>
											</template>
										</span>
									</template>
								</span>
								<!-- Pending status -->
								<span x-show="point.status === 'pending'"
									class="inline-flex items-center rounded-md px-2 py-0.5 text-xs font-medium ring-1 ring-inset bg-yellow-50 text-yellow-700 ring-yellow-600/20 shrink-0">
									<?php esc_html_e( 'Points pending', 'rewardswp' ); ?>
								</span>
							</div>
							<!-- Internal note (muted subtext for manual adjustments) -->
							<template x-if="point.note_internal">
								<p class="text-sm text-gray-400 mt-0.5" x-text="point.note_internal"></p>
							</template>
						</div>

						<!-- Date -->
						<span class="text-sm text-gray-400 shrink-0" x-text="point.date"></span>
					</div>
				</template>
			</div>
		</div>
		<?php
	}


	/**
	 * Render the referrals activity section.
	 *
	 * @since 1.0.0
	 *
	 * @param Member $member The member object.
	 *
	 * @return void
	 */
	private function render_referrals_activity( Member $member ): void {
		$referrals = get_referrals(
			[
				'advocate_id' => $member->id,
				'orderby'     => 'created_at',
				'order'       => 'DESC',
			],
			self::ACTIVITY_ITEMS_PER_PAGE
		);

		if ( empty( $referrals ) ) {
			?>
			<div class="text-center py-12">
				<div class="mx-auto flex items-center justify-center">
					<?php echo wp_kses( $this->icon_helper->get_icon( 'earn-referral', 'size-10 text-gray-400' ), svg_kses() ); ?>
				</div>
				<h3 class="mt-2 text-sm font-medium text-gray-900"><?php esc_html_e( 'No Referral Activity', 'rewardswp' ); ?></h3>
				<p class="mt-1 text-sm text-gray-400"><?php esc_html_e( 'This member has no referral activity yet.', 'rewardswp' ); ?></p>
			</div>
			<?php
			return;
		}

		?>
		<div id="referrals-rows" class="divide-y divide-gray-50">
			<?php foreach ( $referrals as $referral ) : ?>
				<?php
				$order_id   = $referral->order_id ?? null;
				$status     = $referral->status;
				$order_link = '';

				// Build status label and suffix.
				switch ( $status ) {
					case 'pending':
						$status_label = __( 'Pending', 'rewardswp' );
						if ( ! empty( $order_id ) ) {
							$order_link = $this->referrals_service->get_referred_order_link( $referral );
						}
						break;
					case 'completed':
						$status_label = __( 'Completed', 'rewardswp' );
						if ( ! empty( $order_id ) ) {
							$order_link = $this->referrals_service->get_referred_order_link( $referral );
						}
						break;
					case 'rejected':
					case 'blocked':
						$status_label = __( 'Blocked', 'rewardswp' );
						break;
					default:
						$status_label = ucfirst( $status );
				}

				// Get reward title.
				$reward_title    = '';
				$referral_reward = $referral->get_reward();
				if ( is_a( $referral_reward, Reward::class ) && $referral_reward->amount > 0 ) {
					$reward_title = get_reward_formatted_amount( $referral_reward );
				}

				$date = get_relative_date_label( $referral->created_at );
				?>
				<div id="referral-<?php echo esc_attr( $referral->id ); ?>" class="py-3 flex items-center gap-3">
					<?php
					$status_classes = [
						'completed' => 'bg-green-50 text-green-700 ring-green-600/20',
						'canceled'  => 'bg-gray-50 text-gray-600 ring-gray-500/20',
						'blocked'   => 'bg-red-50 text-red-700 ring-red-600/20',
						'pending'   => 'bg-yellow-50 text-yellow-700 ring-yellow-600/20',
					];
					$badge_classes  = $status_classes[ $status ] ?? 'bg-gray-50 text-gray-600 ring-gray-500/20';
					?>
					<!-- Status Badge (fixed width) -->
					<span class="w-24 shrink-0">
						<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ring-1 ring-inset <?php echo esc_attr( $badge_classes ); ?>">
							<?php echo esc_html( $status_label ); ?>
						</span>
					</span>

					<!-- Order + Reward -->
					<div class="flex-1 min-w-0 text-sm text-gray-900">
						<?php if ( ! empty( $order_id ) ) : ?>
							<?php if ( ! empty( $order_link ) ) : ?>
								<a href="<?php echo esc_url( $order_link ); ?>" class="hover:underline">
													<?php
													/* translators: %s: Order ID */
													printf( esc_html__( 'Order #%s', 'rewardswp' ), esc_html( $order_id ) );
													?>
								</a>
							<?php else : ?>
								<?php
								/* translators: %s: Order ID */
								printf( esc_html__( 'Order #%s', 'rewardswp' ), esc_html( $order_id ) );
								?>
							<?php endif; ?>
						<?php elseif ( ! empty( $referral_reward ) || ! empty( $referral->referred_email ) ) : ?>
							<?php esc_html_e( 'Reward claimed', 'rewardswp' ); ?><span class="text-gray-400 px-1">·</span><?php esc_html_e( 'Awaiting purchase', 'rewardswp' ); ?>
						<?php endif; ?>
						<?php if ( $reward_title ) : ?>
							<span class="text-gray-400 px-1">·</span><?php echo esc_html( $reward_title ); ?> <span class="text-gray-400"><?php esc_html_e( '(Advocate)', 'rewardswp' ); ?></span>
						<?php endif; ?>
					</div>

					<!-- Date -->
					<span class="text-sm text-gray-400 shrink-0"><?php echo esc_html( $date ); ?></span>
				</div>
			<?php endforeach; ?>
		</div>
		<?php
	}

	/**
	 * Render the rewards activity section.
	 *
	 * @since 1.0.0
	 *
	 * @param Member $member The member object.
	 *
	 * @return void
	 */
	private function render_rewards_activity( Member $member ): void {
		$rewards = get_advocate_rewards(
			$member->id,
			[
				'orderby' => 'created_at',
				'order'   => 'DESC',
			],
			self::ACTIVITY_ITEMS_PER_PAGE
		);

		if ( empty( $rewards ) ) {
			?>
			<div class="text-center py-12">
				<div class="mx-auto flex items-center justify-center">
					<?php echo wp_kses( $this->icon_helper->get_icon( 'reward-redemption', 'size-10 text-gray-400' ), svg_kses() ); ?>
				</div>
				<h3 class="mt-2 text-sm font-medium text-gray-900"><?php esc_html_e( 'No Rewards Activity', 'rewardswp' ); ?></h3>
				<p class="mt-1 text-sm text-gray-400"><?php esc_html_e( 'This member has no rewards activity yet.', 'rewardswp' ); ?></p>
			</div>
			<?php
			return;
		}

		$points_currency = get_points_currency_plural();
		?>
		<div id="rewards-rows" class="divide-y divide-gray-50" tabindex="-1" aria-label="<?php esc_attr_e( 'Rewards activity list', 'rewardswp' ); ?>">
			<?php
			foreach ( $rewards as $index => $reward ) :
				$status_classes = [
					'pending'  => 'bg-yellow-50 text-yellow-700 ring-yellow-600/20',
					'issued'   => 'bg-blue-50 text-blue-700 ring-blue-600/20',
					'canceled' => 'bg-gray-50 text-gray-600 ring-gray-500/20',
					'redeemed' => 'bg-green-50 text-green-700 ring-green-600/20',
					'expired'  => 'bg-red-50 text-red-700 ring-red-600/20',
				];

				$status_labels = [
					'pending'  => __( 'Pending', 'rewardswp' ),
					'issued'   => __( 'Issued', 'rewardswp' ),
					'canceled' => __( 'Canceled', 'rewardswp' ),
					'redeemed' => __( 'Used', 'rewardswp' ),
					'expired'  => __( 'Expired', 'rewardswp' ),
				];

				$status_key    = strtolower( $reward->status );
				$badge_classes = $status_classes[ $status_key ] ?? 'bg-gray-50 text-gray-600 ring-gray-500/20';
				$status_label  = $status_labels[ $status_key ] ?? ucfirst( $status_key );

				// Context-aware date based on status.
				$display_date = '';
				switch ( $status_key ) {
					case 'redeemed':
						$display_date = get_relative_date_label( $reward->applied_at );
						break;
					case 'expired':
						$display_date = get_relative_date_label( $reward->expires_at );
						break;
					case 'issued':
					case 'pending':
					case 'canceled':
					default:
						$display_date = get_relative_date_label( $reward->created_at );
						break;
				}

				// Get reward name/amount and optional meta.
				$reward_name       = get_reward_formatted_amount( $reward );
				$point_cost        = $reward->get_point_cost();
				$is_referral       = ! empty( $reward->referral_id );
				$applied_order_id  = $reward->get_meta( 'applied_order_id' );
				$applied_order_url = ! empty( $applied_order_id ) ? admin_url( 'post.php?post=' . $applied_order_id . '&action=edit' ) : '';
				?>
				<div id="reward-<?php echo esc_attr( $reward->id ); ?>" class="py-3 flex items-center gap-3 <?php echo ( 0 === $index ) ? 'first-row transition-all duration-300' : ''; ?>">
					<!-- Status Badge (fixed width) -->
					<span class="w-24 shrink-0">
						<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ring-1 ring-inset <?php echo esc_attr( $badge_classes ); ?>">
							<?php echo esc_html( $status_label ); ?>
						</span>
					</span>

					<!-- Reward name + meta -->
					<div class="flex-1 min-w-0 text-sm text-gray-900">
						<?php echo esc_html( $reward_name ); ?>
						<?php if ( 'redeemed' === $status_key && ! empty( $applied_order_id ) ) : ?>
							<span class="text-gray-400 px-1">·</span>
							<span class="text-gray-400"><?php esc_html_e( 'Used on', 'rewardswp' ); ?></span>
							<a href="<?php echo esc_url( $applied_order_url ); ?>" class="text-gray-400 hover:underline">
								<?php
								/* translators: %s: Order ID. */
								printf( esc_html__( 'Order #%s', 'rewardswp' ), esc_html( $applied_order_id ) );
								?>
							</a>
						<?php elseif ( $is_referral ) : ?>
							<span class="text-gray-400 px-1">·</span>
							<span class="text-gray-400"><?php esc_html_e( 'Referral reward', 'rewardswp' ); ?></span>
						<?php elseif ( ! empty( $point_cost ) && $point_cost > 0 ) : ?>
							<span class="text-gray-400 px-1">·</span>
							<span class="text-gray-400">
								<?php
								printf(
									/* translators: 1: number of points, 2: points currency name (e.g., "Points", "Coins") */
									esc_html__( 'Redeemed %1$s %2$s', 'rewardswp' ),
									esc_html( number_format( $point_cost ) ),
									esc_html( $points_currency )
								);
								?>
							</span>
						<?php endif; ?>
					</div>

					<!-- Date -->
					<?php if ( ! empty( $display_date ) ) : ?>
						<span class="text-sm text-gray-400 shrink-0"><?php echo esc_html( $display_date ); ?></span>
					<?php endif; ?>
				</div>
			<?php endforeach; ?>
		</div>
		<?php
	}
}
