<?php
/**
 * Members list table view.
 *
 * @package Awesomemotive\Rewardswp\Views\Admin\ListTables
 * @since 1.0.0
 */

namespace Awesomemotive\Rewardswp\Views\Admin\ListTables;

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

use Awesomemotive\Rewardswp\Factories\IntegrationsFactory;
use Awesomemotive\Rewardswp\Factories\ViewsFactory;
use Awesomemotive\Rewardswp\Interfaces\IntegrationWithCouponInterface;
use Awesomemotive\Rewardswp\Interfaces\ViewInterface;
use Awesomemotive\Rewardswp\Models\Member;
use Awesomemotive\Rewardswp\Services\MembersService;
use Awesomemotive\Rewardswp\Helpers\IconHelper;
use Awesomemotive\Rewardswp\Services\MemberStatsService;
use Exception;
use WP_List_Table;
use function Awesomemotive\Rewardswp\Helpers\get_human_readable_date;
use function Awesomemotive\Rewardswp\Helpers\get_member_status_badge_html;
use function Awesomemotive\Rewardswp\Helpers\get_referrals;
use function Awesomemotive\Rewardswp\Helpers\get_site_currency_symbol;
use function Awesomemotive\Rewardswp\Helpers\format_currency;
use function Awesomemotive\Rewardswp\Helpers\is_pro_version_at_least;
use function Awesomemotive\Rewardswp\Helpers\is_rewardswp_lite_plan;
use Awesomemotive\Rewardswp\Settings\Options\Points\PointsEnabledOption;
use Awesomemotive\Rewardswp\Settings\Options\Referrals\EnabledOption as ReferralsEnabledOption;
use function Awesomemotive\Rewardswp\Helpers\get_option_value;
use function Awesomemotive\Rewardswp\Helpers\svg_kses;

class MembersListTableView extends WP_List_Table implements ViewInterface {
	/**
	 * The gravatar size.
	 *
	 * @since 1.0.0
	 *
	 * @var int
	 */
	const GRAVATAR_SIZE = 36;

	/**
	 * Members service instance.
	 *
	 * @since 1.0.0
	 *
	 * @var MembersService
	 */
	private MembersService $members_service;

	/**
	 * Integrations factory instance.
	 *
	 * @since 1.0.0
	 *
	 * @var IntegrationsFactory
	 */
	private IntegrationsFactory $integration_factory;

	/**
	 * Member stats service instance.
	 *
	 * @since 1.0.0
	 *
	 * @var MembersService
	 */
	private MemberStatsService $member_stats_service;

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

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

	/**
	 * Status labels for list table.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	private array $statuses = [];

	/**
	 * Constructor.
	 *
	 * @param MembersService      $members_service
	 * @param IntegrationsFactory $integration_factory
	 * @param MemberStatsService  $member_stats_service
	 * @param ViewsFactory        $views_factory
	 * @param IconHelper          $icon_helper
	 *
	 * @since 1.0.0
	 */
	public function __construct(
		MembersService $members_service,
		IntegrationsFactory $integration_factory,
		MemberStatsService $member_stats_service,
		ViewsFactory $views_factory,
		IconHelper $icon_helper
	) {
		$this->members_service      = $members_service;
		$this->integration_factory  = $integration_factory;
		$this->member_stats_service = $member_stats_service;
		$this->views_factory        = $views_factory;
		$this->icon_helper          = $icon_helper;

		$this->statuses = [
			'active'   => esc_html__( 'Members', 'rewardswp' ),
			'guest'    => esc_html__( 'Guests', 'rewardswp' ),
			'excluded' => esc_html__( 'Excluded', 'rewardswp' ),
		];

		parent::__construct(
			[
				'singular' => 'member',
				'plural'   => 'members',
				'ajax'     => false,
			]
		);
	}

	/**
	 * Get columns.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	public function get_columns(): array {
		$columns = [
			'cb'     => '<input type="checkbox" />',
			'member' => esc_html__( 'Member', 'rewardswp' ),
		];

		if ( is_pro_version_at_least( '1.0.1' ) ) {
			$columns['points_available'] = sprintf(
				'<span title="%s">%s</span>',
				esc_attr__( 'Total points available for this member', 'rewardswp' ),
				esc_html__( 'Points Available', 'rewardswp' )
			);
		}

		$columns += [
			'referral_revenue' => sprintf(
				'<span title="%s">%s</span>',
				esc_attr__( 'Total revenue generated from referred customers', 'rewardswp' ),
				esc_html__( 'Referral Revenue', 'rewardswp' )
			),
			'referrals'        => sprintf(
				'<span title="%s">%s</span>',
				esc_attr__( 'Number of successful referrals and conversion rate', 'rewardswp' ),
				esc_html__( 'Referrals', 'rewardswp' )
			),
			'points_balance'   => sprintf(
				'<span title="%s">%s</span>',
				esc_attr__( 'Current points balance for this member', 'rewardswp' ),
				esc_html__( 'Points Balance', 'rewardswp' )
			),
			'created_at'       => esc_html__( 'Joined', 'rewardswp' ),
			'status'           => esc_html__( 'Status', 'rewardswp' ),
			'actions'          => esc_html__( 'Actions', 'rewardswp' ),
		];

		return $columns;
	}

	/**
	 * Get sortable columns.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	public function get_sortable_columns(): array {
		$columns = [
			'member'         => [ 'first_name', false ],
			'referrals'      => [ 'completed_referrals', false ],
			'points_balance' => [ 'points_balance', false ],
			'created_at'     => [ 'created_at', false ],
			'status'         => [ 'status', false ],
		];

		if ( is_pro_version_at_least( '1.0.1' ) ) {
			$columns['points_available'] = [ 'points_balance', false ];
		}

		return $columns;
	}

	/**
	 * Set hidden columns.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	public function get_hidden_columns(): array {
		return get_hidden_columns( $this->screen );
	}

	/**
	 * Get bulk actions.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	public function get_bulk_actions(): array {
		$actions = [
			'rewardswp_bulk_delete'  => esc_html__( 'Delete', 'rewardswp' ),
			'rewardswp_bulk_exclude' => esc_html__( 'Exclude from program', 'rewardswp' ),
			'rewardswp_bulk_include' => esc_html__( 'Include in program', 'rewardswp' ),
		];
		return $actions;
	}

	/**
	 * Renders the message to be displayed when there are no members.
	 *
	 * @since 1.0.0
	 */
	function no_items() {
		esc_html_e( 'No members found.', 'rewardswp' );
	}

