<?php
/**
 * Dashboard admin view.
 *
 * @package Awesomemotive\Rewardswp\Views\Admin
 * @since 1.0.0
 */

namespace Awesomemotive\Rewardswp\Views\Admin;

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

use Awesomemotive\Rewardswp\Interfaces\ViewInterface;
use Awesomemotive\Rewardswp\Abstracts\AbstractView;
use Awesomemotive\Rewardswp\Helpers\IconHelper;
use Awesomemotive\Rewardswp\Services\DashboardService;
use Awesomemotive\Rewardswp\Views\Admin\Components\NotificationItemComponentView;
use Awesomemotive\Rewardswp\Views\Admin\Components\ChartEmptyStateComponentView;
use function Awesomemotive\Rewardswp\Helpers\svg_kses;
use function Awesomemotive\Rewardswp\Helpers\has_rewardswp_plan_level;
use function Awesomemotive\Rewardswp\Helpers\is_rewardswp_lite_plan;
use function Awesomemotive\Rewardswp\Helpers\get_option_value;
use function Awesomemotive\Rewardswp\Helpers\kses;
use function Awesomemotive\Rewardswp\Helpers\get_view_component;
use function Awesomemotive\Rewardswp\Helpers\tooltip;
use function Awesomemotive\Rewardswp\Helpers\can_access_rewardswp_feature;
use function Awesomemotive\Rewardswp\Helpers\get_site_currency_symbol;
use function Awesomemotive\Rewardswp\Helpers\format_currency;
use function Awesomemotive\Rewardswp\Helpers\get_upgrade_url;
use function Awesomemotive\Rewardswp\Helpers\add_utm_params;


/**
 * Dashboard Admin View.
 *
 * @since 1.0.0
 */
class DashboardAdminView extends AbstractView implements ViewInterface {

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

	/**
	 * Notification component view instance.
	 *
	 * @since 1.0.0
	 *
	 * @var NotificationItemComponentView
	 */
	private NotificationItemComponentView $notification_component;

	/**
	 * Dashboard service instance.
	 *
	 * @since 1.1.0
	 *
	 * @var DashboardService
	 */
	private DashboardService $dashboard_service;

	/**
	 * Chart empty state component view instance.
	 *
	 * @since 1.0.0
	 *
	 * @var ChartEmptyStateComponentView
	 */
	private ChartEmptyStateComponentView $chart_empty_state;

	/**
	 * Constructor.
	 *
	 * @since 1.1.0
	 *
	 * @param IconHelper                    $icon_helper            Icon helper instance.
	 * @param NotificationItemComponentView $notification_component Notification component view.
	 * @param DashboardService              $dashboard_service      Dashboard service instance.
	 * @param ChartEmptyStateComponentView  $chart_empty_state      Chart empty state component view.
	 */
	public function __construct(
		IconHelper $icon_helper,
		NotificationItemComponentView $notification_component,
		DashboardService $dashboard_service,
		ChartEmptyStateComponentView $chart_empty_state
	) {
		$this->icon_helper            = $icon_helper;
		$this->notification_component = $notification_component;
		$this->dashboard_service      = $dashboard_service;
		$this->chart_empty_state      = $chart_empty_state;
	}

	/**
	 * Get the store timezone in a human-readable format.
	 *
	 * @since 1.0.0
	 * @return string The formatted timezone string
	 */
	private function get_formatted_timezone(): string {
		$timezone_string = get_option( 'timezone_string' );

		if ( $timezone_string ) {
			try {
				$timezone = new \DateTimeZone( $timezone_string );
				$datetime = new \DateTime( 'now', $timezone );

				// Extract city name from timezone string (e.g., "America/New_York" -> "New York").
				$parts = explode( '/', $timezone_string );
				$city  = end( $parts );
				$city  = str_replace( '_', ' ', $city );

				// Get timezone abbreviation (e.g., EST, PST, GMT).
				$abbreviation = $datetime->format( 'T' );

				return sprintf( '%s (%s)', $city, $abbreviation );
			} catch ( \Exception $e ) {
				// Fallback to the raw timezone string if parsing fails.
				return $timezone_string;
			}
		}

		// Fallback to UTC offset if no timezone string is set.
		$offset = get_option( 'gmt_offset' );
		if ( $offset ) {
			$hours         = intval( $offset );
			$minutes       = abs( ( $offset - $hours ) * 60 );
			$offset_string = sprintf( '%+03d:%02d', $hours, $minutes );
			return 'UTC' . $offset_string;
		}

		return 'UTC';
	}

	/**
	 * Render a dashboard widget with consistent styling.
	 * Supports both collapsible and non-collapsible widgets with optional dismiss functionality.
	 *
	 * @param array    $config        Widget configuration such as classes and title.
	 * @param callable $body_callback Callback responsible for rendering the widget body.
	 */
	private function render_widget( array $config, callable $body_callback ): void {
		$config = wp_parse_args(
			$config,
			[
				'title'                     => '',
				'subtitle'                  => '', // Optional subtitle text.
				'title_dynamic'             => '', // Alpine.js expression for dynamic title.
				'header_right'              => '', // Content or callable for right side of header.
				'footer'                    => '', // Footer content or callable.
				'footer_x_show'             => '', // Alpine.js x-show expression for footer visibility.
				'heading_tag'               => 'h3',
				'collapsible'               => true, // Whether widget can collapse.
				'dismissible'               => false, // Whether widget can be dismissed.
				'dismiss_action'            => 'dismiss()', // Alpine.js action for dismiss.
				'open_by_default'           => true,
				'wrapper_class'             => 'bg-white border border-gray-900/8 rounded-xl',
				'button_class'              => 'w-full px-6 py-4 text-left flex justify-between items-center',
				'heading_class'             => 'text-lg font-semibold text-gray-900',
				'subtitle_class'            => 'text-sm text-gray-600 mt-1',
				'content_wrapper_class'     => 'p-6 space-y-4',
				'toggle_icon'               => true,
				'toggle_icon_id'            => 'chevron-right',
				'toggle_icon_classes'       => 'w-5 h-5 text-slate-500',
				'toggle_icon_wrapper_class' => 'flex-shrink-0 transition-transform duration-200',
				'toggle_icon_rotate_class'  => '-rotate-90',
				'x_data'                    => null,
			]
		);

		$heading_tag          = strtolower( (string) $config['heading_tag'] );
		$allowed_heading_tags = [ 'h2', 'h3', 'h4', 'h5', 'h6' ];
		if ( ! in_array( $heading_tag, $allowed_heading_tags, true ) ) {
			$heading_tag = 'h3';
		}

		$wrapper_classes          = trim( (string) $config['wrapper_class'] );
		$button_class             = trim( (string) $config['button_class'] );
		$heading_class            = trim( (string) $config['heading_class'] );
		$subtitle                 = trim( (string) $config['subtitle'] );
		$subtitle_class           = trim( (string) $config['subtitle_class'] );
		$content_class            = trim( (string) $config['content_wrapper_class'] );
		$toggle_icon_id           = trim( (string) $config['toggle_icon_id'] );
		$toggle_icon_classes      = trim( (string) $config['toggle_icon_classes'] );
		$toggle_icon_wrapper      = trim( (string) $config['toggle_icon_wrapper_class'] );
		$toggle_icon_rotate_class = trim( (string) $config['toggle_icon_rotate_class'] );
		$is_collapsible           = (bool) $config['collapsible'];
		$is_dismissible           = (bool) $config['dismissible'];

		$open_state = $config['open_by_default'] ? 'true' : 'false';
		$x_data     = $config['x_data'] ?: sprintf( '{ open: %s }', $open_state );

		// Handle title - check for dynamic title first.
		$title_dynamic = trim( (string) $config['title_dynamic'] );
		$title         = $config['title'];
		$title_markup  = '';

		if ( '' !== $title_dynamic ) {
			// Use Alpine.js x-text for dynamic title.
			$title_markup = '<span x-text="' . esc_attr( $title_dynamic ) . '"></span>';
		} elseif ( is_callable( $title ) ) {
			ob_start();
			call_user_func( $title, $config );
			$title_markup = ob_get_clean();
		} else {
			$title_markup = esc_html( (string) $title );
		}

		$wrapper_class_attr  = '' !== $wrapper_classes ? ' class="' . esc_attr( $wrapper_classes ) . '"' : '';
		$button_class_attr   = '' !== $button_class ? ' class="' . esc_attr( $button_class ) . '"' : '';
		$heading_class_attr  = '' !== $heading_class ? ' class="' . esc_attr( $heading_class ) . '"' : '';
		$subtitle_class_attr = '' !== $subtitle_class ? ' class="' . esc_attr( $subtitle_class ) . '"' : '';
		$content_class_attr  = '' !== $content_class ? ' class="' . esc_attr( $content_class ) . '"' : '';
		$icon_wrapper_attr   = '' !== $toggle_icon_wrapper ? ' class="' . esc_attr( $toggle_icon_wrapper ) . '"' : '';
		$toggle_icon_markup  = '';
		if ( $is_collapsible && $config['toggle_icon'] && '' !== $toggle_icon_id ) {
			$toggle_icon_markup = $this->icon_helper->get_icon( $toggle_icon_id, $toggle_icon_classes );
		}

		?>
		<div x-data="<?php echo esc_attr( $x_data ); ?>"<?php echo wp_kses( $wrapper_class_attr, kses() ); ?><?php echo $is_dismissible ? ' x-show="!dismissed"' : ''; ?>>
			<?php if ( $is_collapsible ) : ?>
				<button x-on:click="open = !open"<?php echo wp_kses( $button_class_attr, kses() ); ?> x-bind:class="{ 'border-b border-gray-200': open }">
					<div>
						<<?php echo wp_kses( $heading_tag, kses() ); ?><?php echo wp_kses( $heading_class_attr, kses() ); ?>>
							<?php echo wp_kses( $title_markup, kses() ); ?>
						</<?php echo wp_kses( $heading_tag, kses() ); ?>>
						<?php if ( '' !== $subtitle ) : ?>
							<p<?php echo wp_kses( $subtitle_class_attr, kses() ); ?>><?php echo esc_html( $subtitle ); ?></p>
						<?php endif; ?>
					</div>
					<?php if ( '' !== $toggle_icon_markup ) : ?>
						<span<?php echo wp_kses( $icon_wrapper_attr, kses() ); ?> x-bind:class="{ '<?php echo esc_js( $toggle_icon_rotate_class ); ?>': open }">
							<?php echo wp_kses( $toggle_icon_markup, svg_kses() ); ?>
						</span>
					<?php endif; ?>
				</button>
			<?php else : ?>
				<?php
				$header_right     = $config['header_right'];
				$has_header_right = ! empty( $header_right );
				?>
				<div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
					<div class="flex items-center gap-2">
						<<?php echo wp_kses( $heading_tag, kses() ); ?><?php echo wp_kses( $heading_class_attr, kses() ); ?>>
							<?php echo wp_kses( $title_markup, kses() ); ?>
						</<?php echo wp_kses( $heading_tag, kses() ); ?>>
						<?php if ( '' !== $subtitle ) : ?>
							<p<?php echo wp_kses( $subtitle_class_attr, kses() ); ?>><?php echo esc_html( $subtitle ); ?></p>
						<?php endif; ?>
						<?php
						if ( $has_header_right ) {
							if ( is_callable( $header_right ) ) {
								call_user_func( $header_right, $config );
							} else {
								echo wp_kses( $header_right, kses() );
							}
						}
						?>
					</div>
					<?php if ( $is_dismissible ) : ?>
						<button x-on:click="<?php echo wp_kses( $config['dismiss_action'], kses() ); ?>" class="text-gray-400 hover:text-gray-600 p-1">
							<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
								<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
							</svg>
						</button>
					<?php endif; ?>
				</div>
			<?php endif; ?>
			<div <?php echo wp_kses( $is_collapsible ? 'x-show="open" x-collapse' : '', kses() ); ?>>
				<div<?php echo wp_kses( $content_class_attr, kses() ); ?>>
					<?php call_user_func( $body_callback, $config ); ?>
				</div>
				<?php
				// Render footer if provided.
				$footer        = $config['footer'];
				$footer_x_show = trim( (string) $config['footer_x_show'] );
				if ( ! empty( $footer ) ) {
					echo '<div class="border-t border-slate-200 px-6 py-4"';
					if ( '' !== $footer_x_show ) {
						printf( ' x-show="%s"', esc_attr( $footer_x_show ) );
					}
					echo '>';
					if ( is_callable( $footer ) ) {
						call_user_func( $footer, $config );
					} else {
						echo wp_kses( $footer, kses() );
					}
					echo '</div>';
				}
				?>
			</div>
		</div>
		<?php
	}

