<?php
/**
 * Emails admin controller.
 *
 * @package Awesomemotive\Rewardswp\Controllers\Admin
 * @since 1.0.0
 */

namespace Awesomemotive\Rewardswp\Controllers\Admin;

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

use Awesomemotive\Rewardswp\Database\Upgrades\SeedBirthdayEmailUpgrade;
use Awesomemotive\Rewardswp\Database\Upgrades\SeedDefaultEmailsUpgrade;
use Awesomemotive\Rewardswp\Factories\ViewsFactory;
use Awesomemotive\Rewardswp\Factories\MailerFactory;
use Awesomemotive\Rewardswp\Interfaces\ControllerInterface;
use Awesomemotive\Rewardswp\Models\Email;
use Awesomemotive\Rewardswp\Services\AssetsService;
use Awesomemotive\Rewardswp\Services\EmailsService;
use Awesomemotive\Rewardswp\Services\OptionsService;
use Awesomemotive\Rewardswp\Services\SettingsScreenService;
use Awesomemotive\Rewardswp\Settings\Options\Emails\FromEmailOption;
use Awesomemotive\Rewardswp\Settings\Options\Emails\EmailLogoOption;
use Awesomemotive\Rewardswp\Views\Admin\EmailPreviewView;
use Awesomemotive\Rewardswp\Views\Admin\EmailsManagementView;
use function Awesomemotive\Rewardswp\Helpers\is_rewardswp_admin_page;
use function Awesomemotive\Rewardswp\Helpers\get_option_value;
use function Awesomemotive\Rewardswp\Helpers\rewardswp_log_error;
use function Awesomemotive\Rewardswp\Helpers\format_points_with_label;
use function Awesomemotive\Rewardswp\Helpers\get_points_currency_singular;
use function Awesomemotive\Rewardswp\Helpers\get_points_currency_plural;
use function Awesomemotive\Rewardswp\Helpers\format_currency;

/**
 * Class EmailsAdminController
 *
 * Handles the admin interface for email management.
 *
 * @since 1.1.0
 */
class EmailsAdminController implements ControllerInterface {
	/**
	 * Menu position in the admin sidebar.
	 *
	 * @since 1.1.0
	 *
	 * @var int
	 */
	const MENU_POSITION = 50;

	/**
	 * Menu slug for the emails admin page.
	 *
	 * @since 1.1.0
	 *
	 * @var string
	 */
	const MENU_SLUG = 'rewardswp-emails';

	/**
	 * AJAX nonce for email settings.
	 *
	 * @since 1.1.0
	 *
	 * @var string
	 */
	const AJAX_NONCE = 'rewardswp_email_settings_nonce';


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

	/**
	 * Emails service instance.
	 *
	 * @since 1.1.0
	 *
	 * @var EmailsService
	 */
	private EmailsService $emails_service;

	/**
	 * Mailer factory instance.
	 *
	 * @since 1.1.0
	 *
	 * @var MailerFactory
	 */
	private MailerFactory $mailer_factory;

	/**
	 * Settings screen service instance.
	 *
	 * @since 1.1.0
	 *
	 * @var SettingsScreenService
	 */
	private SettingsScreenService $settings_screen_service;

	/**
	 * Assets service instance.
	 *
	 * @since 1.1.0
	 *
	 * @var AssetsService
	 */
	private AssetsService $assets_service;

	/**
	 * Seed default emails upgrade instance.
	 *
	 * @since 1.1.0
	 *
	 * @var SeedDefaultEmailsUpgrade
	 */
	private SeedDefaultEmailsUpgrade $seed_emails_upgrade;

	/**
	 * Seed birthday email upgrade instance.
	 *
	 * @since 1.4.0
	 *
	 * @var SeedBirthdayEmailUpgrade
	 */
	private SeedBirthdayEmailUpgrade $seed_birthday_email_upgrade;