	/**
	 * Parse query arguments for members search and filtering.
	 *
	 * @since 1.0.0
	 *
	 * @return array Parsed query arguments ready for DatabaseHandler.
	 */
	private function parse_query_args(): array {
		$args = array_filter(
			[
				'order'   => sanitize_text_field( filter_input( INPUT_GET, 'order' ) ?? 'desc' ),
				'orderby' => sanitize_text_field( filter_input( INPUT_GET, 'orderby' ) ?? 'id' ),
				'status'  => sanitize_text_field( filter_input( INPUT_GET, 'status' ) ?? '' ),
			]
		);

		// Handle search query
		$search_term = sanitize_text_field( filter_input( INPUT_GET, 's' ) ?? '' );
		if ( ! empty( $search_term ) ) {
			$args['like_query'] = [
				'search_term' => $search_term,
				'columns'     => [
					'first_name',
					'last_name',
					'email',
					"CONCAT(first_name, ' ', last_name)",
				],
				'compare'     => 'OR',
			];
		}

		return $args;
	}

	/**
	 * Prepare items.
	 *
	 * @since 1.0.0
	 *
	 * @param int $per_page The number of items per page. Default 20.
	 *
	 * @return void
	 */
	public function prepare_items( int $per_page = 20 ): void {
		$this->_column_headers = [
			$this->get_columns(),
			$this->get_hidden_columns(),
			$this->get_sortable_columns(),
		];

		$current_page = $this->get_pagenum();
		$query_args   = $this->parse_query_args();

		// Get total count for pagination
		$total_count = $this->members_service->count_members( $query_args );

		$this->set_pagination_args(
			[
				'total_items' => $total_count,
				'total_pages' => ceil( $total_count / $per_page ),
				'per_page'    => $per_page,
			]
		);

		// Get the members data
		$this->items = $this->members_service->get_members( $query_args, $per_page, $current_page );
	}

	/**
	 * Generates the HTML for a single row of the table.
	 *
	 * @since 1.1.0
	 * @param object|array $item The current item. Expects a Member object.
	 */
	public function single_row( $item ) {
		// Ensure $item is a Member object and has an id property.
		if ( $item instanceof Member && isset( $item->id ) ) {
			echo '<tr id="member-' . esc_attr( $item->id ) . '">';
		} else {
			echo '<tr>';
		}
		$this->single_row_columns( $item );
		echo '</tr>';
	}