	/**
	 * Render a tabbed widget card.
	 *
	 * @param array $config Configuration array with keys: title, id, default_tab, wrapper_class.
	 * @param array $tabs   Associative array of tabs with keys as tab IDs and values as arrays with 'label' and 'content'.
	 */
	private function render_tabbed_widget( array $config, array $tabs ): void {
		$config = wp_parse_args(
			$config,
			[
				'title'         => '',
				'subtitle'      => '', // Optional subtitle text (e.g., date range).
				'id'            => '',
				'default_tab'   => '', // Will use first tab if not specified.
				'wrapper_class' => 'bg-white border border-gray-900/8 rounded-xl',
			]
		);

		$widget_id   = $config['id'] ?: 'tabbed-widget-' . wp_unique_id();
		$default_tab = $config['default_tab'] ?: ( ! empty( $tabs ) ? array_key_first( $tabs ) : '' );
		?>
		<div id="<?php echo esc_attr( $widget_id ); ?>"
			x-data="{ activeTab: '<?php echo esc_attr( $default_tab ); ?>' }"
			class="<?php echo esc_attr( $config['wrapper_class'] ); ?>">

			<?php if ( $config['title'] ) : ?>
			<div class="px-6 pt-5 pb-2 flex items-baseline gap-2">
				<h3 class="text-lg leading-6 font-medium text-gray-900"><?php echo esc_html( $config['title'] ); ?></h3>
				<?php if ( $config['subtitle'] ) : ?>
					<span class="text-sm text-gray-400">&middot;</span>
					<span class="text-sm text-gray-500"><?php echo esc_html( $config['subtitle'] ); ?></span>
				<?php endif; ?>
			</div>
			<?php endif; ?>

			<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 foreach ( $tabs as $tab_id => $tab ) : ?>
					<button
						x-on:click="activeTab = '<?php echo esc_attr( $tab_id ); ?>'"
						x-bind:class="{
							'border-blue-500 text-blue-600': activeTab === '<?php echo esc_attr( $tab_id ); ?>',
							'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300': activeTab !== '<?php echo esc_attr( $tab_id ); ?>'
						}"
						class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm cursor-pointer"
					>
						<?php echo esc_html( $tab['label'] ); ?>
					</button>
					<?php endforeach; ?>
				</nav>
			</div>