	/**
	 * Constructor.
	 *
	 * @since 1.1.0
	 *
	 * @param ViewsFactory             $views_factory            Views factory instance.
	 * @param EmailsService            $emails_service           Emails service instance.
	 * @param MailerFactory            $mailer_factory           Mailer factory instance.
	 * @param SettingsScreenService    $settings_screen_service  Settings screen service instance.
	 * @param AssetsService            $assets_service           Assets service instance.
	 * @param SeedDefaultEmailsUpgrade $seed_emails_upgrade      Seed default emails upgrade instance.
	 * @param SeedBirthdayEmailUpgrade $seed_birthday_email_upgrade Seed birthday email upgrade instance.
	 */
	public function __construct( ViewsFactory $views_factory, EmailsService $emails_service, MailerFactory $mailer_factory, SettingsScreenService $settings_screen_service, AssetsService $assets_service, SeedDefaultEmailsUpgrade $seed_emails_upgrade, SeedBirthdayEmailUpgrade $seed_birthday_email_upgrade ) {
		$this->views_factory                = $views_factory;
		$this->emails_service               = $emails_service;
		$this->mailer_factory               = $mailer_factory;
		$this->settings_screen_service      = $settings_screen_service;
		$this->assets_service               = $assets_service;
		$this->seed_emails_upgrade          = $seed_emails_upgrade;
		$this->seed_birthday_email_upgrade  = $seed_birthday_email_upgrade;
	}

	/**
	 * Initialize the controller.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	public function init() {
		add_action( 'admin_menu', [ $this, 'add_admin_menu' ], self::MENU_POSITION );
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );

		// Handle iframe preview early, before WordPress sends admin page headers.
		add_action( 'admin_init', [ $this, 'maybe_render_iframe_preview' ] );

		// AJAX actions for email management
		add_action( 'wp_ajax_rewardswp_toggle_email_status', [ $this, 'ajax_toggle_email_status' ] );
		add_action( 'wp_ajax_rewardswp_send_test_email', [ $this, 'ajax_send_test_email' ] );
		add_action( 'wp_ajax_rewardswp_save_email_settings', [ $this, 'ajax_save_email_settings' ] );
		add_action( 'wp_ajax_rewardswp_save_individual_email', [ $this, 'ajax_save_individual_email' ] );
		add_action( 'wp_ajax_rewardswp_get_attachment_url', [ $this, 'ajax_get_attachment_url' ] );
	}

	/**
	 * Check if this is an iframe preview request and render it early.
	 *
	 * This must run on admin_init, before WordPress starts sending the admin page headers,
	 * to ensure we can output minimal HTML without the admin wrapper.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	public function maybe_render_iframe_preview(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a read-only preview request.
		$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$action = isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : '';
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$iframe = isset( $_GET['iframe'] ) ? sanitize_text_field( wp_unslash( $_GET['iframe'] ) ) : '';
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$email_id = isset( $_GET['email_id'] ) ? absint( wp_unslash( $_GET['email_id'] ) ) : 0;

		// Only handle our specific iframe preview requests.
		if ( self::MENU_SLUG !== $page || 'preview' !== $action || '1' !== $iframe || ! $email_id ) {
			return;
		}

		// Verify user has permission.
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have permission to view this preview.', 'rewardswp' ) );
		}

		$email = $this->emails_service->get_email_by_id( $email_id );

		if ( ! $email ) {
			wp_die( esc_html__( 'Email not found.', 'rewardswp' ) );
		}

		// Generate preview content.
		$rendered_content = $this->generate_preview_content( $email );

		// Output minimal HTML and exit.
		$this->render_minimal_iframe( $email, $rendered_content );
		exit;
	}

	/**
	 * Register the emails submenu page.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	public function add_admin_menu() {
		add_submenu_page(
			MainAdminController::MAIN_MENU_SLUG,
			esc_html__( 'Emails', 'rewardswp' ),
			esc_html__( 'Emails', 'rewardswp' ),
			'manage_options',
			self::MENU_SLUG,
			[ $this, 'render_page' ],
			self::MENU_POSITION
		);
	}

	/**
	 * Enqueue scripts and styles for the emails admin page.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	public function enqueue_scripts() {
		if ( ! is_rewardswp_admin_page( self::MENU_SLUG ) ) {
			return;
		}

		// Enqueue admin script (includes merge-tags-dropdown component)
		$this->assets_service->enqueue_script( $this->assets_service::ADMIN_SCRIPT_HANDLE );

		// Enqueue WordPress media scripts for logo upload functionality
		wp_enqueue_media();

		// Localize script with nonce
		wp_localize_script(
			$this->assets_service::ADMIN_SCRIPT_HANDLE,
			'rewardswpEmailsData',
			[
				'nonce'   => wp_create_nonce( self::AJAX_NONCE ),
				'ajaxurl' => admin_url( 'admin-ajax.php' ),
			]
		);
	}



	/**
	 * Render the emails admin page.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	public function render_page() {
		// Ensure default emails exist before rendering the page
		$this->ensure_default_emails_exist();

		$current_action = $this->get_current_action();

		switch ( $current_action ) {
			case 'preview':
				$this->render_preview_page();
				break;
			default:
				$this->render_list_page();
				break;
		}
	}

	/**
	 * Ensure default emails exist in the database.
	 *
	 * This method checks if any emails exist in the database and if not,
	 * automatically seeds the default email templates. This prevents the
	 * admin from seeing an empty emails list if the upgrade didn't run
	 * or if emails were accidentally deleted.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	private function ensure_default_emails_exist() {
		// Check if any emails exist
		$email_count = $this->emails_service->count_emails();

		// If no emails exist, seed the default templates using the upgrade class.
		if ( $email_count === 0 ) {
			$this->seed_emails_upgrade->up();
		}

		// Ensure the birthday email exists (may be missing if DB was cleaned
		// or if the 1.4.0 upgrade didn't run yet).
		$this->seed_birthday_email_upgrade->up();
	}

	/**
	 * Get the current action from the request.
	 *
	 * @since 1.1.0
	 *
	 * @return string
	 */
	private function get_current_action(): string {
		// This is a GET request in admin area for navigation purposes only, nonce verification is not required.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		return sanitize_text_field( wp_unslash( $_GET['action'] ?? 'list' ) );
	}