	/**
	 * Render the template.
	 *
	 * @since 1.0.0
	 *
	 * @param array $args {
	 *     @type string $page_title     The page title. Default to the current admin page title.
	 *     @type string $items_per_page The page content. Default ''.
	 * }
	 *
	 * @return void
	 */
	public function render( array $args = [] ): void {
		$args = wp_parse_args(
			$args,
			[
				'page_title'     => esc_html__( 'Members', 'rewardswp' ),
				'items_per_page' => $this->get_items_per_page( 'members_per_page' ),
			]
		);

		$this->prepare_items( $args['items_per_page'] );

		// Nonce for fetching member modal - ensure this nonce is also used in MembersAdminController for check_ajax_referer()
		$member_modal_nonce = wp_create_nonce( 'rewardswp_admin_ajax_nonce' );

		?>

		<div
			class="wrap !mt-6 mr-6 mb-0 ml-[2px] px-3"
			x-data="{
				showMemberModal: false,
				memberModalHtml: '',
				memberModalLoading: false,
				memberModalNonce: '<?php echo esc_js( $member_modal_nonce ); ?>',
				init() {
					const urlParams = new URLSearchParams(window.location.search);
					const message = urlParams.get('rewardswp_message');
					if (message === 'member_deleted_successfully') {
						window.dispatchEvent(new CustomEvent('rewardswp-toast', {
							detail: { message: '<?php echo esc_js( __( 'Member deleted successfully.', 'rewardswp' ) ); ?>', type: 'success' }
						}));
						// Clean the URL
						const newUrl = window.location.pathname + window.location.search.replace(/[?&]rewardswp_message=member_deleted_successfully/, '').replace(/^&/, '?');
						window.history.replaceState({}, document.title, newUrl);
					} else if (message === 'member_created_successfully') {
						window.dispatchEvent(new CustomEvent('rewardswp-toast', {
							detail: { message: '<?php echo esc_js( __( 'Member created successfully.', 'rewardswp' ) ); ?>', type: 'success' }
						}));
						// Clean the URL
						const newUrl = window.location.pathname + window.location.search.replace(/[?&]rewardswp_message=member_created_successfully/, '').replace(/^&/, '?');
						window.history.replaceState({}, document.title, newUrl);
					}
				},
				openMemberModal(memberId) {
					this.memberModalLoading = true;
					this.showMemberModal = true; // Show modal container, perhaps with a loader
					this.memberModalHtml = '<div class=\'p-10 text-center\'><?php esc_html_e( 'Loading member details...', 'rewardswp' ); ?></div>'; // Basic loader

					const formData = new FormData();
					formData.append('action', 'rewardswp_get_member_modal');
					formData.append('member_id', memberId);
					formData.append('nonce', this.memberModalNonce);

					fetch(ajaxurl, { // ajaxurl is a global WordPress variable
						method: 'POST',
						body: formData
					})
					.then(response => response.json())
					.then(result => {
						this.memberModalLoading = false;
						if (result.success && result.data.html) {
							this.memberModalHtml = result.data.html;
						} else {
							this.memberModalHtml = '<div class=\'p-10 text-center text-red-500\'>' + (result.data.message || '<?php esc_html_e( 'Error loading details.', 'rewardswp' ); ?>') + '</div>';
						}
					})
					.catch(error => {
						this.memberModalLoading = false;
						this.memberModalHtml = '<div class=\'p-10 text-center text-red-500\'><?php esc_html_e( 'Request failed.', 'rewardswp' ); ?></div>';
						console.error('Error fetching member modal:', error);
					});
				},
				closeMemberModal() {
					this.showMemberModal = false;
					this.memberModalHtml = ''; // Clear content on close
				}
			}"
			x-on:close-member-modal.window="closeMemberModal()" <?php // Listen for global close event from modal itself ?>
		>
			<h1 class="wp-heading-inline sr-only"><?php echo esc_html( $args['page_title'] ); ?></h1>

			<button
				type="button"
				x-on:click="$dispatch('open-add-member-modal')"
				class="page-title-action"
			>
				<?php esc_html_e( 'Add New Member', 'rewardswp' ); ?>
			</button>
			<hr class="wp-header-end"><?php // Padrão WordPress para espaçamento após título ?>

			<div class="mb-0" style="overflow: hidden;">
				<?php
				$this->views();
				?>
			</div>

			<form method="get">
				<?php
				// Preserve current page and other query parameters
				// This is an admin GET form for navigation purposes only, nonce verification is not required.
				// phpcs:ignore WordPress.Security.NonceVerification.Recommended
				foreach ( $_GET as $key => $value ) {
					if ( 'page' === $key || 'paged' === $key || 's' === $key ) {
						continue; // These will be handled by search_box() and pagination
					}
					// Sanitize the value for output in hidden field.
					$sanitized_key   = sanitize_text_field( wp_unslash( $key ) );
					$sanitized_value = sanitize_text_field( wp_unslash( $value ) );
					echo '<input type="hidden" name="' . esc_attr( $sanitized_key ) . '" value="' . esc_attr( $sanitized_value ) . '" />';
				}
				// phpcs:ignore WordPress.Security.NonceVerification.Recommended
				$current_page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
				echo '<input type="hidden" name="page" value="' . esc_attr( $current_page ) . '" />';
				?>
				<?php $this->search_box( esc_html__( 'Search Members', 'rewardswp' ), 'search_id' ); ?>
				<?php $this->display_tablenav( 'top' ); ?>

				<table class="wp-list-table <?php echo esc_attr( implode( ' ', $this->get_table_classes() ) ); ?>">

					<thead>
					<tr>
						<?php $this->print_column_headers(); ?>
					</tr>
					</thead>

					<tbody id="the-list" <?php echo $this->has_items() ? 'data-wp-lists="list:' . esc_attr( $this->_args['singular'] ) . '"' : ''; ?>>
					<?php $this->display_rows_or_placeholder(); ?>
					</tbody>

					<tfoot>
					<tr>
						<?php $this->print_column_headers( false ); ?>
					</tr>
					</tfoot>

				</table>

				<?php $this->display_tablenav( 'bottom' ); ?>

			</form>

			<div class="rewardswp-container">
				<?php // Global Modal Container ?>
				<template x-if="showMemberModal">
					<div x-html="memberModalHtml" x-on:click.self="closeMemberModal()" class="fixed inset-0 z-[99998] flex items-center justify-center"></div>
				</template>

				<?php $this->render_modals(); ?>
			</div>
		</div>