			<div class="px-4 py-5 sm:p-6">
				<?php foreach ( $tabs as $tab_id => $tab ) : ?>
				<div x-show="activeTab === '<?php echo esc_attr( $tab_id ); ?>'" x-cloak>
					<?php
					if ( is_callable( $tab['content'] ) ) {
						call_user_func( $tab['content'] );
					} else {
						echo wp_kses( $tab['content'], kses() );
					}
					?>
				</div>
				<?php endforeach; ?>
			</div>
		</div>
		<?php
	}

	public function render( array $args = [] ): void {
		// Determine current plan.
		$current_plan = \Awesomemotive\Rewardswp\Helpers\get_rewardswp_plan_tier();

		// Get date range based on plan.
		$date_range_config = $this->dashboard_service->get_date_range_config( $current_plan );

		// Sanitize and validate range parameter.
		$range_raw      = filter_input( INPUT_GET, 'range', FILTER_UNSAFE_RAW );
		$range_param    = is_string( $range_raw ) ? sanitize_text_field( wp_unslash( $range_raw ) ) : '';
		$allowed_ranges = array_keys( $this->dashboard_service->get_date_ranges() );
		$selected_range = in_array( $range_param, $allowed_ranges, true ) ? $range_param : $date_range_config['default'];

		// Get KPI data and definitions.
		$kpi_data        = $this->dashboard_service->get_kpi_data( $selected_range );
		$kpi_definitions = $this->dashboard_service->get_kpis_for_plan( $current_plan );

		// Determine featured KPI.
		$featured_kpi_id = $this->dashboard_service->get_featured_kpi( $kpi_data );

		// Get charts for plan.
		$chart_definitions = $this->dashboard_service->get_charts_for_plan( $current_plan );

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

		?>
		<div
			class="rewardswp-container mt-6 mr-6 mb-0 ml-[2px] px-3"
			x-data="dashboardData"
			x-init="$nextTick(() => { initializeSparklines(); })"
		>

	<div class="flex max-w-7xl mx-auto mb-4">
		<h1 class="text-2xl font-semibold text-slate-900"><?php esc_html_e( 'Overview', 'rewardswp' ); ?></h1>

		<div class="ml-auto flex flex-col items-end gap-2 md:flex-row md:items-center md:gap-4">
				<?php
				// Get the formatted timezone.
				$store_timezone = $this->get_formatted_timezone();
				?>

				<?php if ( $date_range_config['show_picker'] ) : ?>
					<!-- Date Range Picker with Timezone -->
					<div class="flex items-center gap-3">
						<span class="text-sm text-gray-500"><?php echo esc_html( $store_timezone ); ?></span>
						<div class="relative inline-block text-left">
							<button type="button"
								x-on:click="dateRangeOpen = !dateRangeOpen"
								class="inline-flex items-center justify-center w-full px-3 py-1.5 text-sm font-medium text-gray-700 bg-white border border-gray-200 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
								<?php echo esc_html( $this->dashboard_service->get_date_ranges()[ $selected_range ]['label'] ?? __( 'Last 30 days', 'rewardswp' ) ); ?>
								<?php echo wp_kses( $this->icon_helper->get_icon( 'chevron-down', 'w-4 h-4 ml-2' ), svg_kses() ); ?>
							</button>

							<div x-show="dateRangeOpen"
								x-cloak
								x-on:click.outside="dateRangeOpen = false"
								x-transition
								class="absolute right-0 z-10 mt-1 w-40 origin-top-right rounded-md bg-white border border-gray-200 shadow-lg">
								<div class="p-1">
									<?php
									foreach ( $date_range_config['ranges'] as $range_key ) :
										$range_data = $this->dashboard_service->get_date_ranges()[ $range_key ];
										?>
										<a href="?page=rewardswp&range=<?php echo esc_attr( $range_key ); ?>"
											class="block px-3 py-2 text-sm text-gray-700 rounded-md hover:bg-gray-100 <?php echo $selected_range === $range_key ? 'bg-gray-50 font-medium' : ''; ?>">
											<?php echo esc_html( $range_data['label'] ); ?>
										</a>
									<?php endforeach; ?>
								</div>
							</div>
						</div>
					</div>
				<?php else : ?>
					<!-- Static text for Lite version (no date picker) -->
					<div class="flex items-center gap-2 text-sm text-gray-500">
						<span><?php echo esc_html( $store_timezone ); ?></span>
						<span class="text-gray-400">·</span>
						<span><?php echo esc_html( __( 'Last 30 days', 'rewardswp' ) ); ?></span>
					</div>
				<?php endif; ?>
			</div>
	</div>

	<div class="flex gap-8 gap-y-8 flex-col @container max-w-7xl mx-auto">



		<div>


			<!-- KPI Cards Section -->
			<?php if ( isset( $kpi_definitions[ $featured_kpi_id ] ) ) : ?>
				<!-- Grid layout with featured card on left, regular cards on right -->
				<div class="grid grid-cols-1 lg:grid-cols-5 gap-8">
					<!-- Featured KPI Card (Left Column - takes 2 of 5 columns) -->
					<div class="h-full lg:col-span-2">
						<?php $this->render_featured_kpi_card( $kpi_definitions[ $featured_kpi_id ], $kpi_data[ $featured_kpi_id ] ?? [] ); ?>
					</div>

					<!-- Regular KPI Cards (Right Column - takes 3 of 5 columns) -->
					<div class="grid grid-cols-1 md:grid-cols-2 lg:col-span-3 gap-4">
						<?php
						foreach ( $kpi_definitions as $kpi_id => $kpi_def ) {
							// Skip featured KPI in regular grid.
							if ( $kpi_id === $featured_kpi_id ) {
								continue;
							}
							$this->render_kpi_card( $kpi_def, $kpi_data[ $kpi_id ] ?? [] );
						}
						?>
					</div>
				</div>
			<?php else : ?>
				<!-- No featured card, display regular grid -->
				<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
					<?php
					foreach ( $kpi_definitions as $kpi_id => $kpi_def ) {
						$this->render_kpi_card( $kpi_def, $kpi_data[ $kpi_id ] ?? [] );
					}
					?>
				</div>
			<?php endif; ?>
		</div>


		<div class="grid grid-cols-1 md:grid-cols-2 gap-8">

			<!-- Left Column -->
			<div class="space-y-6">
				<!-- Tabbed Trends Widget -->
				<?php
				$points_chart_def  = $chart_definitions['points-activity-chart'] ?? null;
				$points_chart_data = $points_chart_def ? $this->dashboard_service->get_chart_data( 'points-activity-chart', $selected_range ) : [];

				$referral_chart_def  = $chart_definitions['referral-revenue'] ?? null;
				$referral_chart_data = $referral_chart_def ? $this->dashboard_service->get_chart_data( 'referral-revenue', $selected_range ) : [];

				$tabs = [];

				if ( $points_chart_def ) {
					$tabs['points'] = [
						'label'   => __( 'Points', 'rewardswp' ),
						'content' => fn() => $this->render_chart( $points_chart_def, $points_chart_data, true ),
					];
				}

				if ( $referral_chart_def ) {
					$tabs['referrals'] = [
						'label'   => __( 'Referrals', 'rewardswp' ),
						'content' => fn() => $this->render_chart( $referral_chart_def, $referral_chart_data, true ),
					];
				}

				if ( ! empty( $tabs ) ) {
					$this->render_tabbed_widget(
						[
							'title'    => __( 'Trends', 'rewardswp' ),
							'subtitle' => $this->dashboard_service->get_date_ranges()[ $selected_range ]['label'] ?? __( 'Last 30 days', 'rewardswp' ),
							'id'       => 'activity-trends',
						],
						$tabs
					);
				}
				?>

				<?php
				/**
				 * Program Insights Tabbed Widget
				 */
				$top_referrers    = $this->dashboard_service->get_top_referrers( $selected_range, 5 );
				$top_rewards      = $this->dashboard_service->get_top_redeemed_rewards( $selected_range, 5 );
				$date_range_label = $this->dashboard_service->get_date_ranges()[ $selected_range ]['label'] ?? __( 'Last 30 days', 'rewardswp' );

				$this->render_tabbed_widget(
					[
						'title'    => __( 'Program Insights', 'rewardswp' ),
						'subtitle' => $date_range_label,
						'id'       => 'program-insights',
					],
					[
						'referrers' => [
							'label'   => __( 'Top Referrers', 'rewardswp' ),
							'content' => fn() => $this->render_top_referrers_list( $top_referrers ),
						],
						'rewards'   => [
							'label'   => __( 'Most Redeemed', 'rewardswp' ),
							'content' => fn() => $this->render_top_rewards_list( $top_rewards ),
						],
					]
				);
				?>

				<?php
				/**
				 * Help & Support Widget
				 */
				$icon_helper = $this->icon_helper;
				$this->render_widget(
					[
						'title' => esc_html__( 'Help & Support', 'rewardswp' ),
					],
					static function () use ( $icon_helper ): void {
						?>
						<nav class="divide-y divide-slate-100">
							<a href="<?php echo esc_url( add_utm_params( 'https://rewardswp.com/start-here/', 'WordPress', 'dashboard-help-widget', '', 'getting_started' ) ); ?>" target="_blank" rel="noopener noreferrer" class="flex items-center gap-3 py-3 text-slate-700 hover:text-blue-600 transition-colors">
							<?php echo wp_kses( $icon_helper->get_icon( 'compass', 'size-6 text-slate-400', 'bold' ), svg_kses() ); ?>
								<span class="text-sm font-medium"><?php esc_html_e( 'Getting Started', 'rewardswp' ); ?></span>
							</a>
							<a href="<?php echo esc_url( add_utm_params( is_rewardswp_lite_plan() ? 'https://rewardswp.com/lite-support/' : 'https://rewardswp.com/account/support/', 'WordPress', 'dashboard-help-widget', '', 'support_ticket' ) ); ?>" target="_blank" rel="noopener noreferrer" class="flex items-center gap-3 py-3 text-slate-700 hover:text-blue-600 transition-colors">
								<?php echo wp_kses( $icon_helper->get_icon( 'chat-bubble', 'size-6 text-slate-400', 'bold' ), svg_kses() ); ?>
								<span class="text-sm font-medium"><?php esc_html_e( 'Submit a Support Ticket', 'rewardswp' ); ?></span>
							</a>
							<a href="<?php echo esc_url( add_utm_params( 'https://rewardswp.com/docs/', 'WordPress', 'dashboard-help-widget', '', 'documentation' ) ); ?>" target="_blank" rel="noopener noreferrer" class="flex items-center gap-3 py-3 text-slate-700 hover:text-blue-600 transition-colors">
								<?php echo wp_kses( $icon_helper->get_icon( 'book', 'size-6 text-slate-400', 'bold' ), svg_kses() ); ?>
								<span class="text-sm font-medium"><?php esc_html_e( 'Documentation', 'rewardswp' ); ?></span>
							</a>
							<?php if ( is_rewardswp_lite_plan() ) : ?>
							<a href="<?php echo esc_url( get_upgrade_url( 'upgrade_to_pro', 'dashboard-help-widget' ) ); ?>" target="_blank" rel="noopener noreferrer" class="flex items-center gap-3 py-3 text-slate-700 hover:text-blue-600 transition-colors">
								<?php echo wp_kses( $icon_helper->get_icon( 'star-burst', 'size-6 text-slate-400', 'bold' ), svg_kses() ); ?>
								<span class="text-sm font-medium"><?php esc_html_e( 'Upgrade to Pro', 'rewardswp' ); ?></span>
							</a>
							<?php endif; ?>
						</nav>

						<?php if ( is_rewardswp_lite_plan() ) : ?>
						<div class="mt-4 -mx-6 -mb-6 px-6 py-4 bg-amber-50/50 border-t border-amber-100/50">
							<a href="https://rewardswp.com/go/review/" target="_blank" rel="noopener noreferrer" class="flex items-center justify-between">
								<span class="text-sm font-medium text-blue-600">
									<?php esc_html_e( 'Rate us 5 stars', 'rewardswp' ); ?>
									<span class="ml-1">&rarr;</span>
								</span>
								<div class="flex gap-0.5 text-amber-400">
									<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
									<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
									<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
									<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
									<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
								</div>
							</a>
						</div>
						<?php endif; ?>
						<?php
					}
				);
		?>

				<?php if ( is_rewardswp_lite_plan() ) : ?>
					<?php
					$icon_helper = $this->icon_helper;
					$this->render_widget(
						[
							'title'       => esc_html__( 'Upgrade to Pro to Unlock Advanced Loyalty Features', 'rewardswp' ),
							'collapsible' => false,
						],
						static function () use ( $icon_helper ): void {
							?>
						<div class="grid grid-cols-2 gap-x-6 gap-y-3 mb-6">
							<div class="flex items-center gap-2">
								<?php echo wp_kses( $icon_helper->get_icon( 'check-circle', 'size-5 text-emerald-500' ), svg_kses() ); ?>
								<span class="text-sm text-slate-700"><?php esc_html_e( 'Points expiration', 'rewardswp' ); ?></span>
							</div>
							<div class="flex items-center gap-2">
								<?php echo wp_kses( $icon_helper->get_icon( 'check-circle', 'size-5 text-emerald-500' ), svg_kses() ); ?>
								<span class="text-sm text-slate-700"><?php esc_html_e( 'Friend rewards for referrals', 'rewardswp' ); ?></span>
							</div>
							<div class="flex items-center gap-2">
								<?php echo wp_kses( $icon_helper->get_icon( 'check-circle', 'size-5 text-emerald-500' ), svg_kses() ); ?>
								<span class="text-sm text-slate-700"><?php esc_html_e( 'Free shipping rewards', 'rewardswp' ); ?></span>
							</div>
							<div class="flex items-center gap-2">
								<?php echo wp_kses( $icon_helper->get_icon( 'check-circle', 'size-5 text-emerald-500' ), svg_kses() ); ?>
								<span class="text-sm text-slate-700"><?php esc_html_e( 'Data export', 'rewardswp' ); ?></span>
							</div>
							<div class="flex items-center gap-2">
								<?php echo wp_kses( $icon_helper->get_icon( 'check-circle', 'size-5 text-emerald-500' ), svg_kses() ); ?>
								<span class="text-sm text-slate-700"><?php esc_html_e( 'Custom points branding', 'rewardswp' ); ?></span>
							</div>
							<div class="flex items-center gap-2">
								<?php echo wp_kses( $icon_helper->get_icon( 'check-circle', 'size-5 text-emerald-500' ), svg_kses() ); ?>
								<span class="text-sm text-slate-700"><?php esc_html_e( 'Priority support', 'rewardswp' ); ?></span>
							</div>
							<div class="flex items-center gap-2">
								<?php echo wp_kses( $icon_helper->get_icon( 'check-circle', 'size-5 text-emerald-500' ), svg_kses() ); ?>
								<span class="text-sm text-slate-700"><?php esc_html_e( 'Advanced reporting', 'rewardswp' ); ?></span>
							</div>
							<div class="flex items-center gap-2">
								<?php echo wp_kses( $icon_helper->get_icon( 'check-circle', 'size-5 text-emerald-500' ), svg_kses() ); ?>
								<span class="text-sm text-slate-700"><?php esc_html_e( 'Unlimited redemption options', 'rewardswp' ); ?></span>
							</div>
						</div>

						<div class="flex flex-col items-center gap-3">
							<a href="<?php echo esc_url( get_upgrade_url( 'upgrade_to_pro', 'dashboard-upgrade-widget' ) ); ?>" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center px-6 py-2.5 bg-blue-600 text-white text-sm font-semibold rounded-lg hover:bg-blue-700 transition-colors">
								<?php esc_html_e( 'Upgrade to Pro', 'rewardswp' ); ?>
							</a>
							<a href="https://rewardswp.com/pricing/?utm_source=WordPress&utm_campaign=liteplugin&utm_medium=dashboard-upgrade-widget" target="_blank" rel="noopener noreferrer" class="text-sm text-blue-600 hover:text-blue-700 transition-colors">
								<?php esc_html_e( 'Learn more about all features', 'rewardswp' ); ?> &rarr;
							</a>
						</div>
							<?php
						}
					);
					?>
				<?php endif; ?>

			</div>

			<?php
			/**
			 * Right Column
			 */
			?>
			<div class="space-y-8">
				<?php
				/**
				 * Things to do next Widget
				 */
				?>
				<?php $icon_helper = $this->icon_helper; ?>
				<div x-data="setupTasks" x-show="!dismissed" class="bg-white border border-gray-900/8 rounded-xl">
					<div class="px-6 py-4 flex justify-between items-center border-b border-gray-200">
						<div class="flex items-center gap-2">
							<h3 class="text-lg font-semibold text-gray-900"><?php esc_html_e( 'Things to do next', 'rewardswp' ); ?></h3>
							<span x-show="remainingCount > 0" class="inline-flex items-center justify-center px-2 py-0.5 text-xs font-medium bg-gray-100 text-gray-600 rounded-full" x-text="remainingCount"></span>
						</div>
						<div class="relative">
							<button x-on:click="menuOpen = !menuOpen" class="cursor-pointer p-1.5 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-md transition-colors">
								<?php echo wp_kses( $icon_helper->get_icon( 'menu-kebab', 'w-4 h-4', 'bold' ), svg_kses() ); ?>
							</button>
							<div
								x-show="menuOpen"
								x-cloak
								x-on:click.outside="menuOpen = false"
								x-transition:enter="transition ease-out duration-100"
								x-transition:enter-start="transform opacity-0 scale-95"
								x-transition:enter-end="transform opacity-100 scale-100"
								x-transition:leave="transition ease-in duration-75"
								x-transition:leave-start="transform opacity-100 scale-100"
								x-transition:leave-end="transform opacity-0 scale-95"
								class="absolute right-0 z-50 mt-1 w-40 origin-top-right bg-white rounded-md shadow-lg border border-gray-200 focus:outline-none"
							>
								<div class="p-1">
									<button
										x-on:click="dismiss(); menuOpen = false"
										class="cursor-pointer group w-full text-left"
									>
										<span class="px-3 py-2 text-sm text-gray-700 block rounded-md group-hover:bg-gray-100"><?php esc_html_e( 'Hide this', 'rewardswp' ); ?></span>
									</button>
								</div>
							</div>
						</div>
					</div>

					<?php
					/**
					 * Task List
					 */
					?>
					<div class="divide-y divide-gray-200">
						<template x-for="(task, index) in tasks" x-bind:key="task.id">
							<a x-bind:href="task.action.url" x-on:click="markTaskComplete(task.id)" class="block py-4 px-6 hover:bg-gray-50 transition-colors" x-bind:class="{ 'rounded-b-xl': index === tasks.length - 1 }">
								<div class="flex items-center gap-3">

									<div class="shrink-0">

										<div x-show="task.status === 'incomplete'" class="size-5 rounded-full border-2 border-gray-300"></div>

										<div x-show="task.status === 'complete'" class="text-blue-600 flex items-center justify-center">
											<?php echo wp_kses( $icon_helper->get_icon( 'check-circle', 'size-5' ), svg_kses() ); ?>
										</div>
									</div>


									<div class="flex-1 min-w-0">
										<h4 class="text-sm font-medium" x-bind:class="task.status === 'complete' ? 'text-gray-500' : 'text-gray-900'" x-text="task.title"></h4>
										<p class="text-sm text-gray-500 mt-0.5" x-text="task.description"></p>
									</div>
								</div>
							</a>
						</template>
					</div>

				</div>

				<?php
				/**
				 * Recent Activity Widget
				 */
				$activities         = $this->dashboard_service->get_recent_activity( 10 );
				$empty_state_markup = get_view_component(
					'empty-state',
					[
						'icon'        => 'time-rest',
						'title'       => __( 'No activity yet', 'rewardswp' ),
						'description' => __( 'Once members start using your rewards program, their recent activity will appear here.', 'rewardswp' ),
					]
				);
				$this->render_widget(
					[
						'title' => esc_html__( 'Recent Activity', 'rewardswp' ),
					],
					static function () use ( $activities, $empty_state_markup ): void {
						$has_activities = ! empty( $activities );
						?>

						<?php if ( ! $has_activities ) : ?>
							<?php echo $empty_state_markup; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Content escaped in EmptyStateComponentView ?>
						<?php else : ?>
							<div class="relative">
								<div class="flow-root">
									<ul role="list" class="-mb-2">
										<?php
										foreach ( $activities as $index => $activity ) :
											$is_last  = $index === count( $activities ) - 1;
											$user_url = $activity['user_url'] ?? '#';
											?>
											<li>
												<div class="relative pb-5">
													<?php if ( ! $is_last ) : ?>
														<span class="absolute left-1.5 top-3 -ml-px h-full w-0.5 bg-gray-200" aria-hidden="true"></span>
													<?php endif; ?>

													<div class="relative flex items-start space-x-3">
														<div class="relative pt-1">
															<div class="h-3 w-3 rounded-full <?php echo esc_attr( $activity['dot_color'] ); ?> ring-4 ring-white"></div>
														</div>

														<div class="min-w-0 flex-1 -mt-0.5">
															<div>
																<div class="text-sm text-gray-900">
																	<a href="<?php echo esc_url( $user_url ); ?>" class="font-medium text-blue-600 hover:text-blue-800 hover:underline"><?php echo esc_html( $activity['user'] ); ?></a>
																	<span class="text-gray-600 ml-0.5"><?php echo esc_html( $activity['description'] ); ?></span>
																	<?php if ( ! empty( $activity['meta'] ) ) : ?>
																		<span class="text-gray-400 ml-0.5">(<?php echo esc_html( $activity['meta'] ); ?>)</span>
																	<?php endif; ?>
																	<?php if ( ! empty( $activity['order_id'] ) && ! empty( $activity['order_url'] ) ) : ?>
																		<a href="<?php echo esc_url( $activity['order_url'] ); ?>" class="text-blue-600 hover:text-blue-800 hover:underline">
																			<?php
																			/* translators: %d: Order ID. */
																			printf( esc_html__( 'order #%d', 'rewardswp' ), (int) $activity['order_id'] );
																			?>
																		</a>
																	<?php endif; ?>
																</div>
																<p class="mt-0.5 text-xs text-gray-400">
																	<?php echo esc_html( $activity['time'] ); ?>
																</p>
															</div>
														</div>
													</div>
												</div>
											</li>
										<?php endforeach; ?>
									</ul>
								</div>
							</div>
						<?php endif; ?>
						<?php
					}
				);
		?>

				<?php
				/**
				 * Notifications Widget
				 */
				$notification_component   = $this->notification_component;
				$notification_empty_state = fn() => get_view_component(
					'empty-state',
					[
						'icon'        => 'message-check',
						'title'       => __( 'No new notifications', 'rewardswp' ),
						'description' => __( 'You\'re all caught up! Important updates will appear here.', 'rewardswp' ),
					]
				);
				$this->render_widget(
					[
						'title'         => esc_html__( 'Notifications', 'rewardswp' ),
						'collapsible'   => false,
						'x_data'        => '{ notifications: $store.notificationsDrawer }',
						'header_right'  => static function () {
							?>
							<span x-show="notifications.activeNotifications.length > 0" class="inline-flex items-center justify-center px-2 py-0.5 text-xs font-medium bg-gray-100 text-gray-600 rounded-full" x-text="notifications.activeNotifications.length"></span>
							<?php
						},
						'footer'        => static function () {
							?>
							<button
								type="button"
								class="inline-flex items-center text-sm font-semibold text-blue-600 transition hover:text-blue-700"
								x-on:click.prevent="notifications.open()"
							>
								<span x-text="notifications.moreNotificationsLabel()"></span>
							</button>
							<?php
						},
						'footer_x_show' => 'notifications.hasNotifications',
					],
					static function () use ( $notification_component, $notification_empty_state ) {
						?>
						<template x-if="!notifications.hasNotifications">
							<div>
								<?php echo wp_kses( $notification_empty_state(), kses() ); ?>
							</div>
						</template>
						<template x-for="(notification, index) in notifications.widgetNotifications" x-bind:key="notification.id">
							<div
								x-show="!notification.dismissed"
								x-collapse
								x-bind:style="notification.dismissOrder >= 0 ? `transition-delay: ${notification.dismissOrder * 50}ms` : ''"
							>
								<div
									class="pb-4 transition-opacity duration-200 ease-out"
									x-bind:class="{
										'opacity-0': notification.dismissed,
										'border-b border-gray-100': index < notifications.widgetNotifications.filter(n => !n.dismissed).length - 1
									}"
								>
									<?php
									$notification_component->render(
										[
											'mode'         => 'full',
											'show_divider' => false,
											'alpine_var'   => 'notification',
											'alpine_action' => 'notifications.dismissNotification',
										]
									);
									?>
								</div>
							</div>
						</template>
						<?php
					}
				);
		?>

				</div>

			</div>

		</div>

	</div>

	<script>
	const rewardswpCurrencySymbol = '<?php echo esc_js( get_site_currency_symbol() ); ?>';
	<?php $rwp_currency_position = \Awesomemotive\Rewardswp\Helpers\get_currency_position(); ?>
	const rewardswpCurrencyAfter = <?php echo ( 'after' === ( $rwp_currency_position['position'] ?? 'before' ) ) ? 'true' : 'false'; ?>;
	const rewardswpCurrencySpace = <?php echo ! empty( $rwp_currency_position['space'] ) ? 'true' : 'false'; ?>;
	// Assemble a symbol and amount honoring the store's currency position (e.g. "5 €" vs "€5").
	function rewardswpMoney( amount ) {
		const sep = rewardswpCurrencySpace ? ' ' : '';
		return rewardswpCurrencyAfter
			? amount + sep + rewardswpCurrencySymbol
			: rewardswpCurrencySymbol + sep + amount;
	}
	document.addEventListener('alpine:init', () => {
		Alpine.data('dashboardData', () => ({
			dateRangeOpen: false,
			selectedRange: '<?php echo esc_js( $selected_range ); ?>',

			initializeSparklines() {
				// Initialize ApexCharts sparklines for KPI cards.
				if (typeof ApexCharts === 'undefined') {
					console.warn('ApexCharts not loaded');
					return;
				}

				document.querySelectorAll('.sparkline-container[data-sparkline]').forEach(el => {
					const data = JSON.parse(el.dataset.sparkline);
					if (data && data.length > 0) {
						this.renderSparkline(el, data);
					}
				});

				// Initialize full charts.
				this.initializeCharts();
			},

			initializeCharts() {
				// Initialize full-size charts for the dashboard.
				document.querySelectorAll('.chart-container[data-chart-config]').forEach(el => {
					const config = JSON.parse(el.dataset.chartConfig);
					if (config && config.data) {
						this.renderChart(el, config);
					}
				});
			},

			renderChart(container, config) {
				const { type, data, series } = config;
				const chartType = type;
				const isReferralRevenue = container.id.includes('referral-revenue');
				const isPointsActivity = container.id.includes('points-activity');

				// Prepare series data based on chart type.
				let chartSeries = [];
				let chartOptions = {};

				if (chartType === 'bar-line' && isReferralRevenue) {
					// Referral Revenue: Bar chart with line overlay.
					chartSeries = data.datasets.map((dataset, index) => ({
						name: dataset.name,
						type: dataset.type || (index === 0 ? 'bar' : 'line'),
						data: dataset.data,
						color: dataset.color
					}));

					// Dynamic column width based on data points.
					const dataPointCount = data.labels?.length || 0;
					let columnWidth = '50%';
					if (dataPointCount <= 2) {
						columnWidth = '15%';
					} else if (dataPointCount <= 5) {
						columnWidth = '30%';
					} else if (dataPointCount <= 10) {
						columnWidth = '40%';
					}

					chartOptions = {
						chart: {
							type: 'line',
							height: 256,
							toolbar: {
								show: false
							},
							zoom: {
								enabled: true,
								type: 'x',
								autoScaleYaxis: true
							}
						},
						stroke: {
							width: [0, 2],
							curve: 'smooth'
						},
						plotOptions: {
							bar: {
								columnWidth: columnWidth,
								borderRadius: 5,
								borderRadiusApplication: 'end'
							}
						},
						//colors: ['#3B82F6', '#94A3B8'],
						fill: {
							opacity: [1, 0.9]
						},
						dataLabels: {
							enabled: false
						},

						xaxis: {
							categories: data.labels,
							tickAmount: 7,
							labels: {
								rotate: 0,
								rotateAlways: false,
							},
							tooltip: {
								enabled: false
							}
						},
						yaxis: {
							title: {
								text: 'Revenue (' + rewardswpCurrencySymbol + ')'
							},
							labels: {
								formatter: function (val) {
									return rewardswpMoney(val.toFixed(0));
								}
							}
						},
						tooltip: {
							shared: true,
							intersect: false,
							x: {
								show: false
							},
							custom: function({ series, seriesIndex, dataPointIndex, w }) {
								const revenue = series[0][dataPointIndex];
								const avg = series[1] ? series[1][dataPointIndex] : 0;
								const referrals = data.tooltip_data?.completed_referrals?.[dataPointIndex] || 0;
								const label = data.labels[dataPointIndex];

								return '<div class="apexcharts-tooltip-custom min-w-3xs">' +
									'<div class="px-3 py-2 bg-white">' +
									'<div class="text-xs text-gray-600 mb-1">' + label + '</div>' +
									'<div class="text-sm font-semibold text-gray-900 mb-0.5">' + rewardswpMoney(revenue.toFixed(0)) + ' <?php echo esc_js( __( 'referral revenue', 'rewardswp' ) ); ?></div>' +
									'<div class="text-xs text-gray-600"><?php echo esc_js( __( 'Completed referrals:', 'rewardswp' ) ); ?> ' + referrals + '</div>' +
									'</div>' +
									'</div>';
							}
						},
						legend: {
						//	show: false.
						},
						grid: {
							borderColor: '#f3f4f6',
							xaxis: {
								lines: {
									show: false
								}
							}
						}
					};
				} else if (chartType === 'multi-line' && isPointsActivity) {
					// Points Activity: Dual line chart.
					chartSeries = data.datasets.map(dataset => ({
						name: dataset.name,
						type: 'line',
						data: dataset.data,
						color: dataset.color
					}));

					chartOptions = {
						chart: {
							type: 'line',
							height: 256,
							toolbar: {
								show: false
							},
							zoom: {
								enabled: true,
								type: 'x',
								autoScaleYaxis: true
							}
						},
						stroke: {
							width: 2,
							curve: 'smooth'
						},
						colors: ['#2563eb', '#fb923c'],
						dataLabels: {
							enabled: false
						},
						xaxis: {
							categories: data.labels,
							tickAmount: 7,
							labels: {
								rotate: 0,
								rotateAlways: false,
							},
							tooltip: {
								enabled: false
							}
						},
						yaxis: {
							title: {
								text: 'Points'
							},
							min: 0
						},
						tooltip: {
							shared: true,
							intersect: false,
							custom: function({ series, seriesIndex, dataPointIndex, w }) {
								const earned = series[0][dataPointIndex];
								const redeemed = series[1][dataPointIndex];
								const rr = earned > 0 ? ((redeemed / earned) * 100).toFixed(1) : 0;
								const label = data.labels[dataPointIndex];

								return '<div class="apexcharts-tooltip-custom min-w-3xs">' +
									'<div class="px-3 py-2 bg-white">' +
									'<div class="text-xs text-gray-600 mb-1">' + label + '</div>' +
									'<div class="text-sm text-gray-900"><?php echo esc_js( __( 'Earned:', 'rewardswp' ) ); ?> ' + earned.toLocaleString() + ' <?php echo esc_js( __( 'pts', 'rewardswp' ) ); ?></div>' +
									'<div class="text-sm text-gray-900"><?php echo esc_js( __( 'Redeemed:', 'rewardswp' ) ); ?> ' + redeemed.toLocaleString() + ' <?php echo esc_js( __( 'pts', 'rewardswp' ) ); ?></div>' +
									'<div class="text-xs text-gray-500 mt-1"><?php echo esc_js( __( 'RR today:', 'rewardswp' ) ); ?> ' + rr + '%</div>' +
									'</div>' +
									'</div>';
							}
						},
						legend: {
						//	show: false.
						},
						grid: {
							borderColor: '#f3f4f6',
							xaxis: {
								lines: {
									show: false
								}
							}
						}
					};
				} else {
					// Default line chart.
					chartSeries = data.datasets.map(dataset => ({
						name: dataset.name,
						data: dataset.data
					}));

					chartOptions = {
						chart: {
							type: 'line',
							height: 256,
							toolbar: {
								show: false
							},
							zoom: {
								enabled: true,
								type: 'x',
								autoScaleYaxis: true
							}
						},
						stroke: {
							width: 2,
							curve: 'smooth'
						},
						dataLabels: {
							enabled: false
						},
						xaxis: {
							categories: data.labels
						},
						grid: {
							borderColor: '#f3f4f6'
						}
					};
				}

				// Create and render the chart.
				chartOptions.series = chartSeries;

				// Add double-click to reset zoom.
				let chart = null;
				chartOptions.chart.events = {
					click: function(event) {
						if (event.detail === 2 && chart) {
							chart.resetSeries();
						}
					}
				};

				chart = new ApexCharts(container, chartOptions);
				chart.render();
			},

			renderSparkline(container, data) {
				const color = container.dataset.sparklineColor || '#3B82F6';
				const chartType = container.dataset.sparklineType || 'area';
				const isBarChart = chartType === 'bar';
				// Use custom height if provided, or taller height for featured sparkline, or default 64.
				const isFeatured = container.id && container.id.includes('featured-sparkline');
				const chartHeight = container.dataset.sparklineHeight ? parseInt(container.dataset.sparklineHeight, 10) : (isFeatured ? 192 : 64);

				// Check if this is rewards-applied-revenue sparkline with enhanced data.
				const isRevenueSparkline = container.id && container.id.includes('rewards-applied-revenue');
				const hasEnhancedData = isRevenueSparkline && data.length > 0 && typeof data[0] === 'object' && 'refunds' in data[0];

				const options = {
					theme: {
						mode: 'light',
						palette: 'palette1'
					},
					chart: {
						type: chartType === 'line' ? 'area' : chartType, // Convert 'line' to 'area' for better fill
						height: chartHeight,
						sparkline: {
							enabled: true,
						},
						animations: {
							enabled: false
						}
					},
					series: [{
						data: data
					}],
					stroke: {
						curve: 'smooth',
						width: isBarChart ? 0 : 2
					},
					colors: [color],
					fill: {
						type: isBarChart ? 'solid' : 'gradient',
						gradient: {
							shadeIntensity: 1,
							opacityFrom: 0.4,
							opacityTo: 0.1,
							stops: [0, 100]
						}
					},
					plotOptions: {
						bar: {
							columnWidth: '80%',
							borderRadius: 4,
							borderRadiusApplication: 'end',
							distributed: false,
							rangeBarOverlap: false
						}
					},
					dataLabels: {
						enabled: false
					},
					grid: {
						show: false,
						padding: {
							top: 20,
							bottom: 0,
							left: 0,
							right: 0
						}
					},
					yaxis: {
						min: 0,
						max: function(max) {
							return max * 1.2; // Add 20% padding at top
						},
						show: false,
						crosshairs: {
							show: false
						}
					},
					xaxis: {
						show: false,
						crosshairs: {
							show: false
						}
					},

					tooltip: {
						enabled: true,
						x: {
							show: false
						},
						custom: hasEnhancedData ? function({series, seriesIndex, dataPointIndex, w}) {
							// Enhanced tooltip for rewards-applied-revenue.
							const dataPoint = w.globals.initialSeries[seriesIndex].data[dataPointIndex];
							const revenue = dataPoint.y;
							const refunds = dataPoint.refunds || 0;
							const date = dataPoint.date;
							const net = revenue - refunds;

							return '<div class="apexcharts-tooltip-custom min-w-3xs">' +
								'<div class="px-3 py-2 bg-white">' +
								'<div class="text-xs text-gray-600 mb-1">' + date + '</div>' +
								'<div class="text-sm font-semibold text-gray-900 mb-0.5">' + rewardswpMoney(revenue.toLocaleString()) + '</div>' +
								'<div class="text-xs text-gray-600 mb-0.5"><?php echo esc_js( __( 'Refunds posted today:', 'rewardswp' ) ); ?> ' + rewardswpMoney(refunds.toLocaleString()) + '</div>' +
								'<div class="text-xs text-gray-500"><?php echo esc_js( __( 'Net excl. tax & shipping', 'rewardswp' ) ); ?></div>' +
								'</div>' +
								'</div>';
						} : undefined,
						y: {
							formatter: hasEnhancedData ? undefined : function(value, {series, seriesIndex, dataPointIndex, w}) {
								if (value === undefined || value === null) {
									return '';
								}

								// Determine value type based on container data attributes and ID.
								const kpiType = container.closest('[data-kpi-type]')?.dataset.kpiType;
								const containerId = container.id;

								// Check for specific KPI types.
								if (kpiType === 'currency' || containerId.includes('rewards-applied-revenue')) {
									// Format as currency.
									return rewardswpMoney(Math.round(value).toLocaleString());
								} else if (kpiType === 'percentage' || containerId.includes('orders-using-rewards')) {
									// Format as percentage.
									return Math.round(value) + '%';
								} else if (containerId.includes('points-activity')) {
									// Points activity shows redemption rate percentages.
									return value.toFixed(1) + '%';
								} else if (kpiType === 'percentage_with_count' || containerId.includes('active-members')) {
									// Active members shows daily active counts.
									return Math.round(value) + ' members';
								} else if (containerId.includes('referrals')) {
									// Referrals shows count.
									return Math.round(value) + ' referrals';
								} else {
									// Default: format as number.
									return Math.round(value).toLocaleString();
								}
							},
							title: {
								formatter: function() {
									return '';
								}
							}
						},
						marker: {
							show: false
						}
					}
				};

				const chart = new ApexCharts(container, options);
				chart.render().then(() => {
					// Add left-to-right reveal animation if requested.
					if (container.dataset.sparklineAnimate === 'true') {
						container.classList.add('animate-reveal-ltr');
					}
				});

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

	/**
	 * Render a featured KPI card (larger, prominent display).
	 *
	 * @since 1.0.0
	 * @param array $kpi_def KPI definition
	 * @param array $kpi_data KPI data
	 */
	private function render_featured_kpi_card( array $kpi_def, array $kpi_data ): void {
		// Check if we should show empty state using the service helper.
		$empty_state_config = $this->dashboard_service->get_empty_state_for_kpi( $kpi_def['id'] ?? '', $kpi_data );
		$show_empty_state   = null !== $empty_state_config;
		?>
		<div class="bg-white border border-gray-900/8 rounded-xl p-6 h-full flex flex-col"
			data-kpi-type="<?php echo esc_attr( $kpi_def['value_type'] ?? '' ); ?>">
			<div class="flex items-start justify-between">
				<div class="flex-1">
					<h3 class="text-lg text-gray-900 inline-block border-b border-dashed border-gray-300 cursor-help"
						data-tippy-content="<?php echo esc_attr( is_array( $kpi_def['tooltip'] ) ? tooltip( $kpi_def['tooltip'] ) : $kpi_def['tooltip'] ); ?>">
						<?php echo esc_html( $kpi_def['title'] ); ?>
					</h3>

					<?php if ( $show_empty_state ) : ?>
						<?php
						$empty_config = $empty_state_config; // Use already-fetched config.
						?>
						<!-- Empty State with blurred chart background -->
						<div class="mt-4">
							<div class="flex items-baseline gap-3">
								<p class="text-3xl font-bold text-gray-900">
									<?php echo esc_html( $empty_config['empty_value'] ?? '—' ); ?>
								</p>
								<?php if ( ! empty( $empty_config['empty_delta'] ) ) : ?>
									<span class="text-sm font-medium text-gray-400">
										<?php echo esc_html( $empty_config['empty_delta'] ); ?>
									</span>
								<?php endif; ?>
							</div>
						</div>
						<div class="mt-2">
							<?php
							$this->chart_empty_state->render(
								[
									'title'       => $empty_config['message'] ?? __( 'Collecting data...', 'rewardswp' ),
									'description' => $empty_config['description'] ?? '',
								]
							);
							?>
						</div>
					<?php else : ?>
						<!-- Value Display -->
						<div class="mt-4">
							<div class="flex items-baseline gap-3">
								<p class="text-3xl font-bold text-gray-900">
									<?php echo wp_kses_post( $kpi_data['value_html'] ?? '0' ); ?>
								</p>
								<?php if ( ! empty( $kpi_data['delta'] ) && can_access_rewardswp_feature( 'dashboard_deltas' ) ) : ?>
									<span class="text-sm font-medium <?php echo esc_attr( $kpi_data['delta_class'] ?? 'text-gray-500' ); ?>">
										<?php echo esc_html( $kpi_data['delta'] ); ?>
									</span>
								<?php endif; ?>
							</div>

							<?php if ( ! empty( $kpi_def['subline'] ) && $kpi_def['subline']['show'] ) : ?>
								<p class="text-sm text-gray-500 mt-2">
									<?php
									$subline_text = $kpi_def['subline']['text'];
									// Replace template variables with actual values.
									if ( ! empty( $kpi_data['total_members'] ) ) {
										$subline_text = str_replace( '{total}', $kpi_data['total_members'], $subline_text );
									}
									if ( isset( $kpi_data['rate'] ) ) {
										$subline_text = str_replace( '{rate}', $kpi_data['rate'], $subline_text );
									}
									if ( ! empty( $kpi_data['median_time'] ) ) {
										$subline_text = str_replace( '{median_time}', $kpi_data['median_time'], $subline_text );
									}
									if ( isset( $kpi_data['rewarded_count'] ) ) {
										$subline_text = str_replace( '{rewarded_count}', number_format_i18n( $kpi_data['rewarded_count'] ), $subline_text );
									}
									if ( isset( $kpi_data['total_count'] ) ) {
										$subline_text = str_replace( '{total_count}', number_format_i18n( $kpi_data['total_count'] ), $subline_text );
									}
									echo esc_html( $subline_text );

									// Add delta if specified (Pro feature).
									if ( can_access_rewardswp_feature( 'dashboard_deltas' ) && ! empty( $kpi_def['subline']['delta_field'] ) && ! empty( $kpi_data[ $kpi_def['subline']['delta_field'] ] ) ) {
										$delta_class = $kpi_data['rr_delta_class'] ?? 'text-emerald-600';
										echo '  ·  <span class="' . esc_attr( $delta_class ) . '">' . esc_html( $kpi_data[ $kpi_def['subline']['delta_field'] ] ) . '</span>';
									}
									?>
								</p>
							<?php endif; ?>

							<?php if ( ! empty( $kpi_data['badge'] ) ) : ?>
								<div class="mt-3">
									<?php if ( ! empty( $kpi_data['badge']['status'] ) ) : ?>
										<span class="inline-flex items-center px-2.5 py-1 rounded text-sm font-medium
											<?php
											switch ( $kpi_data['badge']['status'] ) {
												case 'healthy':
													echo 'bg-green-100 text-green-800';
													break;
												case 'okay':
													echo 'bg-yellow-100 text-yellow-800';
													break;
												case 'attention':
													echo 'bg-red-100 text-red-800';
													break;
												default:
													echo 'bg-gray-100 text-gray-800';
											}
											?>
											">
											<?php echo esc_html( ucfirst( $kpi_data['badge']['status'] ) ); ?>
										</span>
									<?php endif; ?>
								</div>
							<?php endif; ?>

							<?php if ( ! empty( $kpi_data['sparkline'] ) && is_array( $kpi_data['sparkline'] ) ) : ?>
								<?php if ( count( $kpi_data['sparkline'] ) >= 2 ) : ?>
									<div class="mt-4 sparkline-container preserve-styles"
										id="featured-sparkline-<?php echo esc_attr( $kpi_def['id'] ); ?>"
										data-sparkline="<?php echo esc_attr( json_encode( $kpi_data['sparkline'] ) ); ?>"
										data-sparkline-color="<?php echo esc_attr( $kpi_def['sparkline']['color'] ?? '#3B82F6' ); ?>"
										data-sparkline-animate="true">
									</div>
								<?php else : ?>
									<div class="mt-4">
										<?php
										$this->chart_empty_state->render(
											[
												'description' => __( 'When more orders use rewards, this chart will show the revenue they drive.', 'rewardswp' ),
											]
										);
										?>
									</div>
								<?php endif; ?>
							<?php endif; ?>

							<?php if ( ! empty( $kpi_data['meta'] ) ) : ?>
								<div class="mt-4">
									<p class="text-sm text-gray-500">
										<?php
										if ( ! empty( $kpi_data['meta']['discounts_given'] ) ) {
											printf(
												/* translators: %s: Amount of discounts given. */
												esc_html__( 'Discounts %s', 'rewardswp' ),
												format_currency( $kpi_data['meta']['discounts_given'], '', false )
											);
										}
										if ( ! empty( $kpi_data['meta']['refunds'] ) ) {
											echo ' • ' . sprintf(
												/* translators: %s: Amount refunded. */
												esc_html__( 'Refunds %s', 'rewardswp' ),
												format_currency( $kpi_data['meta']['refunds'], '', false )
											);
										}
										?>
									</p>
								</div>
							<?php endif; ?>
						</div>
					<?php endif; ?>
				</div>
			</div>
		</div>
		<?php
	}

	/**
	 * Render a standard KPI card.
	 *
	 * @since 1.0.0
	 * @param array $kpi_def KPI definition
	 * @param array $kpi_data KPI data
	 */
	private function render_kpi_card( array $kpi_def, array $kpi_data ): void {
		$kpi_id = $kpi_def['id'] ?? '';

		// Check if we should show empty state using the service helper.
		$empty_state_config = $this->dashboard_service->get_empty_state_for_kpi( $kpi_id, $kpi_data );
		$show_empty_state   = null !== $empty_state_config;

		// Check if program is off but has data (show badge instead of empty state).
		$program_status = $this->dashboard_service->get_program_status_for_kpi( $kpi_id, $kpi_data );
		?>
		<?php
		// Check if empty state config wants to show a badge.
		$empty_badge = $show_empty_state && ! empty( $empty_state_config['show_badge'] ) ? $empty_state_config['badge_text'] : null;
		?>
		<div class="@container bg-white border border-gray-900/8 rounded-lg p-4"
			data-kpi-type="<?php echo esc_attr( $kpi_def['value_type'] ?? '' ); ?>">
			<div class="flex items-start justify-between gap-x-4 gap-y-1 flex-wrap @min-[280px]:flex-nowrap mb-2">

				<h3 class="text-sm text-gray-900 inline border-b border-dashed border-gray-300 pb-0.5 cursor-help"
					data-tippy-content="<?php echo esc_attr( is_array( $kpi_def['tooltip'] ) ? tooltip( $kpi_def['tooltip'] ) : $kpi_def['tooltip'] ); ?>">
					<?php echo esc_html( $kpi_def['title'] ); ?>
				</h3>

				<?php if ( $program_status || $empty_badge ) : ?>
					<span class="shrink-0 inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-600 whitespace-nowrap">
						<?php echo esc_html( $program_status['badge'] ?? $empty_badge ); ?>
					</span>
				<?php endif; ?>

			</div>

			<?php if ( $show_empty_state ) : ?>
				<?php
				$empty_config = $empty_state_config; // Use already-fetched config.
				?>
				<!-- Empty State -->
				<div class="mt-4">
					<?php if ( '' !== ( $empty_config['empty_value'] ?? '' ) ) : ?>
					<div class="flex items-baseline gap-2">
						<p class="text-xl font-semibold text-gray-900">
							<?php echo esc_html( $empty_config['empty_value'] ); ?>
						</p>
						<?php if ( ! empty( $empty_config['empty_delta'] ) ) : ?>
							<span class="text-xs font-medium text-gray-400">
								<?php echo esc_html( $empty_config['empty_delta'] ); ?>
							</span>
						<?php endif; ?>
					</div>
					<?php endif; ?>

					<?php
					// Handle subline display based on config.
					$show_subline = $empty_config['show_subline'] ?? false;
					if ( 'conditional' === $show_subline ) {
						// Show only if total > 0.
						$show_subline = ! empty( $kpi_data['total_count'] ) || ! empty( $kpi_data['total_members'] );
					}

					if ( $show_subline ) :
						$subline_text = $empty_config['subline_value'] ?? $empty_config['subline_format'] ?? '';
						// Replace template variables.
						$subline_text = str_replace( '{total}', $kpi_data['total_count'] ?? $kpi_data['total_members'] ?? '0', $subline_text );
						?>
						<p class="text-sm text-gray-500 mt-1">
							<?php echo esc_html( $subline_text ); ?>
						</p>
					<?php endif; ?>

					<?php if ( ! empty( $empty_config['message'] ) ) : ?>
						<p class="text-sm text-gray-900 mt-2">
							<?php echo esc_html( $empty_config['message'] ); ?>
						</p>
					<?php endif; ?>

					<?php if ( ! empty( $empty_config['description'] ) ) : ?>
						<?php
						// When message is empty, description becomes the primary text.
						$desc_class = empty( $empty_config['message'] ) ? 'text-sm text-gray-900 mt-2' : 'text-sm text-gray-500 mt-1';
						?>
						<p class="<?php echo esc_attr( $desc_class ); ?>">
							<?php echo esc_html( $empty_config['description'] ); ?>
						</p>
					<?php endif; ?>

					<?php if ( ! empty( $empty_config['actions'] ) ) : ?>
						<div class="mt-3">
							<?php foreach ( $empty_config['actions'] as $action ) : ?>
								<a href="<?php echo esc_url( $action['url'] ); ?>"
									class="inline-flex items-center px-2.5 py-1 border border-blue-300 text-xs font-medium rounded text-blue-600 hover:bg-blue-50 hover:border-blue-400 transition-all duration-200">
									<?php echo esc_html( $action['label'] ); ?>
								</a>
							<?php endforeach; ?>
						</div>
					<?php endif; ?>
				</div>
			<?php else : ?>
				<!-- Value Display -->
				<div>
					<div class="flex items-start justify-between">
						<div class="flex-1">
							<div class="flex items-baseline gap-2">
								<p class="text-xl font-semibold text-gray-900">
									<?php echo wp_kses_post( $kpi_data['value_html'] ?? '0' ); ?>
								</p>
								<?php if ( ! empty( $kpi_data['delta'] ) && can_access_rewardswp_feature( 'dashboard_deltas' ) ) : ?>
									<span class="text-xs font-medium <?php echo esc_attr( $kpi_data['delta_class'] ?? 'text-gray-500' ); ?>">
										<?php echo esc_html( $kpi_data['delta'] ); ?>
									</span>
								<?php endif; ?>
							</div>

							<?php if ( ! empty( $kpi_def['subline'] ) && $kpi_def['subline']['show'] && ! $program_status ) : ?>
								<p class="text-sm text-gray-500 mt-1">
									<?php
									$subline_text = $kpi_def['subline']['text'];
									// Replace template variables with actual values.
									if ( ! empty( $kpi_data['total_members'] ) ) {
										$subline_text = str_replace( '{total}', $kpi_data['total_members'], $subline_text );
									}
									if ( isset( $kpi_data['rate'] ) ) {
										$subline_text = str_replace( '{rate}', $kpi_data['rate'], $subline_text );
									}
									if ( ! empty( $kpi_data['median_time'] ) ) {
										$subline_text = str_replace( '{median_time}', $kpi_data['median_time'], $subline_text );
									}
									if ( isset( $kpi_data['rewarded_count'] ) ) {
										$subline_text = str_replace( '{rewarded_count}', number_format_i18n( $kpi_data['rewarded_count'] ), $subline_text );
									}
									if ( isset( $kpi_data['total_count'] ) ) {
										$subline_text = str_replace( '{total_count}', number_format_i18n( $kpi_data['total_count'] ), $subline_text );
									}
									echo esc_html( $subline_text );

									// Add delta if specified (Pro feature).
									if ( can_access_rewardswp_feature( 'dashboard_deltas' ) && ! empty( $kpi_def['subline']['delta_field'] ) && ! empty( $kpi_data[ $kpi_def['subline']['delta_field'] ] ) ) {
										$delta_class = $kpi_data['rr_delta_class'] ?? 'text-emerald-600';
										echo '  ·  <span class="' . esc_attr( $delta_class ) . '">' . esc_html( $kpi_data[ $kpi_def['subline']['delta_field'] ] ) . '</span>';
									}
									?>
								</p>
							<?php endif; ?>

							<?php if ( ! empty( $kpi_data['badge'] ) ) : ?>
						<div class="mt-2 flex items-center gap-2">
								<?php if ( ! empty( $kpi_data['badge']['status'] ) ) : ?>
								<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium
									<?php
									switch ( $kpi_data['badge']['status'] ) {
										case 'healthy':
											echo 'bg-green-100 text-green-800';
											break;
										case 'okay':
											echo 'bg-yellow-100 text-yellow-800';
											break;
										case 'attention':
											echo 'bg-red-100 text-red-800';
											break;
										default:
											echo 'bg-gray-100 text-gray-800';
									}
									?>
									">
									<?php echo esc_html( ucfirst( $kpi_data['badge']['status'] ) ); ?>
								</span>
							<?php endif; ?>
								<?php if ( ! empty( $kpi_data['badge']['multiple'] ) ) : ?>
								<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-800">
									×<?php echo esc_html( number_format( $kpi_data['badge']['multiple'], 1 ) ); ?>
								</span>
							<?php endif; ?>
						</div>
					<?php endif; ?>

						</div>

						<?php if ( ! empty( $kpi_data['sparkline'] ) && is_array( $kpi_data['sparkline'] ) && count( $kpi_data['sparkline'] ) >= 2 ) : ?>
							<div class="sparkline-container w-24 preserve-styles"
								id="sparkline-<?php echo esc_attr( $kpi_def['id'] ); ?>"
								data-sparkline="<?php echo esc_attr( json_encode( $kpi_data['sparkline'] ) ); ?>"
								data-sparkline-color="<?php echo esc_attr( $kpi_def['sparkline']['color'] ?? '#3B82F6' ); ?>"
								data-sparkline-type="<?php echo esc_attr( $kpi_def['sparkline']['type'] ?? 'area' ); ?>">
							</div>
						<?php endif; ?>
					</div>

					<?php if ( ! empty( $kpi_data['meta'] ) ) : ?>
						<div class="mt-3 pt-3 border-t border-gray-100">
							<p class="text-xs text-gray-500">
								<?php
								if ( ! empty( $kpi_data['meta']['discounts_given'] ) ) {
									printf(
										/* translators: %s: Amount of discounts given. */
										esc_html__( 'Discounts %s', 'rewardswp' ),
										format_currency( $kpi_data['meta']['discounts_given'], '', false )
									);
								}
								if ( ! empty( $kpi_data['meta']['refunds'] ) ) {
									echo ' • ' . sprintf(
										/* translators: %s: Amount refunded. */
										esc_html__( 'Refunds %s', 'rewardswp' ),
										format_currency( $kpi_data['meta']['refunds'], '', false )
									);
								}
								?>
							</p>
						</div>
					<?php endif; ?>


				</div>

				<?php if ( $program_status && ! empty( $program_status['action'] ) ) : ?>
					<!-- Program Status Action -->
					<div class="mt-3">
						<a href="<?php echo esc_url( admin_url( $program_status['action']['url'] ) ); ?>"
							class="inline-flex items-center px-2.5 py-1 border border-blue-300 text-xs font-medium rounded text-blue-600 hover:bg-blue-50 hover:border-blue-400 transition-all duration-200">
							<?php echo esc_html( $program_status['action']['label'] ); ?>
						</a>
					</div>
				<?php endif; ?>
			<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * Render a chart.
	 *
	 * @since 1.0.0
	 * @param array $chart_def  Chart definition.
	 * @param array $chart_data Chart data.
	 * @param bool  $borderless Whether to render without border/background.
	 */
	private function render_chart( array $chart_def, array $chart_data, bool $borderless = false ): void {
		$feature_enabled  = $chart_data['feature_enabled'] ?? true;
		$has_data         = ! empty( $chart_data['datasets'] ) && ! empty( $chart_data['datasets'][0]['data'] );
		$show_empty_state = ! $feature_enabled || ! $has_data;
		$wrapper_class    = $borderless ? '' : 'bg-white border border-gray-900/8 rounded-lg p-6';
		?>
		<div class="<?php echo esc_attr( $wrapper_class ); ?>"
			data-chart-id="<?php echo esc_attr( $chart_def['id'] ); ?>"
			data-chart-type="<?php echo esc_attr( $chart_def['type'] ); ?>">

			<?php if ( ! $feature_enabled ) : ?>
				<!-- Feature Disabled - Promo Card -->
				<div class="flex flex-col items-center justify-center h-64 text-center">
					<h3 class="text-lg font-semibold text-gray-900 mb-2">
						<?php
						if ( 'referral-revenue' === $chart_def['id'] ) {
							esc_html_e( 'Referrals are off', 'rewardswp' );
						} elseif ( 'points-activity-chart' === $chart_def['id'] ) {
							esc_html_e( 'Points are off', 'rewardswp' );
						}
						?>
					</h3>
					<p class="text-sm text-gray-600 mb-4">
						<?php
						if ( 'referral-revenue' === $chart_def['id'] ) {
							esc_html_e( 'Turn them on to unlock word-of-mouth revenue.', 'rewardswp' );
						} elseif ( 'points-activity-chart' === $chart_def['id'] ) {
							esc_html_e( 'Turn them on to build repeat purchases.', 'rewardswp' );
						}
						?>
					</p>
					<a href="
					<?php
					echo esc_url(
						admin_url(
							'admin.php?page=rewardswp-settings&tab=' .
							( 'referral-revenue' === $chart_def['id'] ? 'referrals' : 'points' )
						)
					);
					?>
						"
						class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700">
						<?php
						if ( 'referral-revenue' === $chart_def['id'] ) {
							esc_html_e( 'Enable referrals', 'rewardswp' );
						} elseif ( 'points-activity-chart' === $chart_def['id'] ) {
							esc_html_e( 'Enable points', 'rewardswp' );
						}
						?>
					</a>
				</div>
			<?php elseif ( ! $has_data ) : ?>
				<!-- No Data Yet - Skeleton State -->
				<div class="relative">
					<div class="flex justify-between items-start mb-4">
						<h3 class="text-lg text-gray-900 inline-block border-b border-dashed border-gray-300 cursor-help"
							data-tippy-content="
							<?php
							echo esc_attr(
								'referral-revenue' === $chart_def['id']
									? __( 'Daily referral revenue with 7-day moving average. Shows revenue from orders where referrals were completed.', 'rewardswp' )
									: __( 'Points earned vs redeemed daily. RR (Redemption Rate) shows engagement quality.', 'rewardswp' )
							);
							?>
							">
							<?php echo esc_html( $chart_def['title'] ); ?>
						</h3>
						<?php if ( 'points-activity-chart' === $chart_def['id'] ) : ?>
							<span class="text-sm font-medium text-gray-500">RR: —</span>
						<?php endif; ?>
					</div>
					<div class="h-64 bg-gray-100 rounded-lg animate-pulse flex items-center justify-center">
						<p class="text-sm text-gray-500">
							<?php esc_html_e( 'Appears after your first activity.', 'rewardswp' ); ?>
						</p>
					</div>
				</div>
			<?php else : ?>
				<!-- Chart with Data -->
				<div class="relative">
					<!-- Chart Header -->
					<div class="flex justify-between items-start mb-4">
						<h3 class="text-lg text-gray-900 inline-block border-b border-dashed border-gray-300 cursor-help"
							data-tippy-content="
							<?php
							echo esc_attr(
								'referral-revenue' === $chart_def['id']
									? __( 'Daily referral revenue with 7-day moving average. Shows revenue from orders where referrals were completed.', 'rewardswp' )
									: __( 'Points earned vs redeemed daily. RR (Redemption Rate) shows engagement quality.', 'rewardswp' )
							);
							?>
							">
							<?php echo esc_html( $chart_def['title'] ); ?>
						</h3>

						<?php if ( 'referral-revenue' === $chart_def['id'] && ! empty( $chart_data['summary'] ) ) : ?>
							<!-- Referral Revenue Summary (Top Right) -->
							<div class="text-right">
								<span class="text-sm text-gray-600">
									<?php esc_html_e( 'Total this period:', 'rewardswp' ); ?>
									<span class="font-semibold text-gray-900">
										<?php echo esc_html( $chart_data['summary']['total_formatted'] ); ?>
									</span>
								</span>
								<?php if ( ! empty( $chart_data['summary']['delta'] ) ) : ?>
									<span class="ml-2 text-sm <?php echo 'positive' === $chart_data['summary']['delta_type'] ? 'text-green-600' : 'text-red-600'; ?>">
										<?php echo esc_html( $chart_data['summary']['delta'] ); ?>
									</span>
								<?php endif; ?>
							</div>
						<?php elseif ( 'points-activity-chart' === $chart_def['id'] && ! empty( $chart_data['badge'] ) ) : ?>
							<!-- Points Activity RR Badge (Top Left as corner badge) -->
							<div class="text-right">
								<span class="text-sm font-medium text-gray-900">
									<?php echo esc_html( $chart_data['badge']['rr_formatted'] ); ?>
								</span>
								<?php if ( ! empty( $chart_data['badge']['delta'] ) ) : ?>
									<span class="ml-1 text-xs <?php echo 'positive' === $chart_data['badge']['delta_type'] ? 'text-green-600' : 'text-red-600'; ?>">
										<?php echo esc_html( $chart_data['badge']['delta'] ); ?>
									</span>
								<?php endif; ?>
							</div>
						<?php endif; ?>
					</div>

					<!-- Chart Container -->
					<div class="h-64 chart-container preserve-styles"
						id="chart-<?php echo esc_attr( $chart_def['id'] ); ?>"
						data-chart-config='
						<?php
							echo esc_attr(
								json_encode(
									[
										'type'   => $chart_def['type'],
										'data'   => $chart_data,
										'series' => $chart_def['series'] ?? [],
									]
								)
							);
						?>
						'>
					</div>


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

	/**
	 * Render top referrers list for Program Insights widget.
	 *
	 * @since 1.1.0
	 *
	 * @param array $referrers Array of top referrers.
	 */
	private function render_top_referrers_list( array $referrers ): void {
		if ( empty( $referrers ) ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output is escaped within the component
			echo get_view_component(
				'empty-state',
				[
					'icon'        => 'earn-referral',
					'title'       => __( 'No top referrers yet', 'rewardswp' ),
					'description' => __( 'Once members start referring others, your top performers will show here.', 'rewardswp' ),
				]
			);
			return;
		}
		?>
		<ul class="space-y-3">
			<?php
			foreach ( $referrers as $i => $referrer ) :
				$member_url = add_query_arg(
					[
						'page'      => 'rewardswp-members',
						'action'    => 'view_member',
						'member_id' => $referrer['advocate_id'],
					],
					admin_url( 'admin.php' )
				);
				$count      = (int) $referrer['referral_count'];
				?>
			<li class="flex items-center justify-between">
				<div class="flex items-center gap-3">
					<span class="inline-flex size-7 items-center justify-center rounded-full bg-slate-100 text-xs font-medium text-slate-600">
						<?php echo esc_html( $i + 1 ); ?>
					</span>
					<a href="<?php echo esc_url( $member_url ); ?>" class="text-sm text-slate-900 hover:text-blue-600"><?php echo esc_html( $referrer['name'] ); ?></a>
				</div>
				<span class="text-sm font-medium text-slate-900">
					<?php echo esc_html( $count ); ?>
					<span class="text-slate-500 font-normal"><?php echo esc_html( _n( 'referral', 'referrals', $count, 'rewardswp' ) ); ?></span>
				</span>
			</li>
			<?php endforeach; ?>
		</ul>
		<?php
	}

	/**
	 * Render top rewards list for Program Insights widget.
	 *
	 * @since 1.1.0
	 *
	 * @param array $rewards Array of top redeemed rewards.
	 */
	private function render_top_rewards_list( array $rewards ): void {
		if ( empty( $rewards ) ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output is escaped within the component
			echo get_view_component(
				'empty-state',
				[
					'icon'        => 'reward-redemption',
					'title'       => __( 'No redemptions yet', 'rewardswp' ),
					'description' => __( 'Once members redeem rewards, you\'ll see your most popular ones here.', 'rewardswp' ),
				]
			);
			return;
		}
		?>
		<ul class="space-y-3">
			<?php foreach ( $rewards as $i => $reward ) : ?>
			<li class="flex items-center justify-between">
				<div class="flex items-center gap-3">
					<span class="inline-flex size-7 items-center justify-center rounded-full bg-slate-100 text-xs font-medium text-slate-600">
						<?php echo esc_html( $i + 1 ); ?>
					</span>
					<span class="text-sm text-slate-900">
						<?php
						$free_product_name = $reward['free_product_name'] ?? '';

						if ( 'free_product' === $reward['reward_type'] && '' !== $free_product_name ) {
							echo wp_kses_post(
								sprintf(
									/* translators: %s: product name */
									__( 'Free %s', 'rewardswp' ),
									esc_html( $free_product_name )
								)
							);
						} else {
							echo wp_kses_post( \Awesomemotive\Rewardswp\Helpers\get_reward_display_title_from_values( null, $reward['reward_type'], (float) $reward['amount'] ) );
						}
						?>
					</span>
				</div>
				<span class="text-sm font-medium text-slate-900">
					<?php
					$count = (int) $reward['redemption_count'];
					echo esc_html( $count );
					?>
					<span class="text-slate-500 font-normal"><?php echo esc_html( _n( 'redemption', 'redemptions', $count, 'rewardswp' ) ); ?></span>
				</span>
			</li>
			<?php endforeach; ?>
		</ul>
		<?php
	}
}