	/**
	 * Render the emails list page.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	private function render_list_page() {
		$this->get_emails_management_view()->render();
	}

	/**
	 * Get the preview view instance.
	 *
	 * @since 1.1.0
	 *
	 * @return EmailPreviewView
	 */
	private function get_preview_view(): EmailPreviewView {
		return $this->views_factory->get_view( EmailPreviewView::class );
	}

	/**
	 * Render the email preview page.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	private function render_preview_page() {
		// This is a GET request in admin area for navigation purposes only, nonce verification is not required.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$email_id = absint( wp_unslash( $_GET['email_id'] ?? 0 ) );
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$get_iframe = isset( $_GET['iframe'] ) ? sanitize_text_field( wp_unslash( $_GET['iframe'] ) ) : '';
		$is_iframe  = '1' === $get_iframe;

		if ( ! $email_id ) {
			wp_die( esc_html__( 'Invalid email ID.', 'rewardswp' ) );
		}

		$email = $this->emails_service->get_email_by_id( $email_id );

		if ( ! $email ) {
			wp_die( esc_html__( 'Email not found.', 'rewardswp' ) );
		}

		// If iframe mode, disable WordPress hooks to avoid admin bar and other elements.
		if ( $is_iframe ) {
			// Prevent any output before our content.
			ob_clean();

			// Generate preview content with sample data.
			$rendered_content = $this->generate_preview_content( $email );

			// Output minimal HTML directly
			$this->render_minimal_iframe( $email, $rendered_content );
			exit;
		}

		// Generate preview content with sample data
		$rendered_content = $this->generate_preview_content( $email );

		// Get display title for the email
		$email_data = $this->emails_service->get_email_with_description( $email );

		// Render preview view
		$this->get_preview_view()->render(
			[
				'email'            => $email,
				'rendered_content' => $rendered_content,
				'display_title'    => $email_data['display_title'] ?? ucwords( str_replace( '_', ' ', $email->name ) ),
			]
		);
	}

	/**
	 * Render minimal iframe HTML without WordPress overhead.
	 *
	 * @since 1.1.0
	 *
	 * @param Email  $email Email object.
	 * @param string $rendered_content The rendered email content.
	 *
	 * @return void
	 */
	private function render_minimal_iframe( $email, $rendered_content ): void {
		header( 'Content-Type: text/html; charset=UTF-8' );
		?>
		<!DOCTYPE html>
		<html lang="en">
		<head>
			<meta charset="UTF-8">
			<meta name="viewport" content="width=device-width, initial-scale=1">
			<title><?php esc_html_e( 'Email Preview', 'rewardswp' ); ?></title>
			<style>
				* {
					box-sizing: border-box;
				}

				html, body {
					margin: 0 !important;
					padding: 0 !important;
					/* Let email template define its own background */
					font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
					line-height: 1.6 !important;
					color: #374151 !important;
					font-size: 14px !important;
				}

				.email-content {
					/* Let email template control its own spacing and background */
					min-height: 100vh !important;
				}

				/* Email content styles */
				h1, h2, h3, h4, h5, h6 {
					margin-top: 0 !important;
					margin-bottom: 16px !important;
					font-weight: 600 !important;
					line-height: 1.25 !important;
				}

				p {
					margin-bottom: 16px !important;
				}

				a {
					font-weight: normal !important;
					border: none !important;
					box-shadow: none !important;
					outline: none !important;
					background: transparent !important;
					display: inline !important;
					box-sizing: border-box !important;
				}

				a:hover {
					background: transparent !important;
				}

				a:focus {
					outline: none !important;
					background: transparent !important;
				}

				/* Protect email button styles from admin interference */
				a.rewardswp-button-link {
					color: #ffffff !important;
					text-decoration: none !important;
					background-color: #3b82f6 !important;
					border-radius: 0.5rem !important;
					padding: 1rem 2rem !important;
					display: inline-block !important;
					font-weight: 600 !important;
					border: none !important;
					box-shadow: none !important;
					outline: none !important;
					font-size: inherit !important;
					line-height: normal !important;
				}

				a.rewardswp-button-link:hover {
					background-color: #2563eb !important;
					color: #ffffff !important;
					text-decoration: none !important;
				}

				a.rewardswp-button-link:focus {
					outline: 2px solid #3b82f6 !important;
					outline-offset: 2px !important;
					background-color: #2563eb !important;
					color: #ffffff !important;
				}

				img {
					max-width: 100% !important;
					height: auto !important;
				}

				table {
					width: 100% !important;
					border-collapse: collapse !important;
				}

				/* Responsive styles */
				@media (max-width: 600px) {
					.email-content {
						padding: 12px !important;
						font-size: 13px !important;
					}
				}
			</style>
			<script>
				// Auto-resize iframe to content height
				function resizeIframe() {
					try {
						const body = document.body;
						const html = document.documentElement;

						if (!body || !html) {
							return;
						}

						const height = Math.max(
							body.scrollHeight || 300,
							body.offsetHeight || 300,
							html.clientHeight || 300,
							html.scrollHeight || 300,
							html.offsetHeight || 300
						);

						// Send height to parent window
						if (window.parent && window.parent !== window) {
							window.parent.postMessage({
								type: 'iframe-resize',
								height: height + 20
							}, '*');
						}
					} catch (e) {
						console.warn('Resize iframe error:', e);
					}
				}

				// Listen for resize requests from parent
				window.addEventListener('message', function(event) {
					if (event.data && event.data.type === 'request-height') {
						resizeIframe();
					}
				});

				// Resize on load
				window.addEventListener('load', function() {
					setTimeout(resizeIframe, 200);
				});

				// Initial resize call
				setTimeout(resizeIframe, 100);
			</script>
		</head>
		<body>
			<div class="email-content">
				<?php
				// For email previews, we output content directly since:
				// 1. We control the content generation (comes from our BaseEmailView)
				// 2. CSS styles are essential for proper email rendering
				// 3. Content is generated server-side, not user input
				echo $rendered_content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Controlled email template content
				?>
			</div>
		</body>
		</html>
		<?php
	}