		<?php
	}

	/**
	 * Render all modals used by the actions dropdown.
	 *
	 * @since 1.1.0
	 * @return void
	 */
	private function render_modals(): void {
		// These modals are generic and will be populated by data from Alpine events.
		$points_enabled    = (bool) get_option_value( PointsEnabledOption::class );
		$referrals_enabled = (bool) get_option_value( ReferralsEnabledOption::class );

		if ( $points_enabled ) {
			$this->views_factory->get_view( \Awesomemotive\Rewardswp\Views\Admin\Modals\AdjustPointsModalView::class )->render(
				[
					'alpine_component_name' => 'listAdjustPointsModal',
				]
			);
		}

		if ( $referrals_enabled ) {
			$this->views_factory->get_view( \Awesomemotive\Rewardswp\Views\Admin\Modals\UpdateReferralCodeModalView::class )->render(
				[
					'alpine_component_name' => 'listUpdateReferralCodeModal',
				]
			);
		}

		$this->views_factory->get_view( \Awesomemotive\Rewardswp\Views\Admin\Modals\AddMemberModalView::class )->render( [] );
		$this->views_factory->get_view( \Awesomemotive\Rewardswp\Views\Admin\Modals\EditMemberModalView::class )->render( [] );
		$this->views_factory->get_view( \Awesomemotive\Rewardswp\Views\Admin\Modals\DeleteMemberModalView::class )->render( [] );
		$this->views_factory->get_view( \Awesomemotive\Rewardswp\Views\Admin\Modals\ExcludeMemberModalView::class )->render( [] );
	}

	/**
	 * Column cb.
	 *
	 * @since 1.0.0
	 *
	 * @param Member $item Advocate object.
	 *
	 * @return string
	 */
	public function column_cb( $item ): string {
		return sprintf(
			'<input type="checkbox" name="bulk-delete[]" value="%s" />',
			$item->id
		);
	}

	/**
	 * Render the actions column with a View button.
	 *
	 * @since 1.0.0
	 * @param Member $item Member object.
	 * @return string
	 */
	public function column_actions( $item ): string {
		// Nonces for the dropdown actions.
		$adjust_points_nonce        = wp_create_nonce( 'rewardswp_adjust_points_nonce_' . $item->id );
		$update_referral_code_nonce = wp_create_nonce( 'rewardswp_update_referral_code_nonce_' . $item->id );
		$edit_member_nonce          = wp_create_nonce( 'rewardswp_edit_member_nonce_' . $item->id );
		$delete_member_nonce        = wp_create_nonce( 'rewardswp_delete_member_nonce_' . $item->id );

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

		// Data for modal events.
		$member_id       = (int) $item->id;
		$full_name       = sanitize_text_field( $item->get_full_name() );
		$email           = sanitize_text_field( $item->email );
		$points_balance  = absint( $item->points_balance ?? 0 );
		$referral_code   = sanitize_text_field( $item->referral_code );
		$detail_view_url = esc_url(
			add_query_arg(
				[
					'page'      => 'rewardswp-members',
					'action'    => 'view_member',
					'member_id' => $item->id,
				],
				admin_url( 'admin.php' )
			)
		);

		$adjust_points_payload = wp_json_encode(
			[
				'memberId'       => $member_id,
				'memberName'     => $full_name,
				'currentBalance' => $points_balance,
				'nonce'          => $adjust_points_nonce,
			]
		);

		$update_referral_payload = wp_json_encode(
			[
				'memberId'             => $member_id,
				'currentReferralCode'  => $referral_code,
				'nonce'                => $update_referral_code_nonce,
			]
		);

		$delete_member_payload = wp_json_encode(
			[
				'memberId' => $member_id,
				'nonce'    => $delete_member_nonce,
			]
		);

		ob_start();
		?>
		<div class="flex items-center gap-2">
			<!-- View Link -->
			<a
				href="<?php echo esc_url( $detail_view_url ); ?>"
				class="text-[#2271b1] hover:text-[#135e96] text-sm font-medium"
			>
				<?php esc_html_e( 'View', 'rewardswp' ); ?>
			</a>

			<!-- Actions Dropdown -->
			<div x-data="{ open: false }" class="relative inline-block">

				<button
					type="button"
					x-ref="trigger"
					x-on:click="open = !open; if (open) $nextTick(() => $refs.menu?.focus())"
					x-on:keydown.arrow-down.prevent="open = true; $nextTick(() => $refs.menu?.focus())"
					x-on:keydown.arrow-up.prevent="open = true; $nextTick(() => $refs.menu?.focus())"
					x-bind:aria-expanded="open"
					aria-haspopup="menu"
					x-bind:aria-label="open ? '<?php esc_attr_e( 'Close menu', 'rewardswp' ); ?>' : '<?php esc_attr_e( 'Open menu', 'rewardswp' ); ?>'"
					class="inline-flex cursor-pointer items-center justify-center w-6 h-6 text-gray-700 hover:text-gray-900 hover:bg-gray-50 rounded focus:outline-none focus:ring-1 focus:ring-blue-500 transition-colors"
					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() ); ?>
				</button>

				<div
					x-show="open"
					x-cloak
					x-ref="menu"
					x-on:keydown.escape.window="open = false; $refs.trigger?.focus()"
					x-on:keydown.arrow-down.prevent="$event.target.nextElementSibling?.focus() || $el.firstElementChild?.focus()"
					x-on:keydown.arrow-up.prevent="$event.target.previousElementSibling?.focus() || $el.lastElementChild?.focus()"
					x-on:click.outside="open = false"
					tabindex="-1"
					role="menu"
					aria-orientation="vertical"
					class="absolute right-0 z-50 mt-1 w-56 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"
				>
					<div class="p-1" role="none">
						<?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"
								tabindex="0"
								x-on:click="open = false; $dispatch('open-adjust-points-modal', <?php echo esc_attr( $adjust_points_payload ); ?>)"
								x-on:keydown.enter.prevent="$el.click()"
								x-on:keydown.space.prevent="$el.click()"
							>
								<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 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"
								tabindex="0"
								x-on:click="open = false; $dispatch('open-list-update-referral-code-modal', <?php echo esc_attr( $update_referral_payload ); ?>)"
								x-on:keydown.enter.prevent="$el.click()"
								x-on:keydown.space.prevent="$el.click()"
							>
								<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; ?>

						<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"
							tabindex="0"
							x-on:click="open = false; window.dispatchEvent(new CustomEvent('open-delete-member-modal', { detail: <?php echo esc_attr( $delete_member_payload ); ?> }))"
							x-on:keydown.enter.prevent="$el.click()"
							x-on:keydown.space.prevent="$el.click()"
						>
							<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>
		<?php
		return ob_get_clean();
	}

	/**
	 * Column default.
	 *
	 * @param Member $item        Advocate object.
	 * @param string $column_name Column name.
	 *
	 * @return string
	 *
	 * @throws Exception
	 */
	public function column_default( $item, $column_name ): string {
		switch ( $column_name ) {
			case 'member':
				return $this->column_member( $item );
			case 'created_at':
				return $this->column_created_at( $item );
			case 'status':
				return $this->column_status( $item );
			case 'points_available':
				return $this->column_points_available( $item );
			case 'points_balance':
				return $this->column_points_balance( $item );
			case 'actions':
				return $this->column_actions( $item );
			default:
				return $item->$column_name;
		}
	}

	/**
	 * Column member.
	 *
	 * @since 1.0.0
	 *
	 * @param Member $item Member object.
	 *
	 * @return string
	 *
	 * @throws Exception
	 */
	public function column_member( Member $item ): string {
		if ( ! is_a( $item, Member::class ) ) {
			return esc_html__( 'N/A', 'rewardswp' );
		}

		ob_start();

		$avatar_url_small = esc_url_raw(
			get_avatar_url(
				$item->email,
				[
					'size' => self::GRAVATAR_SIZE, // Typically 36
				]
			)
		);
		$avatar_url_large = esc_url_raw(
			get_avatar_url(
				$item->email,
				[
					'size' => 64, // Larger for the card
				]
			)
		);
		$full_name        = esc_html( $item->get_full_name() );
		$full_name_attr   = esc_attr( $item->get_full_name() );

		$status_badge_html = get_member_status_badge_html( $item );

		$hover_sections = [
			'activity'         => [
				'label' => esc_html__( 'Last Active', 'rewardswp' ),
				'value' => $this->get_last_active_date( $item->user_id ?? 0 ),
			],
			'referral_revenue' => [
				'label' => esc_html__( 'Referral Revenue', 'rewardswp' ),
				'value' => format_currency( $item->get_total_referral_revenue() ),
			],
			'available_points' => [
				'label' => esc_html__( 'Available Points', 'rewardswp' ),
				'value' => isset( $item->points_balance ) ?
					sprintf(
						/* translators: %s: Number of points available. */
						esc_html__( '%s points', 'rewardswp' ),
						number_format( $item->points_balance )
					) :
					esc_html__( '0 points', 'rewardswp' ),
			],
			'conversion_rate'  => [
				'label' => esc_html__( 'Conversion Rate', 'rewardswp' ),
				'value' => sprintf(
					'%s%%',
					number_format( $item->get_referral_conversion_rate(), 1 )
				),
			],
		];

		?>
		<div x-data="{
				hoverCardHovered: false,
				hoverCardDelay: 500,
				hoverCardLeaveDelay: 100,
				hoverCardTimout: null,
				hoverCardLeaveTimeout: null,
			position: 'bottom',
				init() {
					this.$nextTick(() => this.checkPosition());
				window.addEventListener('scroll', () => this.checkPosition());
				window.addEventListener('resize', () => this.checkPosition());
				},
				checkPosition() {
					const rect = this.$el.getBoundingClientRect();
					const spaceAbove = rect.top;
					const spaceBelow = window.innerHeight - rect.bottom;
				this.position = spaceAbove < 400 ? 'bottom' : 'top';
				},
				hoverCardEnter () {
					clearTimeout(this.hoverCardLeaveTimeout);
					if(this.hoverCardHovered) return;
					clearTimeout(this.hoverCardTimout);
					this.hoverCardTimout = setTimeout(() => {
						this.hoverCardHovered = true;
						this.$nextTick(() => this.checkPosition());
					}, this.hoverCardDelay);
				},
				hoverCardLeave () {
					clearTimeout(this.hoverCardTimout);
					if(!this.hoverCardHovered) return;
					clearTimeout(this.hoverCardLeaveTimeout);
					this.hoverCardLeaveTimeout = setTimeout(() => {
						this.hoverCardHovered = false;
					}, this.hoverCardLeaveDelay);
				}
			}"
			class="relative"
			@mouseover="hoverCardEnter()"
			@mouseleave="hoverCardLeave()">
				<?php
				$member_detail_url = esc_url(
					add_query_arg(
						[
							'page'      => 'rewardswp-members',
							'action'    => 'view_member',
							'member_id' => $item->id,
						],
						admin_url( 'admin.php' )
					)
				);
				?>
				<div class="group block shrink-0 rewardswp-container">
					<div class="flex items-center">
					<a href="<?php echo esc_url( $member_detail_url ); ?>" class="shrink-0">
						<img class="inline-block size-9 rounded-full hover:opacity-80 transition-opacity" src="<?php echo esc_url( $avatar_url_small ); ?>" alt="<?php echo esc_attr( $full_name_attr ); ?>">
					</a>
						<div class="ml-3 min-w-0">
						<a href="<?php echo esc_url( $member_detail_url ); ?>" class="text-sm font-medium text-[#2271b1] hover:text-[#135e96] block truncate max-w-[200px]" title="<?php echo esc_attr( $full_name ); ?>">
							<?php echo esc_html( $full_name ); ?>
						</a>
						</div>
					</div>
				</div>

				<!-- Hover Card -->
				<div x-show="hoverCardHovered"
					x-transition:enter="transition ease-out duration-200"
					x-transition:enter-start="opacity-0"
					x-transition:enter-end="opacity-100"
					x-transition:leave="transition ease-in duration-150"
					x-transition:leave-start="opacity-100"
					x-transition:leave-end="opacity-0"
					x-bind:class="{
					'bottom-full mb-2': position === 'top',
					'top-full mt-2': position === 'bottom'
					}"
					class="absolute left-20 w-96 z-[9999] origin-top-left"
					x-cloak>
					<div class="relative bg-white rounded-lg shadow-lg ring-1 ring-gray-200 p-4 [will-change:opacity]">
						<!-- Header with large avatar -->
						<div class="flex items-start gap-4 mb-4">
							<img class="size-16 rounded-full" src="<?php echo esc_url( $avatar_url_large ); ?>" alt="<?php echo esc_attr( $full_name_attr ); ?>">
								<div class="flex-1 min-w-0">
									<div class="flex items-center gap-2">
									<p class="text-base font-semibold text-gray-900 truncate"><?php echo esc_html( $full_name ); ?></p>
									<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium shrink-0">
										<?php echo wp_kses_post( $status_badge_html ); ?>
									</span>
								</div>
								<p class="text-sm text-gray-500 truncate" title="<?php echo esc_attr( $item->email ); ?>"><?php echo esc_html( $item->email ); ?></p>
							</div>
						</div>

						<!-- Stats Grid -->
						<div class="grid grid-cols-2 gap-4 border-t border-gray-100 pt-4">
						<?php foreach ( $hover_sections as $section ) : ?>
						<div>
							<p class="text-xs font-medium text-gray-500 uppercase"><?php echo esc_html( $section['label'] ); ?></p>
							<p class="mt-1 text-sm font-medium text-gray-900"><?php echo esc_html( $section['value'] ); ?></p>
						</div>
						<?php endforeach; ?>
						</div>

						<!-- Arrow/Triangle for the balloon effect -->
						<div x-bind:class="{
						'-bottom-2 border-t-0 border-l-0': position === 'top',
						'-top-2 border-b-0 border-r-0': position === 'bottom'
						}"
						class="absolute left-4 h-4 w-4 rotate-45 bg-white border border-gray-200"></div>
					</div>
				</div>
		</div>
		<?php
		return ob_get_clean();
	}

	/**
	 * Get the last active date for a member.
	 *
	 * @param int $user_id The user ID.
	 * @return string
	 */
	private function get_last_active_date( int $user_id ): string {
		// TODO: Implement the logic to fetch the user's last active date
		// For now, fall back to user registration date
		$user = get_user_by( 'id', $user_id );
		if ( ! $user ) {
			return esc_html__( 'Unknown', 'rewardswp' );
		}

		// Try to get last login from user meta, fall back to registration date
		$last_login = get_user_meta( $user_id, 'last_login', true );
		$date       = ! empty( $last_login ) ? $last_login : $user->user_registered;

		return get_human_readable_date( $date, true );
	}

	/**
	 * Column created_at.
	 *
	 * @param Member $item Member object.
	 *
	 * @return string
	 *
	 * @throws Exception
	 */
	public function column_created_at( Member $item ): string {
		return get_human_readable_date( $item->created_at, true );
	}

	/**
	 * Get referral revenue for a member.
	 *
	 * @since 1.0.0
	 *
	 * @param int $member_id The member ID.
	 *
	 * @return float
	 */
	private function get_referral_revenue( int $member_id ): float {
		$completed_referrals = get_referrals(
			[
				'status'      => 'completed',
				'advocate_id' => $member_id,
			]
		);

		if ( empty( $completed_referrals ) ) {
			return 0;
		}

		$revenue = 0;

		foreach ( $completed_referrals as $referral ) {

			$integration = $this->integration_factory->get_integration( $referral->source );

			if ( ! is_subclass_of( $integration, IntegrationWithCouponInterface::class ) ) {
				continue;
			}

			if ( empty( $referral->order_id ) ) {
				continue;
			}

			$revenue += $integration->get_order_total( $referral->order_id );
		}

		return $revenue;
	}

	/**
	 * Column referral_revenue.
	 *
	 * @since 1.0.0
	 *
	 * @param Member $item Member object.
	 *
	 * @return string
	 */
	public function column_referral_revenue( Member $item ): string {
		return format_currency( $item->get_total_referral_revenue() );
	}

	/**
	 * Column status.
	 *
	 * @since 1.0.0
	 *
	 * @param Member $item Member object.
	 *
	 * @return string
	 */
	public function column_status( Member $item ): string {
		return get_member_status_badge_html( $item );
	}

	/**
	 * Column referrals.
	 *
	 * @since 1.0.0
	 *
	 * @param Member $item Member object.
	 *
	 * @return string
	 */
	public function column_referrals( Member $item ): string {
		$stats = $this->member_stats_service->get_referral_stats( $item );

		// No referral activity at all
		if ( empty( $stats['total'] ) ) {
			return sprintf(
				'<div class="rewardswp-container text-sm text-gray-500">%s</div>',
				esc_html__( 'No referrals yet', 'rewardswp' )
			);
		}

		// Has pending but no completed referrals
		if ( empty( $stats['completed'] ) && ! empty( $stats['pending'] ) ) {
			/* translators: %d: Number of pending referrals. */
			$pending_phrase = _n( '%d pending', '%d pending', $stats['pending'], 'rewardswp' );
			$pending_message = sprintf( $pending_phrase, $stats['pending'] );

			return sprintf(
				'<div class="rewardswp-container text-sm">
                <div class="text-gray-500">%s</div>
            </div>',
				esc_html( $pending_message )
			);
		}

		// Has completed referrals (with or without pending).
		return sprintf(
			'<div class="text-sm">
            <div class="font-medium">%d %s</div>
            <div class="text-gray-500">%s</div>
        </div>',
			$stats['completed'],
			esc_html__( 'completed', 'rewardswp' ),
			$stats['pending'] > 0
				? sprintf(
					/* translators: 1: Number of pending referrals; 2: Conversion rate percentage. */
					esc_html__( '%1$d pending • %2$s success', 'rewardswp' ),
					$stats['pending'],
					$stats['conversion_rate']
				)
				: sprintf(
					/* translators: %s: Conversion rate percentage. */
					esc_html__( '%s success', 'rewardswp' ),
					$stats['conversion_rate']
				)
		);
	}

	/**
	 * Column points_balance.
	 *
	 * @since 1.1.0
	 *
	 * @param Member $item Member object.
	 *
	 * @return string
	 */
	public function column_points_balance( Member $item ): string {
		$points_balance = $item->points_balance ?? 0;

		return sprintf(
			'<span id="member-points-balance-%s" class="text-sm font-medium">%s</span>',
			esc_attr( absint( $item->id ) ),
			esc_html( number_format( $points_balance ) )
		);
	}

	/**
	 * Column points_available.
	 *
	 * @since 1.0.1
	 *
	 * @param Member $item Member object.
	 *
	 * @return string
	 */
	public function column_points_available( Member $item ): string {
		if ( ! is_pro_version_at_least( '1.0.1' ) || is_rewardswp_lite_plan() ) {
			return '';
		}

		return sprintf(
			'<span id="member-points-balance-%1$s">%2$s</span>',
			esc_attr( absint( $item->id ) ),
			esc_html( number_format( $item->points_balance ) )
		);
	}

	/**
	 * Get member counts by status.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	private function get_status_counts(): array {
		$all_count = $this->members_service->count_members();
		$counts    = [
			'all' => $all_count,
		];

		foreach ( $this->statuses as $status_key => $status_label ) {
			$counts[ $status_key ] = $this->members_service->count_members( [ 'status' => $status_key ] );
		}

		return $counts;
	}

	/**
	 * Get an associative array ( id => link ) with the list of views available on this table.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	protected function get_views(): array {
		$counts         = $this->get_status_counts();
		$current_status = sanitize_text_field( filter_input( INPUT_GET, 'status' ) ?? 'all' );

		$views = [
			'all' => $this->get_view_link( 'all', esc_html__( 'All', 'rewardswp' ), $counts['all'], 'all' === $current_status ),
		];

		foreach ( $this->statuses as $status => $label ) {
			$views[ $status ] = $this->get_view_link(
				$status,
				$label,
				$counts[ $status ] ?? 0,
				$current_status === $status
			);
		}

		return $views;
	}

	/**
	 * Helper method to generate view links.
	 *
	 * @param string $status
	 * @param string $label
	 * @param int    $count
	 * @param bool   $current
	 *
	 * @return string
	 */
	private function get_view_link( string $status, string $label, int $count, bool $current = false ): string {
		$query_args = [ 'status' => $status === 'all' ? false : $status ];
		$url        = esc_url( add_query_arg( $query_args ) );
		$class      = $current ? 'current' : 'text-[#2271b1] hover:text-[#135e96]';

		return sprintf(
			'<a href="%s" class="%s">%s <span class="count">(%d)</span></a>',
			$url,
			$class,
			$label,
			$count
		);
	}

	/**
	 * Renders the UI for confirming member deletion.
	 *
	 * @since 1.1.0
	 * @param array $members_to_display Array of member data for display (e.g., [['id' => 1, 'name' => 'User One']]).
	 * @param array $member_ids_for_form Array of member IDs to be included in the confirmation form.
	 * @return void
	 */
	public function render_delete_confirmation_ui( array $members_to_display, array $member_ids_for_form ): void {
		$page_slug = \Awesomemotive\Rewardswp\Controllers\Admin\MembersAdminController::MENU_SLUG;
		$count     = count( $members_to_display );
		?>
		<div class="wrap rewardswp-container mt-6 mr-6 mb-0 ml-[2px]">
			<h1 class="wp-heading-inline text-2xl font-semibold mb-4">
				<?php
				echo esc_html(
					/* translators: %d: Number of members. */
					_n(
						'Delete Member',
						'Delete Members',
						$count,
						'rewardswp'
					)
				);
				?>
			</h1>

			<p class="description mb-4">
				<?php
				echo esc_html(
					/* translators: %d: Number of members. */
					_n(
						'You have specified the following member for deletion. This action cannot be undone.',
						'You have specified the following members for deletion. This action cannot be undone.',
						$count,
						'rewardswp'
					)
				);
				?>
			</p>

			<div class="notice notice-warning mb-6" style="margin-left: 0; padding: 10px;">
				<p style="margin: 0; padding:0; font-weight: bold;"><?php esc_html_e( 'The following members will be deleted:', 'rewardswp' ); ?></p>
				<ul style="list-style-type: disc; margin-left: 20px; padding: 0; margin-top: 5px;">
					<?php foreach ( $members_to_display as $member_data ) : ?>
						<li>
							<?php
								printf(
									/* translators: 1: Member ID (integer), 2: Member name/email (string). */
									esc_html__( 'ID #%1$d: %2$s', 'rewardswp' ),
									absint( $member_data['id'] ),
									esc_html( $member_data['name'] )
								);
							?>
						</li>
					<?php endforeach; ?>
				</ul>
			</div>

			<form method="post" action="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>">
				<input type="hidden" name="page" value="<?php echo esc_attr( $page_slug ); ?>" />
				<input type="hidden" name="action" value="rewardswp_process_member_deletion" />
				<?php wp_nonce_field( 'rewardswp-confirm-delete-action', 'rewardswp_confirm_delete_nonce' ); ?>

				<?php foreach ( $member_ids_for_form as $member_id ) : ?>
					<input type="hidden" name="member_ids[]" value="<?php echo absint( $member_id ); ?>" />
				<?php endforeach; ?>

				<p class="submit preserve-styles">
					<?php
					submit_button(
						esc_html__( 'Confirm Deletion', 'rewardswp' ),
						'primary delete', // Added 'delete' class for more contextual styling (often makes it red)
						'submit_delete_members',
						false,
						[
							'id'    => 'submit_delete_members', // Ensure an ID for potential styling/JS hooks
							'class' => 'preserve-styles',
						]
					);
					?>
					<a href="<?php echo esc_url( admin_url( 'admin.php?page=' . $page_slug ) ); ?>" class="button button-secondary" style="margin-left: 5px;">
						<?php esc_html_e( 'Cancel', 'rewardswp' ); ?>
					</a>
				</p>
			</form>
		</div>
		<?php
	}

	/**
	 * Renders the UI for confirming member exclusion from the program.
	 *
	 * @since 1.1.0
	 * @param array $members_to_display Array of member data for display (e.g., [['id' => 1, 'name' => 'User One']]).
	 * @param array $member_ids_for_form Array of member IDs to be included in the confirmation form.
	 * @return void
	 */
	public function render_exclude_confirmation_ui( array $members_to_display, array $member_ids_for_form ): void {
		$page_slug = \Awesomemotive\Rewardswp\Controllers\Admin\MembersAdminController::MENU_SLUG;
		$count     = count( $members_to_display );
		?>
		<div class="wrap rewardswp-container mt-6 mr-6 mb-0 ml-[2px]">
			<h1 class="wp-heading-inline text-2xl font-semibold mb-4">
				<?php
				echo esc_html(
					/* translators: %d: Number of members. */
					_n(
						'Exclude Member from Program',
						'Exclude Members from Program',
						$count,
						'rewardswp'
					)
				);
				?>
			</h1>

			<p class="description mb-4">
				<?php
				echo esc_html(
					/* translators: %d: Number of members. */
					_n(
						'You have specified the following member to be excluded from the program. This action will change their status to "Excluded".',
						'You have specified the following members to be excluded from the program. This action will change their status to "Excluded".',
						$count,
						'rewardswp'
					)
				);
				?>
			</p>

			<div class="notice notice-warning mb-6" style="margin-left: 0; padding: 10px;">
				<p style="margin: 0; padding:0; font-weight: bold;"><?php esc_html_e( 'The following members will be excluded:', 'rewardswp' ); ?></p>
				<ul style="list-style-type: disc; margin-left: 20px; padding: 0; margin-top: 5px;">
					<?php foreach ( $members_to_display as $member_data ) : ?>
						<li>
							<?php
								printf(
									/* translators: 1: Member ID (integer), 2: Member name/email (string). */
									esc_html__( 'ID #%1$d: %2$s', 'rewardswp' ),
									absint( $member_data['id'] ),
									esc_html( $member_data['name'] )
								);
							?>
						</li>
					<?php endforeach; ?>
				</ul>
			</div>

			<form method="post" action="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>">
				<input type="hidden" name="page" value="<?php echo esc_attr( $page_slug ); ?>" />
				<input type="hidden" name="action" value="rewardswp_process_member_bulk_exclude" />
				<?php wp_nonce_field( 'rewardswp-confirm-bulk-exclude-action', 'rewardswp_confirm_bulk_exclude_nonce' ); ?>

				<?php foreach ( $member_ids_for_form as $member_id ) : ?>
					<input type="hidden" name="member_ids[]" value="<?php echo absint( $member_id ); ?>" />
				<?php endforeach; ?>

				<p class="submit preserve-styles">
					<?php
					submit_button(
						esc_html__( 'Confirm Exclusion', 'rewardswp' ),
						'primary warning', // Using 'warning' class for visual cue, can be styled further
						'submit_exclude_members',
						false,
						[
							'id'    => 'submit_exclude_members',
							'class' => 'preserve-styles',
						]
					);
					?>
					<a href="<?php echo esc_url( admin_url( 'admin.php?page=' . $page_slug ) ); ?>" class="button button-secondary" style="margin-left: 5px;">
						<?php esc_html_e( 'Cancel', 'rewardswp' ); ?>
					</a>
				</p>
			</form>
		</div>
		<?php
	}
}