	/**
	 * Generate preview content with sample data.
	 *
	 * @since 1.1.0
	 *
	 * @param Email $email Email object.
	 *
	 * @return string
	 */
	private function generate_preview_content( Email $email ): string {
		try {
			// Get the email notification class to generate sample content
			$mailer = $this->mailer_factory->get_mailer( $email->name );

			if ( ! $mailer ) {
				return '<p>' . esc_html__( 'No content available.', 'rewardswp' ) . '</p>';
			}

			// Set sample data for preview
			$sample_data = $this->get_sample_data_for_email( $email->name );
			$mailer->set_data( $sample_data );

			// Allow reactive preview banner overrides via request (not persisted)
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$preview_banner_id = isset( $_REQUEST['preview_banner_id'] ) ? absint( wp_unslash( $_REQUEST['preview_banner_id'] ) ) : 0;
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$preview_banner_size = isset( $_REQUEST['preview_banner_size'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['preview_banner_size'] ) ) : '';

			$has_preview_param = array_key_exists( 'preview_banner_id', $_REQUEST ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended

			// Detect if current email has a banner in DB to decide placeholder on normal reloads
			$has_banner_db = ( (int) ( $email->get_meta( 'banner_attachment_id', true ) ?: $email->get_meta( 'logo_attachment_id', true ) ) ) > 0;

			// Detect if global logo is set to decide logo placeholder
			$logo_data       = get_option_value( EmailLogoOption::class );
			$has_logo_global = ! empty( $logo_data ) && ! empty( $logo_data['attachment_id'] );

			// Always tell the view it's a preview; enable placeholder when explicitly no banner/logo OR when there is no banner/logo stored
			add_filter(
				'rewardswp_email_view_args',
				function ( $args ) use ( $preview_banner_id, $has_preview_param, $has_banner_db, $has_logo_global ) {
					$args['show_banner_placeholder'] = ( $has_preview_param && $preview_banner_id <= 0 ) || ( ! $has_preview_param && ! $has_banner_db );
					$args['show_logo_placeholder']   = ! $has_logo_global;
					return $args;
				}
			);

			if ( $has_preview_param && $preview_banner_id === 0 ) {
				// Explicitly remove banner for this preview request
				add_filter(
					'rewardswp_email_banner_data',
					function () {
						return null;
					}
				);
			} elseif ( $preview_banner_id ) {
				add_filter(
					'rewardswp_email_banner_data',
					function ( $data ) use ( $preview_banner_id, $preview_banner_size ) {
						$size = $preview_banner_size ?: \Awesomemotive\Rewardswp\Services\EmailsService::EMAIL_BANNER_DEFAULT_SIZE;
						$img  = wp_get_attachment_image_src( $preview_banner_id, $size );
						if ( ! $img ) {
							return $data;
						}
						return [
							'attachment_id' => $preview_banner_id,
							'url'           => $img[0],
							'width'         => $img[1],
							'height'        => $img[2],
							'size'          => $size,
							'alt'           => get_post_meta( $preview_banner_id, '_wp_attachment_image_alt', true ) ?: get_bloginfo( 'name' ),
						];
					}
				);
			}

			// Get the rendered content with merge tags replaced by sample data.
			return $mailer->get_content();

		} catch ( \Exception $e ) {
			rewardswp_log_error(
				'Failed to generate email preview: {message}',
				[
					'message'    => $e->getMessage(),
					'email_name' => $email->name ?? '',
				]
			);
			return '<p>' . esc_html__( 'Error generating preview.', 'rewardswp' ) . '</p>';
		}
	}

	/**
	 * Get sample data for email preview based on email type.
	 *
	 * @since 1.1.0
	 *
	 * @param string $email_name Email name.
	 *
	 * @return array
	 */
	private function get_sample_data_for_email( string $email_name ): array {
		$base_data = [
			'member_name'      => 'John',
			'member_full_name' => 'John Doe',
			'site_name'   => get_bloginfo( 'name' ),
			'site_url'    => home_url(),
			'admin_email' => get_option( 'admin_email' ),
		];

		// Build a realistic coupon code using the store's currency label, matching production format.
		$coupon_prefix = sanitize_title( get_points_currency_plural() ) . '-';
		$sample_coupon = $coupon_prefix . 'a1b2c3d4';

		switch ( $email_name ) {
			case 'points_earned':
				return array_merge(
					$base_data,
					[
						'points_earned'             => 25,
						'points_earned_formatted'   => format_points_with_label( 25 ),
						'action_description'        => __( 'Made a purchase', 'rewardswp' ),
						'current_balance'           => 175,
						'current_balance_formatted' => format_points_with_label( 175 ),
						'currency_singular'         => get_points_currency_singular(),
						'currency_plural'           => get_points_currency_plural(),
					]
				);

			case 'advocate_reward_email':
				return array_merge(
					$base_data,
					[
						'friend_name'            => 'Jane',
						'reward_amount'          => format_currency( 10, '', false ),
						'reward_coupon'          => $sample_coupon,
						'reward_expiration_time' => date_i18n( get_option( 'date_format' ), strtotime( '+30 days' ) ),
						'referral_id'            => 456,
					]
				);

			case 'friend_reward_email':
				return array_merge(
					$base_data,
					[
						'reward_amount'          => format_currency( 10, '', false ),
						'reward_coupon'          => $sample_coupon,
						'reward_expiration_time' => date_i18n( get_option( 'date_format' ), strtotime( '+30 days' ) ),
					]
				);

			case 'reward_redemption':
				return array_merge(
					$base_data,
					[
						'reward_title'              => __( '10% Off Your Next Order', 'rewardswp' ),
						'coupon_code'               => $sample_coupon,
						'points_redeemed_formatted' => format_points_with_label( 500 ),
						'current_balance_formatted' => format_points_with_label( 750 ),
						'shop_url'                  => home_url( '/shop' ),
						'reward_deep_link'          => home_url( '/shop' ),
					]
				);

			case 'points_expiration_email':
				return array_merge(
					$base_data,
					[
						'expiring_points_count'  => number_format_i18n( 500 ),
						'current_points_balance' => number_format_i18n( 1250 ),
						'days_before'            => '7',
						'expiration_date'        => date_i18n( get_option( 'date_format' ), strtotime( '+7 days' ) ),
						'currency_singular'      => get_points_currency_singular(),
						'currency_plural'        => get_points_currency_plural(),
					]
				);

			case 'order_linking_verification':
				return array_merge(
					$base_data,
					[
						'user_name'        => 'John Doe',
						'order_count'      => '3',
						'verification_url' => home_url( '/?verify=sample-token' ),
						'expiration_hours' => '48',
					]
				);

			case 'birthday_reward':
				return array_merge(
					$base_data,
					[
						'points_earned'             => 150,
						'points_earned_formatted'   => format_points_with_label( 150 ),
						'action_description'        => __( 'Birthday bonus', 'rewardswp' ),
						'current_balance'           => 500,
						'current_balance_formatted' => format_points_with_label( 500 ),
						'currency_singular'         => get_points_currency_singular(),
						'currency_plural'           => get_points_currency_plural(),
					]
				);

			case 'welcome_member_points':
				return array_merge(
					$base_data,
					[
						'points_earned'             => 50,
						'points_earned_formatted'   => format_points_with_label( 50 ),
						'current_balance'           => 50,
						'current_balance_formatted' => format_points_with_label( 50 ),
						'currency_singular'         => get_points_currency_singular(),
						'currency_plural'           => get_points_currency_plural(),
					]
				);

			case 'export_ready_email':
				return array_merge(
					$base_data,
					[
						'user_name'    => 'John Doe',
						'export_type'  => __( 'Members', 'rewardswp' ),
						'file_size'    => '2.4 MB',
						'expires_in'   => __( '24 hours', 'rewardswp' ),
						'download_url' => admin_url( 'admin.php?page=rewardswp-tools' ),
					]
				);

			default:
				return $base_data;
		}
	}

	/**
	 * AJAX handler for sending test emails.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	public function ajax_send_test_email() {
		check_ajax_referer( 'rewardswp_update_email', 'rewardswp_email_nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( __( 'Insufficient permissions.', 'rewardswp' ) );
		}

		$email_id = absint( wp_unslash( $_POST['email_id'] ?? 0 ) );

		if ( ! $email_id ) {
			wp_send_json_error( __( 'Invalid email ID.', 'rewardswp' ) );
		}

		// Get the configured from email address, fall back to admin email
		$test_email = get_option_value( FromEmailOption::class );

		if ( empty( $test_email ) || ! is_email( $test_email ) ) {
			$test_email = get_option( 'admin_email' );
		}

		if ( ! is_email( $test_email ) ) {
			wp_send_json_error( __( 'Unable to determine recipient email address. Please configure a From Email in settings.', 'rewardswp' ) );
		}

		try {
			$email = $this->emails_service->get_email_by_id( $email_id );

			if ( ! $email ) {
				wp_send_json_error( __( 'Email not found.', 'rewardswp' ) );
			}

			// Get the email notification class
			$mailer = $this->mailer_factory->get_mailer( $email->name );

			if ( ! $mailer ) {
				wp_send_json_error( __( 'Email mailer not found.', 'rewardswp' ) );
			}

			// Set sample data and recipient
			$sample_data = $this->get_sample_data_for_email( $email->name );
			$mailer->set_data( $sample_data );
			$mailer->set_recipient( $test_email );

			// Send the email
			$sent = $mailer->send( true );

			if ( $sent ) {
				wp_send_json_success(
					sprintf(
						/* translators: %s: Test email address. */
						__( 'Message successfully sent to %s', 'rewardswp' ),
						$test_email
					)
				);
			} else {
				wp_send_json_error( __( 'Failed to send test email.', 'rewardswp' ) );
			}
		} catch ( \Exception $e ) {
			wp_send_json_error( __( 'Error: ', 'rewardswp' ) . $e->getMessage() );
		}
	}

	/**
	 * AJAX handler for saving email settings.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	public function ajax_save_email_settings(): void {
		check_ajax_referer( self::AJAX_NONCE, '_ajax_nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error(
				[
					'message' => esc_html__( 'Insufficient permissions.', 'rewardswp' ),
				]
			);
		}

		$settings       = filter_input( INPUT_POST, OptionsService::OPTION_NAME, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
		$email_statuses = filter_input( INPUT_POST, 'email_statuses', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );

		$has_settings       = is_array( $settings ) && ! empty( $settings );
		$has_email_statuses = is_array( $email_statuses ) && ! empty( $email_statuses );

		// Require at least settings OR email statuses to be present.
		if ( ! $has_settings && ! $has_email_statuses ) {
			wp_send_json_error(
				[
					'message' => esc_html__( 'Invalid settings data.', 'rewardswp' ),
				]
			);
		}

		// Process settings if provided (from settings tab).
		if ( $has_settings ) {
			// Remove any additional slashes automatically added during the form submission.
			array_walk_recursive(
				$settings,
				function ( &$value, $key ) {
					$value = wp_unslash( $value );
				}
			);

			// Get existing settings to merge with only email settings.
			$existing_settings = get_option( OptionsService::OPTION_NAME, [] );

			// Extract only email settings from the submitted data.
			$email_settings = $settings['emails'] ?? [];

			// Merge email settings into existing settings.
			$existing_settings['emails'] = $email_settings;

			// Sanitize all settings (this will only sanitize what's present).
			$sanitized_settings = $this->settings_screen_service->sanitize_settings( $existing_settings );

			// Update the complete settings array.
			update_option( OptionsService::OPTION_NAME, $sanitized_settings );
		}

		// Handle email status updates (from emails tab or settings tab).

		if ( is_array( $email_statuses ) ) {
			foreach ( $email_statuses as $email_id => $is_enabled ) {
				$email_id   = absint( $email_id );
				$is_enabled = (bool) $is_enabled;

				$email = $this->emails_service->get_email_by_id( $email_id );
				if ( $email && $this->emails_service->can_manage_email( $email ) ) {
					$this->emails_service->update_email( $email_id, [ 'is_enabled' => $is_enabled ] );
				}
			}
		}

		wp_send_json_success(
			[
				'message' => esc_html__( 'Email settings saved successfully.', 'rewardswp' ),
			]
		);
	}

	/**
	 * AJAX handler to save individual email settings.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	public function ajax_save_individual_email(): void {
		check_ajax_referer( self::AJAX_NONCE, '_ajax_nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error(
				[
					'message' => esc_html__( 'Insufficient permissions.', 'rewardswp' ),
				]
			);
		}

		$email_id = absint( wp_unslash( $_POST['email_id'] ?? 0 ) );
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$subject_raw = isset( $_POST['subject'] ) ? wp_unslash( $_POST['subject'] ) : '';
		$subject     = wp_strip_all_tags( $subject_raw );
		// Backward-compat: accept both banner_* (new) and logo_* (legacy)
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$logo_attachment_id_raw = isset( $_POST['logo_attachment_id'] ) ? wp_unslash( $_POST['logo_attachment_id'] ) : 0;
		$logo_attachment_id     = absint( $logo_attachment_id_raw );
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$banner_attachment_id_raw = isset( $_POST['banner_attachment_id'] ) ? wp_unslash( $_POST['banner_attachment_id'] ) : $logo_attachment_id;
		$banner_attachment_id     = absint( $banner_attachment_id_raw );
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$banner_size_raw = isset( $_POST['banner_size'] ) ? wp_unslash( $_POST['banner_size'] ) : null;
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$logo_size_raw   = isset( $_POST['logo_size'] ) ? wp_unslash( $_POST['logo_size'] ) : null;
		$banner_size_raw = $banner_size_raw ?? $logo_size_raw;
		$banner_size     = is_string( $banner_size_raw ) ? sanitize_text_field( $banner_size_raw ) : '';

		if ( ! $email_id || empty( $subject ) ) {
			wp_send_json_error(
				[
					'message' => esc_html__( 'Invalid email data.', 'rewardswp' ),
				]
			);
		}

		// Get the email
		$email = $this->emails_service->get_email_by_id( $email_id );

		if ( ! $email ) {
			wp_send_json_error(
				[
					'message' => esc_html__( 'Email not found.', 'rewardswp' ),
				]
			);
		}

		if ( ! $this->emails_service->can_manage_email( $email ) ) {
			$email_meta = $this->emails_service->get_email_with_description( $email );
			$title      = $email_meta['display_title'] ?? ucwords( str_replace( '_', ' ', $email->name ) );

			wp_send_json_error(
				[
					'message' => sprintf(
						/* translators: %s: Email title. */
						esc_html__( '%s is available in RewardsWP Pro. Upgrade to make changes.', 'rewardswp' ),
						$title
					),
				]
			);
		}

		// Update email subject (ignore return; may be no-op if subject unchanged)
		$this->emails_service->update_email( $email_id, [ 'subject' => $subject ] );

		// Update banner metadata (and clean legacy keys) regardless of subject update result
		if ( isset( $_POST['banner_removed'] ) && (int) $_POST['banner_removed'] === 1 ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
			// Explicit removal flag wins
			$email->delete_meta( 'banner_attachment_id' );
		} elseif ( $banner_attachment_id > 0 ) {
			$email->update_meta(
				'banner_attachment_id',
				$banner_attachment_id,
				$email->get_meta( 'banner_attachment_id' )
			);
		} else {
			// Remove banner metadata if no attachment
			$email->delete_meta( 'banner_attachment_id' );
		}

		// Handle email status updates (if included in request).
		$email_statuses = filter_input( INPUT_POST, 'email_statuses', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );

		if ( is_array( $email_statuses ) ) {
			foreach ( $email_statuses as $status_email_id => $is_enabled ) {
				$status_email_id = absint( $status_email_id );
				$is_enabled      = (bool) $is_enabled;

				$status_email = $this->emails_service->get_email_by_id( $status_email_id );
				if ( $status_email && $this->emails_service->can_manage_email( $status_email ) ) {
					$this->emails_service->update_email( $status_email_id, [ 'is_enabled' => $is_enabled ] );
				}
			}
		}

		wp_send_json_success(
			[
				'message' => esc_html__( 'Email saved successfully.', 'rewardswp' ),
			]
		);
	}

	/**
	 * Handle AJAX request to toggle email enabled/disabled status.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	public function ajax_toggle_email_status(): void {
		check_ajax_referer( 'rewardswp_update_email', 'rewardswp_email_nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error(
				[
					'message' => esc_html__( 'Insufficient permissions.', 'rewardswp' ),
				]
			);
		}

		$email_id = absint( wp_unslash( $_POST['email_id'] ?? 0 ) );

		if ( ! $email_id ) {
			wp_send_json_error(
				[
					'message' => esc_html__( 'Invalid email ID.', 'rewardswp' ),
				]
			);
		}

		// Get the email
		$email = $this->emails_service->get_email_by_id( $email_id );

		if ( ! $email ) {
			wp_send_json_error(
				[
					'message' => esc_html__( 'Email not found.', 'rewardswp' ),
				]
			);
		}

		if ( ! $this->emails_service->can_manage_email( $email ) ) {
			$email_meta = $this->emails_service->get_email_with_description( $email );
			$title      = $email_meta['display_title'] ?? ucwords( str_replace( '_', ' ', $email->name ) );

			wp_send_json_error(
				[
					'message' => sprintf(
						/* translators: %s: Email title. */
						esc_html__( '%s is a RewardsWP Pro email. Upgrade to change its status.', 'rewardswp' ),
						$title
					),
				]
			);
		}

		// Toggle the status
		$updated = $this->emails_service->toggle_email_status( $email_id );

		if ( $updated ) {
			// Get updated email to return new status
			$updated_email = $this->emails_service->get_email_by_id( $email_id );

			wp_send_json_success(
				[
					'message'    => $updated_email->is_enabled
						? esc_html__( 'Email enabled successfully.', 'rewardswp' )
						: esc_html__( 'Email disabled successfully.', 'rewardswp' ),
					'is_enabled' => (bool) $updated_email->is_enabled,
				]
			);
		} else {
			wp_send_json_error(
				[
					'message' => esc_html__( 'Failed to update email status.', 'rewardswp' ),
				]
			);
		}
	}



	/**
	 * AJAX handler for getting attachment URL by size.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	public function ajax_get_attachment_url(): void {
		check_ajax_referer( self::AJAX_NONCE, '_ajax_nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( esc_html__( 'Insufficient permissions.', 'rewardswp' ) );
		}

		$attachment_id = absint( wp_unslash( $_POST['attachment_id'] ?? 0 ) );
		$size          = sanitize_text_field( wp_unslash( $_POST['size'] ?? 'medium' ) );

		if ( ! $attachment_id ) {
			wp_send_json_error( esc_html__( 'Invalid attachment ID.', 'rewardswp' ) );
		}

		$image_data = wp_get_attachment_image_src( $attachment_id, $size );

		if ( ! $image_data ) {
			wp_send_json_error( esc_html__( 'Unable to get attachment URL.', 'rewardswp' ) );
		}

		wp_send_json_success(
			[
				'url'    => $image_data[0],
				'width'  => $image_data[1],
				'height' => $image_data[2],
			]
		);
	}

	/**
	 * Get the emails management view.
	 *
	 * @since 1.1.0
	 *
	 * @return EmailsManagementView
	 */
	private function get_emails_management_view(): EmailsManagementView {
		return $this->views_factory->get_view( EmailsManagementView::class );
	}
}
