<?php
/**
 * Auto-reply templates admin page.
 *
 * @package SubmissionInbox
 */

use SUBIN\AutoReplies\AutoReplyTemplateLibrary;
use SUBIN\AutoReplies\AutoReplyTemplateRepository;
use SUBIN\AutoReplies\AutoReplyRuleRepository;
use SUBIN\AutoReplies\AutoReplyFormProviderRegistry;
use SUBIN\AutoReplies\AutoReplyConditionEngine;
use SUBIN\AutoReplies\AutoReplyPolicyService;
use SUBIN\AutoReplies\AutoReplyRuleReadiness;
use SUBIN\Forms\FormRepository;

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

/**
 * Renders auto-reply policies and the secondary saved-design library.
 */
class SUBIN_AutoRepliesPage {
	const PAGE_SLUG    = 'submission-inbox-auto-replies';
	const NONCE_ACTION = 'subin_save_auto_reply_template';
	const NONCE_NAME   = 'subin_auto_reply_template_nonce';
	const RULE_NONCE_ACTION = 'subin_save_auto_reply_rule';
	const RULE_NONCE_NAME   = 'subin_auto_reply_rule_nonce';

	/**
	 * Template repository.
	 *
	 * @var AutoReplyTemplateRepository
	 */
	private $templates;

	/**
	 * Starter template library.
	 *
	 * @var AutoReplyTemplateLibrary
	 */
	private $library;

	/**
	 * Form repository.
	 *
	 * @var FormRepository
	 */
	private $forms;

	/**
	 * Rule repository.
	 *
	 * @var AutoReplyRuleRepository
	 */
	private $rules;

	/**
	 * Provider registry.
	 *
	 * @var AutoReplyFormProviderRegistry
	 */
	private $providers;

	/**
	 * Shared policy validation and persistence service.
	 *
	 * @var AutoReplyPolicyService
	 */
	private $policy;

	/** @var AutoReplyRuleReadiness|null */
	private $readiness;

	/**
	 * Cached template usage counts.
	 *
	 * @var array<int|string,mixed>|null
	 */
	private $template_usage_counts = null;

	/** @var array<string,array{form:array<string,string>|null,fields:array<string,array<string,mixed>>}> */
	private $rule_schema_cache = array();

	/**
	 * Current error message.
	 *
	 * @var string
	 */
	private $error_message = '';

	/**
	 * Submitted template data after validation failure.
	 *
	 * @var array<string,mixed>|null
	 */
	private $submitted_template = null;

	/**
	 * Submitted rule data after validation failure.
	 *
	 * @var array<string,mixed>|null
	 */
	private $submitted_rule = null;

	/**
	 * Rule field that failed validation.
	 *
	 * @var string
	 */
	private $rule_error_field = '';

	/**
	 * Whether state-changing request handling has already run.
	 *
	 * @var bool
	 */
	private $request_handled = false;

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->templates           = new AutoReplyTemplateRepository();
		$this->library             = new AutoReplyTemplateLibrary();
		$this->forms               = new FormRepository();
		$this->rules               = new AutoReplyRuleRepository();
		$this->providers           = new AutoReplyFormProviderRegistry();
		$this->policy              = new AutoReplyPolicyService( $this->rules, $this->templates, $this->providers );
		$this->readiness           = new AutoReplyRuleReadiness( null, null, $this->rules, $this->templates );
	}

	/**
	 * Render page.
	 *
	 * @return void
	 */
	public function render() {
		if ( ! current_user_can( SUBIN_AdminMenu::CAPABILITY ) ) {
			wp_die( esc_html__( 'You do not have permission to perform this action.', 'submission-inbox' ) );
		}

		$this->handle_request();

		$view        = SUBIN_Request::get_key( 'view' );
		$rule_view   = SUBIN_Request::get_key( 'rule_view' );
		$template_id = SUBIN_Request::get_absint( 'id' );
		$tab         = $this->current_tab( $view );
		$template    = null;

		if ( 'edit' === $view && $template_id > 0 ) {
			$template = $this->templates->get( $template_id );
		}

		$this->render_page_header( $view, $tab, $template );

		$this->render_notices();

		if ( 'new' === $rule_view || ( 'edit' === $rule_view && SUBIN_Request::get_absint( 'id' ) > 0 ) ) {
			$this->render_rule_editor();
		} elseif ( 'new' === $view ) {
			$this->render_gallery();
		} elseif ( 'preview' === $view ) {
			$this->render_starter_preview();
		} elseif ( 'editor' === $view ) {
			$this->render_editor( $this->editor_template_from_request() );
		} elseif ( 'edit' === $view && $template_id > 0 ) {
			$editor_template = $this->submitted_template && $template ? array_merge( $template, $this->submitted_template ) : $template;
			if ( $editor_template ) {
				$this->render_editor( $editor_template );
			} else {
				$this->render_list( __( 'Saved email design not found.', 'submission-inbox' ) );
			}
		} elseif ( 'templates' === $tab ) {
			$this->render_list();
		} else {
			$this->render_rules_tab();
		}

		SUBIN_View::page_footer();
	}

	/**
	 * Handle redirects and state changes before admin HTML is sent.
	 *
	 * @return void
	 */
	public function handle_request() {
		if ( $this->request_handled ) {
			return;
		}

		$this->request_handled = true;

		if ( ! current_user_can( SUBIN_AdminMenu::CAPABILITY ) ) {
			wp_die( esc_html__( 'You do not have permission to perform this action.', 'submission-inbox' ) );
		}

		$this->maybe_save_rule();
		$this->maybe_handle_rule_action();
		$this->maybe_handle_row_action();
		$this->maybe_save_template();
	}

	/**
	 * Render the contextual page header.
	 *
	 * @param string $view Current view.
	 * @param string $tab Current tab.
	 * @param array<string,mixed>|null $template Current template.
	 * @return void
	 */
	private function render_page_header( $view, $tab, $template = null ) {
		if ( 'new' === $view ) {
			SUBIN_View::page_header(
				__( 'Choose a starting design', 'submission-inbox' ),
				__( 'Create a saved email design that can be inserted into an auto-reply.', 'submission-inbox' ),
				array(
					'wrapper_class' => 'subin-auto-replies-page subin-form-templates-page',
				)
			);
			return;
		}

		if ( 'preview' === $view ) {
			SUBIN_View::page_header(
				__( 'Preview starting design', 'submission-inbox' ),
				__( 'Review the email design before saving an editable copy.', 'submission-inbox' ),
				array(
					'wrapper_class' => 'subin-auto-replies-page subin-form-templates-page',
				)
			);
			return;
		}

		if ( 'editor' === $view ) {
			SUBIN_View::page_header(
				__( 'Create saved design', 'submission-inbox' ),
				__( 'Customize this reusable starting design. Auto-replies choose their form and delivery settings separately.', 'submission-inbox' ),
				array(
					'wrapper_class' => 'subin-auto-replies-page',
					'badges'        => array(
						array(
						'label' => __( 'Unsaved design', 'submission-inbox' ),
							'type'  => 'muted',
						),
					),
				)
			);
			return;
		}

		if ( 'edit' === $view ) {
			$badges = array();
				if ( is_array( $template ) && ! empty( $template['id'] ) ) {
					$used_count = $this->get_shared_rule_count( absint( $template['id'] ) );
					$badges[]   = array(
						/* translators: %s: localized number of auto-replies using the shared design. */
						'label' => sprintf( _n( '%s legacy shared auto-reply', '%s legacy shared auto-replies', $used_count, 'submission-inbox' ), number_format_i18n( $used_count ) ),
						'type'  => 'muted',
					);
					$badges[]   = array(
						/* translators: %s: date and time when the design was last edited. */
						'label' => sprintf( __( 'Last edited: %s', 'submission-inbox' ), $this->format_date( (string) ( $template['updated_at'] ?? '' ) ) ),
					'type'  => 'muted',
				);
			}

			SUBIN_View::page_header(
				__( 'Edit saved design', 'submission-inbox' ),
				__( 'Update this reusable starting design. Existing shared auto-replies may inherit future changes.', 'submission-inbox' ),
				array(
					'wrapper_class' => 'subin-auto-replies-page',
					'badges'        => $badges,
				)
			);
			return;
		}

		$is_design_library = 'templates' === $tab;
		SUBIN_View::page_header(
			$is_design_library ? __( 'Saved email designs', 'submission-inbox' ) : __( 'Auto-replies', 'submission-inbox' ),
			$is_design_library
				? __( 'Manage reusable starting designs. Forms, recipients, conditions, and delivery remain owned by auto-replies.', 'submission-inbox' )
				: __( 'Send useful visitor confirmations with content, conditions, and delivery settings in one place.', 'submission-inbox' ),
			array(
				'wrapper_class'  => 'subin-auto-replies-page',
				'primary_action' => array(
					'label' => $is_design_library ? __( 'Create saved design', 'submission-inbox' ) : __( 'Add auto-reply', 'submission-inbox' ),
					'url'   => $is_design_library ? $this->new_url() : $this->rule_edit_url( 0 ),
				),
			)
		);
	}

	/**
	 * Render rules tab.
	 *
	 * @return void
	 */
	private function render_rules_tab() {
		$per_page = 50;
		$paged    = max( 1, SUBIN_Request::get_absint( 'paged', 1 ) );
		$args = array(
			'per_page'      => $per_page,
			'offset'        => ( $paged - 1 ) * $per_page,
			'delivery_order' => true,
		);
		$provider_filter = SUBIN_Request::get_key( 'provider' );
		$form_filter     = sanitize_text_field( SUBIN_Request::get_text( 'form_id' ) );
		if ( '' !== $provider_filter && '' !== $this->rules->sanitize_provider( $provider_filter ) ) {
			$args['provider'] = $provider_filter;
		}
		if ( '' !== $form_filter ) {
			$args['form_id'] = $form_filter;
		}
		$total_rules  = $this->rules->count_rules( $args );
		$rules        = $this->rules->list_rules( $args );
		$template_ids = array_filter( array_map( 'absint', wp_list_pluck( $rules, 'template_id' ) ) );
		$templates    = $this->templates->get_by_ids( $template_ids );
		?>
		<div class="subin-forms-section subin-auto-reply-rules-section">
			<div class="subin-section-heading subin-auto-reply-section-heading">
				<div>
					<h2><?php esc_html_e( 'Auto-replies', 'submission-inbox' ); ?></h2>
					<p><?php esc_html_e( 'Auto-replies are evaluated by priority. The first published rule whose conditions match sends the visitor reply.', 'submission-inbox' ); ?></p>
				</div>
				<a class="button" href="<?php echo esc_url( $this->templates_url() ); ?>"><?php esc_html_e( 'Manage saved designs', 'submission-inbox' ); ?></a>
			</div>
			<?php if ( '' !== $form_filter ) : ?>
				<div class="subin-auto-reply-filter-notice">
					<?php /* translators: %s: form identifier used to filter auto-reply rules. */ ?>
					<span><?php echo esc_html( sprintf( __( 'Showing rules for form %s.', 'submission-inbox' ), $form_filter ) ); ?></span>
					<a href="<?php echo esc_url( $this->rules_url() ); ?>"><?php esc_html_e( 'Show all rules', 'submission-inbox' ); ?></a>
				</div>
			<?php endif; ?>

			<?php if ( empty( $rules ) ) : ?>
				<div class="subin-forms-empty-state subin-empty-state">
					<h2><?php esc_html_e( 'Send your first visitor confirmation', 'submission-inbox' ); ?></h2>
					<p><?php esc_html_e( 'Start with a simple always-send rule. Conditions, custom sender details, and delays are optional.', 'submission-inbox' ); ?></p>
					<div class="subin-forms-empty-state__actions">
						<a class="button button-primary subin-btn subin-btn-primary" href="<?php echo esc_url( add_query_arg( array_filter( array( 'provider' => $provider_filter, 'form_id' => $form_filter ) ), $this->rule_edit_url( 0 ) ) ); ?>"><?php esc_html_e( 'Create confirmation', 'submission-inbox' ); ?></a>
					</div>
				</div>
				<?php return; ?>
			<?php endif; ?>

			<div class="subin-auto-reply-rules-table-wrap" tabindex="0" role="region" aria-label="<?php esc_attr_e( 'Auto-reply rules', 'submission-inbox' ); ?>">
			<table class="widefat subin-auto-reply-rules-table">
				<thead>
					<tr>
						<th><?php esc_html_e( 'Rule', 'submission-inbox' ); ?></th>
						<th><?php esc_html_e( 'Form & recipient', 'submission-inbox' ); ?></th>
						<th><?php esc_html_e( 'Conditions', 'submission-inbox' ); ?></th>
						<th><?php esc_html_e( 'Content', 'submission-inbox' ); ?></th>
						<th><?php esc_html_e( 'Timing', 'submission-inbox' ); ?></th>
						<th><?php esc_html_e( 'State', 'submission-inbox' ); ?></th>
						<th><span class="screen-reader-text"><?php esc_html_e( 'Actions', 'submission-inbox' ); ?></span></th>
					</tr>
				</thead>
				<tbody>
					<?php foreach ( $rules as $rule ) : ?>
						<?php $this->render_rule_row( $rule, $templates[ absint( $rule['template_id'] ?? 0 ) ] ?? null ); ?>
					<?php endforeach; ?>
				</tbody>
			</table>
			</div>
			<?php if ( $total_rules > $per_page ) : ?>
				<div class="tablenav"><div class="tablenav-pages">
					<?php
					$pagination_url = add_query_arg(
						array_filter(
							array(
								'provider' => $provider_filter,
								'form_id'  => $form_filter,
							)
						),
						$this->rules_url()
					);
					echo wp_kses_post(
						paginate_links(
							array(
								'base'      => add_query_arg( 'paged', '%#%', $pagination_url ),
								'format'    => '',
								'current'   => $paged,
								'total'     => max( 1, (int) ceil( $total_rules / $per_page ) ),
								'prev_text' => __( 'Previous', 'submission-inbox' ),
								'next_text' => __( 'Next', 'submission-inbox' ),
							)
						)
					);
					?>
				</div></div>
			<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * Render one rule row.
	 *
	 * @param array<string,mixed>      $rule Rule.
	 * @param array<string,mixed>|null $template Template.
	 * @return void
	 */
	private function render_rule_row( array $rule, $template = null ) {
		$rule_id    = absint( $rule['id'] ?? 0 );
		$status     = $this->rule_status_details( $rule, $template );
		$conditions = is_array( $rule['conditions'] ?? null ) ? $rule['conditions'] : array();
		$condition_count = count( $conditions );
		$is_draft   = AutoReplyRuleRepository::STATUS_DRAFT === ( $rule['status'] ?? '' );
		$has_independent_message = ! empty( $rule['readiness_projection'] )
			? ! empty( $rule['readiness_subject_override'] ) || ! empty( $rule['readiness_body_override'] )
			: '' !== trim( (string) ( $rule['subject'] ?? '' ) ) || '' !== trim( (string) ( $rule['body'] ?? '' ) );
		?>
		<tr>
				<td class="subin-auto-reply-rule-cell">
					<a class="subin-auto-reply-rule-name" href="<?php echo esc_url( $this->rule_edit_url( $rule_id ) ); ?>"><?php echo esc_html( (string) ( $rule['name'] ?? __( 'Untitled rule', 'submission-inbox' ) ) ); ?></a>
					<?php /* translators: %1$d: rule priority, %2$d: rule revision number. */ ?>
					<span><?php echo esc_html( sprintf( __( 'Priority %1$d · revision %2$d', 'submission-inbox' ), absint( $rule['priority'] ?? AutoReplyRuleRepository::DEFAULT_PRIORITY ), absint( $rule['rule_version'] ?? 1 ) ) ); ?></span>
			</td>
			<td class="subin-auto-reply-rule-cell">
				<strong><?php echo esc_html( (string) ( $rule['form_name'] ?: $rule['form_id'] ) ); ?></strong>
				<span><?php echo esc_html( $this->providers->provider_label( (string) ( $rule['provider'] ?? '' ) ) ); ?> · <?php echo esc_html( (string) ( $rule['visitor_email_field_label'] ?: $rule['visitor_email_field'] ) ); ?></span>
				</td>
				<td class="subin-auto-reply-rule-cell">
					<?php /* translators: %1$s: condition matching mode (Any or All), %2$d: number of conditions. */ ?>
					<strong><?php echo esc_html( 0 === $condition_count ? __( 'Always', 'submission-inbox' ) : sprintf( _n( '%1$s of %2$d condition', '%1$s of %2$d conditions', $condition_count, 'submission-inbox' ), 'any' === ( $rule['condition_match'] ?? 'all' ) ? __( 'Any', 'submission-inbox' ) : __( 'All', 'submission-inbox' ), $condition_count ) ); ?></strong>
				<span><?php echo esc_html( 0 === $condition_count ? __( 'No conditions', 'submission-inbox' ) : __( 'First match wins', 'submission-inbox' ) ); ?></span>
			</td>
			<td class="subin-auto-reply-rule-cell">
				<?php if ( $template ) : ?>
					<strong><?php echo esc_html( (string) ( $template['name'] ?? '' ) ); ?></strong>
					<span><?php esc_html_e( 'Legacy shared design · make independent to edit here', 'submission-inbox' ); ?></span>
				<?php elseif ( $has_independent_message ) : ?>
					<strong><?php esc_html_e( 'Independent message', 'submission-inbox' ); ?></strong>
					<span><?php esc_html_e( 'Editable directly in this rule', 'submission-inbox' ); ?></span>
				<?php else : ?>
					<strong><?php esc_html_e( 'Content missing', 'submission-inbox' ); ?></strong>
					<span><?php esc_html_e( 'Open rule to repair', 'submission-inbox' ); ?></span>
				<?php endif; ?>
			</td>
			<td class="subin-auto-reply-rule-cell">
				<strong><?php echo esc_html( AutoReplyRuleRepository::DELIVERY_DELAY === ( $rule['delivery_mode'] ?? '' ) ? $this->format_rule_delay( absint( $rule['delay_seconds'] ?? 0 ) ) : __( 'Immediately', 'submission-inbox' ) ); ?></strong>
				<span><?php echo esc_html( $this->format_date( (string) ( $rule['updated_at'] ?? '' ) ) ); ?></span>
			</td>
			<td class="subin-auto-reply-rule-state"><?php SUBIN_View::badge( $status['label'], $status['type'] ); ?></td>
			<td class="subin-auto-reply-rule-actions">
				<a class="button button-small" href="<?php echo esc_url( $this->rule_edit_url( $rule_id ) ); ?>"><?php esc_html_e( 'Edit', 'submission-inbox' ); ?></a>
				<details class="subin-auto-reply-rule-menu">
					<summary class="button button-small" aria-label="<?php esc_attr_e( 'More rule actions', 'submission-inbox' ); ?>"><span class="dashicons dashicons-ellipsis" aria-hidden="true"></span></summary>
					<div>
						<a href="<?php echo esc_url( $this->rule_action_url( 'duplicate', $rule_id ) ); ?>"><?php esc_html_e( 'Duplicate as draft', 'submission-inbox' ); ?></a>
						<a href="<?php echo esc_url( $this->rule_action_url( ! empty( $rule['enabled'] ) && ! $is_draft ? 'disable' : 'enable', $rule_id ) ); ?>"><?php echo esc_html( ! empty( $rule['enabled'] ) && ! $is_draft ? __( 'Disable', 'submission-inbox' ) : __( 'Publish & enable', 'submission-inbox' ) ); ?></a>
						<a class="subin-action-chip-danger" href="<?php echo esc_url( $this->rule_action_url( 'delete', $rule_id ) ); ?>" onclick="return window.confirm('<?php echo esc_js( __( 'Delete this sending rule?', 'submission-inbox' ) ); ?>');"><?php esc_html_e( 'Delete', 'submission-inbox' ); ?></a>
					</div>
				</details>
			</td>
		</tr>
		<?php
	}

	/**
	 * Render Add/Edit rule screen.
	 *
	 * @return void
	 */
	private function render_rule_editor() {
		$rule_id = SUBIN_Request::get_absint( 'id' );
		$rule    = $rule_id > 0 ? $this->rules->find( $rule_id ) : null;
		if ( $rule_id > 0 && ! $rule ) {
			?>
			<div class="subin-forms-empty-state subin-empty-state">
				<h2><?php esc_html_e( 'Auto-reply rule not found', 'submission-inbox' ); ?></h2>
				<p><?php esc_html_e( 'This rule may have been deleted in another browser session.', 'submission-inbox' ); ?></p>
				<a class="button button-primary" href="<?php echo esc_url( $this->rules_url() ); ?>"><?php esc_html_e( 'Back to sending rules', 'submission-inbox' ); ?></a>
			</div>
			<?php
			return;
		}
		$rule    = $rule ? $rule : $this->empty_rule();
		if ( is_array( $this->submitted_rule ) ) {
			$rule = array_merge( $rule, $this->submitted_rule );
		}
		if ( $rule_id <= 0 ) {
			$rule['provider'] = SUBIN_Request::get_key( 'provider' ) ?: AutoReplyRuleRepository::PROVIDER_SUBMISSION_INBOX_FORM;
			$rule['form_id']  = sanitize_text_field( SUBIN_Request::get_text( 'form_id' ) );
			$requested_template_id = SUBIN_Request::get_absint( 'template_id' );
			if ( $requested_template_id > 0 ) {
				$loaded_design = $this->policy->load_design( AutoReplyPolicyService::DESIGN_TYPE_SAVED, $requested_template_id );
				if ( ! is_wp_error( $loaded_design ) && is_array( $loaded_design['design'] ?? null ) ) {
					$rule['template_id'] = 0;
					$rule['body']        = (string) ( $loaded_design['design']['body'] ?? '' );
				}
			}
		}

		$provider                  = $this->rules->sanitize_provider( (string) ( $rule['provider'] ?? '' ) ) ?: AutoReplyRuleRepository::PROVIDER_SUBMISSION_INBOX_FORM;
		$form_id                   = sanitize_text_field( (string) ( $rule['form_id'] ?? '' ) );
		$form_choice               = $this->providers->get_form( $provider, $form_id );
		$email_fields              = $this->providers->list_email_fields( $provider, $form_id );
		$all_forms                 = $this->provider_form_choices( $provider );
		$all_email_fields          = $this->provider_email_field_choices( $provider, $form_id );
		$saved_design_page_size    = 24;
		$saved_designs             = $this->templates->get_choice_metadata( array( 'per_page' => $saved_design_page_size, 'offset' => 0 ) );
		$saved_design_total        = $this->templates->count();
		$starter_designs           = $this->library->all();
		$selected_template_id      = absint( $rule['template_id'] ?? 0 );
		$selected_template         = $selected_template_id > 0 ? $this->templates->get( $selected_template_id ) : null;
		$uses_shared_design        = $selected_template_id > 0 && is_array( $selected_template );
		$shared_design_usage       = $uses_shared_design ? $this->get_shared_rule_count( $selected_template_id ) : 0;
		$conditions                = is_array( $rule['conditions'] ?? null ) ? array_values( $rule['conditions'] ) : array();
		$conditions_doc            = array(
			'version'    => AutoReplyConditionEngine::VERSION,
			'mode'       => 'any' === ( $rule['condition_match'] ?? '' ) ? 'any' : 'all',
			'conditions' => $conditions,
		);
		$conditions_json           = wp_json_encode( $conditions_doc );
		$status                    = $this->rule_status_details( $rule, $selected_template );
		$is_published              = AutoReplyRuleRepository::STATUS_PUBLISHED === ( $rule['status'] ?? '' );
		$delay_minutes             = max( 1, (int) ceil( absint( $rule['delay_seconds'] ?? 0 ) / 60 ) );
		$has_sender                = '' !== trim( (string) ( $rule['from_name'] ?? '' ) ) || '' !== trim( (string) ( $rule['from_email'] ?? '' ) ) || '' !== trim( (string) ( $rule['reply_to_name'] ?? '' ) ) || '' !== trim( (string) ( $rule['reply_to_email'] ?? '' ) );
		?>
		<div class="subin-auto-reply-rule-editor-shell" data-subin-auto-reply-rules-editor data-rule-id="<?php echo esc_attr( (string) $rule_id ); ?>">
			<a class="subin-back-link" href="<?php echo esc_url( $this->rules_url() ); ?>"><?php esc_html_e( 'Back to sending rules', 'submission-inbox' ); ?></a>
			<form method="post" action="" class="subin-auto-reply-rule-editor" data-subin-auto-reply-rule-form>
				<?php wp_nonce_field( self::RULE_NONCE_ACTION, self::RULE_NONCE_NAME ); ?>
				<input type="hidden" name="subin_auto_reply_rule_save" value="1" />
				<input type="hidden" name="rule_id" value="<?php echo esc_attr( (string) $rule_id ); ?>" data-subin-rule-id />
				<input type="hidden" name="expected_version" value="<?php echo esc_attr( (string) ( $rule_id > 0 ? absint( $rule['rule_version'] ?? 1 ) : 0 ) ); ?>" />
				<input type="hidden" name="status" value="<?php echo esc_attr( (string) ( $rule['status'] ?? AutoReplyRuleRepository::STATUS_DRAFT ) ); ?>" data-subin-rule-status />
				<input type="hidden" name="conditions_json" value="<?php echo esc_attr( is_string( $conditions_json ) ? $conditions_json : '{&quot;version&quot;:1,&quot;mode&quot;:&quot;all&quot;,&quot;conditions&quot;:[]}' ); ?>" data-subin-conditions-json />
				<input type="hidden" name="delay_seconds" value="<?php echo esc_attr( (string) absint( $rule['delay_seconds'] ?? 0 ) ); ?>" data-subin-delay-seconds />
				<input type="hidden" name="template_id" value="<?php echo esc_attr( (string) $selected_template_id ); ?>" data-subin-rule-template-id />

				<div class="subin-auto-reply-rule-editor__main">
					<section class="subin-auto-reply-policy-card subin-auto-reply-policy-card--basics">
						<header class="subin-auto-reply-policy-card__header">
							<div>
								<span class="subin-auto-reply-policy-card__eyebrow"><?php esc_html_e( 'Visitor confirmation', 'submission-inbox' ); ?></span>
								<h2><?php echo esc_html( $rule_id > 0 ? __( 'Edit auto-reply rule', 'submission-inbox' ) : __( 'Create auto-reply rule', 'submission-inbox' ) ); ?></h2>
								<p><?php esc_html_e( 'Choose a form and recipient field. Everything else can stay at its safe default.', 'submission-inbox' ); ?></p>
							</div>
							<div data-subin-rule-state-badge><?php SUBIN_View::badge( $status['label'], $status['type'] ); ?></div>
						</header>

						<div class="subin-auto-reply-policy-grid">
							<div class="<?php echo esc_attr( $this->rule_field_class( 'name' ) ); ?>">
								<label for="subin-rule-name"><?php esc_html_e( 'Rule name', 'submission-inbox' ); ?></label>
								<input id="subin-rule-name" type="text" name="name" value="<?php echo esc_attr( (string) ( $rule['name'] ?? '' ) ); ?>" placeholder="<?php esc_attr_e( 'Visitor confirmation', 'submission-inbox' ); ?>" <?php echo 'name' === $this->rule_error_field ? 'aria-invalid="true"' : ''; ?> />
								<p><?php esc_html_e( 'Internal label. If blank, the form name is used.', 'submission-inbox' ); ?></p>
								<?php $this->render_rule_field_error( 'name', __( 'Enter a short internal name for this auto-reply rule.', 'submission-inbox' ) ); ?>
							</div>
							<div class="<?php echo esc_attr( $this->rule_field_class( 'provider' ) ); ?>">
								<label for="subin-rule-provider"><?php esc_html_e( 'Provider', 'submission-inbox' ); ?></label>
								<select id="subin-rule-provider" name="provider" <?php echo 'provider' === $this->rule_error_field ? 'aria-invalid="true"' : ''; ?>>
									<?php foreach ( $this->providers->providers() as $item ) : ?>
										<option value="<?php echo esc_attr( $item['key'] ); ?>" <?php selected( $provider, $item['key'] ); ?> <?php disabled( empty( $item['forms'] ) ); ?>><?php echo esc_html( $item['label'] ); ?></option>
									<?php endforeach; ?>
								</select>
								<?php $this->render_rule_field_error( 'provider', __( 'Provider is required.', 'submission-inbox' ) ); ?>
							</div>
							<div class="<?php echo esc_attr( $this->rule_field_class( 'form' ) ); ?>">
								<label for="subin-rule-form"><?php esc_html_e( 'Form', 'submission-inbox' ); ?></label>
								<select id="subin-rule-form" name="form_id" data-subin-rule-form-select <?php echo 'form' === $this->rule_error_field ? 'aria-invalid="true"' : ''; ?>>
									<option value=""><?php esc_html_e( 'Select form', 'submission-inbox' ); ?></option>
									<?php foreach ( $all_forms as $form ) : ?>
										<option value="<?php echo esc_attr( $form['value'] ); ?>" data-subin-provider="<?php echo esc_attr( $form['provider'] ); ?>" <?php selected( $provider . '|' . $form_id, $form['value'] ); ?> <?php echo $provider === $form['provider'] ? '' : 'hidden'; ?>><?php echo esc_html( $form['label'] ); ?></option>
									<?php endforeach; ?>
								</select>
								<?php $this->render_rule_field_error( 'form', __( 'Select the form that should send this auto-reply.', 'submission-inbox' ) ); ?>
							</div>
							<div class="<?php echo esc_attr( $this->rule_field_class( 'visitor_email_field' ) ); ?>">
								<label for="subin-rule-email-field"><?php esc_html_e( 'Send to', 'submission-inbox' ); ?></label>
								<select id="subin-rule-email-field" name="visitor_email_field" data-subin-rule-email-field-select <?php disabled( empty( $all_email_fields ) || '' === $form_id ); ?> <?php echo 'visitor_email_field' === $this->rule_error_field ? 'aria-invalid="true"' : ''; ?>>
									<option value=""><?php esc_html_e( 'Select visitor email field', 'submission-inbox' ); ?></option>
									<?php foreach ( $all_email_fields as $field ) : ?>
										<?php $field_visible = $provider === $field['provider'] && '' !== $form_id && $provider . '|' . $form_id === $field['form_value']; ?>
										<option value="<?php echo esc_attr( $field['value'] ); ?>" data-subin-provider="<?php echo esc_attr( $field['provider'] ); ?>" data-subin-form-value="<?php echo esc_attr( $field['form_value'] ); ?>" <?php selected( $provider . '|' . $form_id . '|' . (string) ( $rule['visitor_email_field'] ?? '' ), $field['value'] ); ?> <?php echo $field_visible ? '' : 'hidden'; ?>><?php echo esc_html( $field['label'] ); ?></option>
									<?php endforeach; ?>
								</select>
								<p><?php esc_html_e( 'The address is validated again when the form is submitted.', 'submission-inbox' ); ?></p>
								<?php $this->render_rule_field_error( 'visitor_email_field', __( 'Select the email field that contains the visitor address.', 'submission-inbox' ) ); ?>
								<?php if ( $form_choice && empty( $email_fields ) ) : ?><p class="subin-settings-warning"><?php esc_html_e( 'This form has no supported email field.', 'submission-inbox' ); ?></p><?php endif; ?>
							</div>
						</div>

						<label class="subin-settings-toggle subin-auto-reply-enabled-toggle">
							<input type="checkbox" name="enabled" value="1" <?php checked( ! empty( $rule['enabled'] ) ); ?> data-subin-rule-enabled />
							<span></span>
							<strong><?php esc_html_e( 'Enabled after publishing', 'submission-inbox' ); ?></strong>
						</label>
					</section>

					<section class="subin-auto-reply-policy-card" data-subin-content-card>
						<header class="subin-auto-reply-policy-card__header">
							<div>
								<h2><?php esc_html_e( 'Message', 'submission-inbox' ); ?></h2>
								<p><?php esc_html_e( 'The final subject and email body are stored with this auto-reply, so you can change only the words you need.', 'submission-inbox' ); ?></p>
							</div>
							<button type="button" class="button" data-subin-open-design-picker><?php esc_html_e( 'Choose starting design', 'submission-inbox' ); ?></button>
						</header>

						<?php if ( $uses_shared_design ) : ?>
							<div class="subin-auto-reply-shared-design" data-subin-shared-design data-design-id="<?php echo esc_attr( (string) $selected_template_id ); ?>">
								<div>
									<span class="subin-auto-reply-shared-design__eyebrow"><?php esc_html_e( 'Legacy shared design', 'submission-inbox' ); ?></span>
									<strong><?php echo esc_html( (string) ( $selected_template['name'] ?? __( 'Saved design', 'submission-inbox' ) ) ); ?></strong>
									<?php /* translators: %d: number of auto-replies affected by changes to the shared design. */ ?>
									<p><?php echo esc_html( sprintf( _n( 'Changes to the shared design can affect %d auto-reply.', 'Changes to the shared design can affect %d auto-replies.', $shared_design_usage, 'submission-inbox' ), $shared_design_usage ) ); ?></p>
								</div>
								<div class="subin-auto-reply-shared-design__actions">
									<a class="button" href="<?php echo esc_url( $this->edit_url( $selected_template_id ) ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Edit shared design', 'submission-inbox' ); ?><span class="screen-reader-text"><?php esc_html_e( ' (opens in a new tab)', 'submission-inbox' ); ?></span></a>
									<button type="button" class="button button-primary" data-subin-detach-design><?php esc_html_e( 'Make this message independent', 'submission-inbox' ); ?></button>
								</div>
							</div>
						<?php elseif ( $selected_template_id > 0 ) : ?>
							<div class="subin-settings-warning" data-subin-missing-design-warning>
								<strong><?php esc_html_e( 'The previously shared design is missing.', 'submission-inbox' ); ?></strong>
								<p><?php esc_html_e( 'Choose a starting design or add message content before publishing.', 'submission-inbox' ); ?></p>
							</div>
						<?php endif; ?>

						<div class="subin-auto-reply-message-editor" data-subin-message-editor <?php echo $uses_shared_design ? 'hidden' : ''; ?>>
							<div class="<?php echo esc_attr( $this->rule_field_class( 'content' ) ); ?>">
								<label for="subin-rule-subject"><?php esc_html_e( 'Email subject', 'submission-inbox' ); ?></label>
								<input id="subin-rule-subject" type="text" name="subject" value="<?php echo esc_attr( (string) ( $rule['subject'] ?? '' ) ); ?>" placeholder="<?php esc_attr_e( 'We received your request', 'submission-inbox' ); ?>" data-subin-merge-target />
							</div>
							<div class="<?php echo esc_attr( $this->rule_field_class( 'preheader' ) ); ?>">
								<label for="subin-rule-preheader"><?php esc_html_e( 'Preview text', 'submission-inbox' ); ?> <span class="subin-field-optional"><?php esc_html_e( 'Optional', 'submission-inbox' ); ?></span></label>
								<input id="subin-rule-preheader" type="text" name="preheader" maxlength="500" value="<?php echo esc_attr( (string) ( $rule['preheader'] ?? '' ) ); ?>" placeholder="<?php esc_attr_e( 'Shown next to the subject in many inboxes', 'submission-inbox' ); ?>" data-subin-merge-target />
								<p><?php esc_html_e( 'Hidden in the email itself and included consistently in preview, tests, and delivery.', 'submission-inbox' ); ?></p>
								<?php $this->render_rule_field_error( 'preheader', __( 'Shorten the preview text.', 'submission-inbox' ) ); ?>
							</div>
							<div class="<?php echo esc_attr( $this->rule_field_class( 'content' ) ); ?>">
								<label for="subin_rule_body_editor"><?php esc_html_e( 'Email body', 'submission-inbox' ); ?></label>
								<div class="subin-auto-reply-rule-wp-editor" data-subin-rule-wp-editor>
									<?php
									wp_editor(
										(string) ( $rule['body'] ?? '' ),
										'subin_rule_body_editor',
										array(
											'textarea_name' => 'body',
											'textarea_rows' => 18,
											'media_buttons' => true,
											'teeny'         => false,
											'quicktags'     => true,
											'tinymce'       => array(
												'wpautop'  => false,
												'toolbar1' => 'formatselect,fontsizeselect,bold,italic,underline,forecolor,alignleft,aligncenter,alignright,bullist,numlist,link,unlink,removeformat',
												'toolbar2' => 'undo,redo,pastetext,charmap,hr,blockquote,code',
											),
										)
									);
									?>
								</div>
								<?php $this->render_rule_field_error( 'content', __( 'Add a subject and body, or insert a starting design.', 'submission-inbox' ) ); ?>
							</div>
							<div class="subin-auto-reply-merge-picker" data-subin-merge-picker>
								<span><?php esc_html_e( 'Insert variable', 'submission-inbox' ); ?></span>
								<div data-subin-merge-tags>
									<?php foreach ( $this->variable_groups() as $variables ) : ?>
										<?php foreach ( $variables as $variable => $label ) : ?>
											<button type="button" class="button button-small" data-subin-merge-tag="<?php echo esc_attr( $variable ); ?>" title="<?php echo esc_attr( $label ); ?>"><?php echo esc_html( $variable ); ?></button>
										<?php endforeach; ?>
									<?php endforeach; ?>
								</div>
							</div>
						</div>

						<div class="subin-auto-reply-design-picker" role="dialog" aria-modal="true" aria-hidden="true" aria-labelledby="subin-design-picker-title" data-subin-design-picker hidden>
							<button type="button" class="subin-auto-reply-design-picker__backdrop" data-subin-close-design-picker tabindex="-1" aria-label="<?php esc_attr_e( 'Close design picker', 'submission-inbox' ); ?>"></button>
							<div class="subin-auto-reply-design-picker__panel">
								<header>
									<div><h3 id="subin-design-picker-title"><?php esc_html_e( 'Choose a starting design', 'submission-inbox' ); ?></h3><p><?php esc_html_e( 'Only the layout and email body are copied. Subject and preview text stay with this auto-reply.', 'submission-inbox' ); ?></p></div>
									<button type="button" class="button-link" data-subin-close-design-picker aria-label="<?php esc_attr_e( 'Close design picker', 'submission-inbox' ); ?>"><span class="dashicons dashicons-no-alt" aria-hidden="true"></span></button>
								</header>
								<label class="subin-auto-reply-design-picker__search"><span><?php esc_html_e( 'Search designs', 'submission-inbox' ); ?></span><input type="search" data-subin-design-search placeholder="<?php esc_attr_e( 'Search by design name', 'submission-inbox' ); ?>" /></label>
								<div class="subin-auto-reply-design-picker__content" data-subin-design-list>
									<section data-subin-design-group="starter">
										<h4><?php esc_html_e( 'Starter designs', 'submission-inbox' ); ?></h4>
										<div class="subin-auto-reply-design-grid">
											<?php foreach ( $starter_designs as $design ) : ?>
											<article class="subin-auto-reply-design-card" data-subin-design-card data-design-search="<?php echo esc_attr( (string) ( $design['name'] ?? '' ) . ' ' . (string) ( $design['description'] ?? '' ) ); ?>">
												<span><?php esc_html_e( 'Starter', 'submission-inbox' ); ?></span><h5><?php echo esc_html( (string) ( $design['name'] ?? '' ) ); ?></h5><p><?php echo esc_html( (string) ( $design['description'] ?? '' ) ); ?></p>
													<button type="button" class="button button-primary" data-subin-insert-design data-design-type="starter" data-design-key="<?php echo esc_attr( (string) ( $design['key'] ?? '' ) ); ?>"><?php esc_html_e( 'Insert and customize', 'submission-inbox' ); ?></button>
												</article>
											<?php endforeach; ?>
										</div>
									</section>
									<section data-subin-design-group="saved">
										<div class="subin-auto-reply-design-group-heading"><h4><?php esc_html_e( 'Saved designs', 'submission-inbox' ); ?></h4><a href="<?php echo esc_url( $this->templates_url() ); ?>"><?php esc_html_e( 'Manage saved designs', 'submission-inbox' ); ?></a></div>
										<p class="subin-auto-reply-design-empty" data-subin-saved-design-empty <?php echo empty( $saved_designs ) ? '' : 'hidden'; ?>><?php esc_html_e( 'No saved designs yet. Starter designs are ready to use.', 'submission-inbox' ); ?></p>
										<div class="subin-auto-reply-design-grid" data-subin-saved-design-grid>
											<?php foreach ( $saved_designs as $design ) : ?>
											<article class="subin-auto-reply-design-card" data-subin-design-card data-design-search="<?php echo esc_attr( (string) ( $design['name'] ?? '' ) ); ?>">
												<span><?php esc_html_e( 'Saved', 'submission-inbox' ); ?></span><h5><?php echo esc_html( (string) ( $design['name'] ?? '' ) ); ?></h5><p><?php esc_html_e( 'Reusable email layout and content', 'submission-inbox' ); ?></p>
													<button type="button" class="button button-primary" data-subin-insert-design data-design-type="saved" data-design-id="<?php echo esc_attr( (string) absint( $design['id'] ?? 0 ) ); ?>"><?php esc_html_e( 'Insert and customize', 'submission-inbox' ); ?></button>
												</article>
											<?php endforeach; ?>
										</div>
										<button type="button" class="button subin-auto-reply-design-load-more" data-subin-load-more-designs <?php echo $saved_design_total > $saved_design_page_size ? '' : 'hidden'; ?>><?php esc_html_e( 'Load more saved designs', 'submission-inbox' ); ?></button>
									</section>
									<p class="subin-auto-reply-design-no-results" data-subin-design-no-results hidden><?php esc_html_e( 'No designs match your search.', 'submission-inbox' ); ?></p>
								</div>
								<div class="subin-auto-reply-design-picker__feedback" data-subin-design-feedback aria-live="polite"></div>
							</div>
						</div>
					</section>

					<details class="subin-auto-reply-policy-card subin-auto-reply-disclosure" <?php echo ! empty( $conditions ) ? 'open' : ''; ?>>
						<summary><span><strong><?php esc_html_e( 'Conditions', 'submission-inbox' ); ?></strong><small><?php esc_html_e( 'Optional · send only when submitted values match', 'submission-inbox' ); ?></small></span><b data-subin-condition-count><?php echo esc_html( empty( $conditions ) ? __( 'Always', 'submission-inbox' ) : (string) count( $conditions ) ); ?></b></summary>
						<div class="subin-auto-reply-disclosure__body">
							<div class="subin-auto-reply-condition-mode">
								<label for="subin-rule-condition-match"><?php esc_html_e( 'Send when', 'submission-inbox' ); ?></label>
								<select id="subin-rule-condition-match" name="condition_match" data-subin-condition-mode><option value="all" <?php selected( 'all', $rule['condition_match'] ?? 'all' ); ?>><?php esc_html_e( 'All conditions match', 'submission-inbox' ); ?></option><option value="any" <?php selected( 'any', $rule['condition_match'] ?? 'all' ); ?>><?php esc_html_e( 'Any condition matches', 'submission-inbox' ); ?></option></select>
							</div>
							<div class="subin-auto-reply-conditions" data-subin-condition-list>
								<?php foreach ( $conditions as $condition_index => $condition ) : ?><?php $this->render_rule_condition_row( is_array( $condition ) ? $condition : array(), $condition_index ); ?><?php endforeach; ?>
							</div>
							<div class="subin-auto-reply-condition-empty" data-subin-condition-empty <?php echo empty( $conditions ) ? '' : 'hidden'; ?>><strong><?php esc_html_e( 'Always send', 'submission-inbox' ); ?></strong><span><?php esc_html_e( 'No conditions are configured for this rule.', 'submission-inbox' ); ?></span></div>
							<button type="button" class="button" data-subin-add-condition><?php esc_html_e( 'Add condition', 'submission-inbox' ); ?></button>
							<?php $this->render_rule_field_error( 'conditions', __( 'Review the highlighted condition values.', 'submission-inbox' ) ); ?>
						</div>
					</details>

					<details class="subin-auto-reply-policy-card subin-auto-reply-disclosure" <?php echo $has_sender ? 'open' : ''; ?>>
						<summary><span><strong><?php esc_html_e( 'Sender & replies', 'submission-inbox' ); ?></strong><small><?php esc_html_e( 'Optional · defaults to your configured WordPress mail identity', 'submission-inbox' ); ?></small></span></summary>
						<div class="subin-auto-reply-disclosure__body subin-auto-reply-policy-grid">
							<div class="subin-settings-field"><label for="subin-rule-from-name"><?php esc_html_e( 'From name', 'submission-inbox' ); ?></label><input id="subin-rule-from-name" type="text" name="from_name" value="<?php echo esc_attr( (string) ( $rule['from_name'] ?? '' ) ); ?>" /></div>
							<div class="subin-settings-field"><label for="subin-rule-from-email"><?php esc_html_e( 'From email', 'submission-inbox' ); ?></label><input id="subin-rule-from-email" type="email" name="from_email" value="<?php echo esc_attr( (string) ( $rule['from_email'] ?? '' ) ); ?>" /></div>
							<div class="subin-settings-field"><label for="subin-rule-reply-name"><?php esc_html_e( 'Reply-To name', 'submission-inbox' ); ?></label><input id="subin-rule-reply-name" type="text" name="reply_to_name" value="<?php echo esc_attr( (string) ( $rule['reply_to_name'] ?? '' ) ); ?>" /></div>
							<div class="subin-settings-field"><label for="subin-rule-reply-email"><?php esc_html_e( 'Reply-To email', 'submission-inbox' ); ?></label><input id="subin-rule-reply-email" type="email" name="reply_to_email" value="<?php echo esc_attr( (string) ( $rule['reply_to_email'] ?? '' ) ); ?>" /></div>
						</div>
					</details>

					<details class="subin-auto-reply-policy-card subin-auto-reply-disclosure" <?php echo AutoReplyRuleRepository::DELIVERY_DELAY === ( $rule['delivery_mode'] ?? '' ) ? 'open' : ''; ?>>
						<summary><span><strong><?php esc_html_e( 'Timing & priority', 'submission-inbox' ); ?></strong><small><?php esc_html_e( 'Optional · immediate delivery and priority 100 are safe defaults', 'submission-inbox' ); ?></small></span></summary>
						<div class="subin-auto-reply-disclosure__body subin-auto-reply-policy-grid">
							<div class="subin-settings-field"><label for="subin-rule-delivery-mode"><?php esc_html_e( 'Delivery', 'submission-inbox' ); ?></label><select id="subin-rule-delivery-mode" name="delivery_mode" data-subin-delivery-mode><option value="immediate" <?php selected( AutoReplyRuleRepository::DELIVERY_IMMEDIATE, $rule['delivery_mode'] ?? AutoReplyRuleRepository::DELIVERY_IMMEDIATE ); ?>><?php esc_html_e( 'Immediately', 'submission-inbox' ); ?></option><option value="delay" <?php selected( AutoReplyRuleRepository::DELIVERY_DELAY, $rule['delivery_mode'] ?? '' ); ?>><?php esc_html_e( 'After a delay', 'submission-inbox' ); ?></option></select></div>
							<div class="subin-settings-field" data-subin-delay-field <?php echo AutoReplyRuleRepository::DELIVERY_DELAY === ( $rule['delivery_mode'] ?? '' ) ? '' : 'hidden'; ?>><label for="subin-rule-delay-minutes"><?php esc_html_e( 'Delay in minutes', 'submission-inbox' ); ?></label><input id="subin-rule-delay-minutes" type="number" name="delay_minutes" min="1" max="10080" step="1" value="<?php echo esc_attr( (string) $delay_minutes ); ?>" data-subin-delay-minutes /></div>
							<div class="subin-settings-field"><label for="subin-rule-priority"><?php esc_html_e( 'Priority', 'submission-inbox' ); ?></label><input id="subin-rule-priority" type="number" name="priority" min="0" max="10000" step="1" value="<?php echo esc_attr( (string) absint( $rule['priority'] ?? AutoReplyRuleRepository::DEFAULT_PRIORITY ) ); ?>" /><p><?php esc_html_e( 'Lower numbers are checked first.', 'submission-inbox' ); ?></p></div>
						</div>
					</details>
				</div>

				<aside class="subin-auto-reply-rule-editor__preview" aria-label="<?php esc_attr_e( 'Preview and testing', 'submission-inbox' ); ?>">
					<div class="subin-auto-reply-preview-panel">
						<header><div><span><?php esc_html_e( 'Safe preview', 'submission-inbox' ); ?></span><h2 data-subin-preview-subject><?php esc_html_e( 'Choose a form to preview', 'submission-inbox' ); ?></h2><p data-subin-preview-preheader hidden></p></div><button type="button" class="button" data-subin-refresh-preview><?php esc_html_e( 'Refresh', 'submission-inbox' ); ?></button></header>
						<div class="subin-auto-reply-sample-fields" data-subin-sample-fields><p><?php esc_html_e( 'Sample form values will appear here after the form is selected.', 'submission-inbox' ); ?></p></div>
						<iframe title="<?php esc_attr_e( 'Auto-reply email preview', 'submission-inbox' ); ?>" sandbox="" srcdoc="<?php echo esc_attr( '<!doctype html><html><body style="font:14px sans-serif;color:#64748b;padding:24px">' . esc_html__( 'Preview will appear here.', 'submission-inbox' ) . '</body></html>' ); ?>" data-subin-preview-frame></iframe>
						<div class="subin-auto-reply-preview-diagnostics" data-subin-preview-diagnostics aria-live="polite"></div>
					</div>

					<div class="subin-auto-reply-test-panel">
						<h3><?php esc_html_e( 'Check this rule', 'submission-inbox' ); ?></h3>
						<p><?php esc_html_e( 'Simulation never sends email. A test send uses only the address entered below.', 'submission-inbox' ); ?></p>
						<button type="button" class="button" data-subin-simulate><?php esc_html_e( 'Run safe simulation', 'submission-inbox' ); ?></button>
						<div class="subin-auto-reply-simulation-result" data-subin-simulation-result aria-live="polite"></div>
						<label for="subin-rule-test-email"><?php esc_html_e( 'Test recipient', 'submission-inbox' ); ?></label>
						<div class="subin-auto-reply-test-row"><input id="subin-rule-test-email" type="email" inputmode="email" placeholder="name@example.com" data-subin-test-email /><button type="button" class="button" data-subin-test-send><?php esc_html_e( 'Send test', 'submission-inbox' ); ?></button></div>
						<div data-subin-test-result aria-live="polite"></div>
					</div>
				</aside>

				<footer class="subin-auto-reply-rule-savebar">
					<div><strong data-subin-save-title><?php echo esc_html( $is_published ? __( 'Published rule', 'submission-inbox' ) : __( 'Draft rule', 'submission-inbox' ) ); ?></strong><span data-subin-rule-feedback aria-live="polite"><?php esc_html_e( 'Changes are not saved automatically.', 'submission-inbox' ); ?></span></div>
					<div class="subin-auto-reply-rule-savebar__actions">
						<button type="submit" class="button" name="rule_intent" value="draft" data-subin-save-intent="draft"><?php esc_html_e( 'Save draft', 'submission-inbox' ); ?></button>
						<button type="submit" class="button button-primary" name="rule_intent" value="<?php echo esc_attr( $is_published ? 'save' : 'publish' ); ?>" data-subin-save-intent="<?php echo esc_attr( $is_published ? 'save' : 'publish' ); ?>"><?php echo esc_html( $is_published ? __( 'Save changes', 'submission-inbox' ) : __( 'Publish & enable', 'submission-inbox' ) ); ?></button>
					</div>
				</footer>
			</form>
		</div>
		<script type="application/json" id="subin-auto-reply-rule-data"><?php echo str_replace( '</script', '<\/script', wp_json_encode( array( 'rule' => $rule, 'conditions' => $conditions_doc ) ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JSON is encoded and the script-close sequence is escaped. ?></script>
		<?php
	}

	/**
	 * Build field wrapper class for rule editor validation.
	 *
	 * @param string $field Field key.
	 * @return string
	 */
	private function rule_field_class( $field ) {
		$classes = array( 'subin-settings-field' );
		if ( $field === $this->rule_error_field ) {
			$classes[] = 'subin-settings-field--error';
		}

		return implode( ' ', $classes );
	}

	/**
	 * Render inline rule field validation help.
	 *
	 * @param string $field Field key.
	 * @param string $message Message.
	 * @return void
	 */
	private function render_rule_field_error( $field, $message ) {
		if ( $field !== $this->rule_error_field ) {
			return;
		}
		?>
		<p class="subin-settings-field-error"><?php echo esc_html( $message ); ?></p>
		<?php
	}

	/**
	 * Render one progressively enhanced condition row.
	 *
	 * @param array<string,mixed> $condition Condition.
	 * @param int                 $index Condition index.
	 * @return void
	 */
	private function render_rule_condition_row( array $condition, $index = 0 ) {
		$field    = sanitize_key( (string) ( $condition['field'] ?? '' ) );
		$type     = sanitize_key( (string) ( $condition['type'] ?? 'text' ) );
		$operator = sanitize_key( (string) ( $condition['operator'] ?? 'equals' ) );
		$value    = $condition['value'] ?? '';
		if ( is_array( $value ) ) {
			$value = implode( ', ', array_map( 'strval', $value ) );
		} elseif ( ! is_scalar( $value ) ) {
			$value = '';
		}
		$field_types = array(
			'text'     => __( 'Text', 'submission-inbox' ),
			'email'    => __( 'Email', 'submission-inbox' ),
			'url'      => __( 'URL', 'submission-inbox' ),
			'tel'      => __( 'Phone', 'submission-inbox' ),
			'textarea' => __( 'Long text', 'submission-inbox' ),
			'choice'   => __( 'Choice', 'submission-inbox' ),
			'select'   => __( 'Select', 'submission-inbox' ),
			'radio'    => __( 'Radio', 'submission-inbox' ),
			'checkbox' => __( 'Checkbox', 'submission-inbox' ),
			'consent'  => __( 'Consent', 'submission-inbox' ),
			'number'   => __( 'Number', 'submission-inbox' ),
			'date'     => __( 'Date', 'submission-inbox' ),
			'datetime' => __( 'Date and time', 'submission-inbox' ),
			'time'     => __( 'Time', 'submission-inbox' ),
		);
		?>
		<div class="subin-auto-reply-condition-row" data-subin-condition-row>
			<span class="subin-auto-reply-condition-row__handle" aria-hidden="true">⋮⋮</span>
			<label><span class="screen-reader-text"><?php esc_html_e( 'Field', 'submission-inbox' ); ?></span><select name="conditions[<?php echo esc_attr( (string) absint( $index ) ); ?>][field]" data-subin-condition-field><option value=""><?php esc_html_e( 'Choose field', 'submission-inbox' ); ?></option><?php if ( '' !== $field ) : ?><option value="<?php echo esc_attr( $field ); ?>" selected><?php echo esc_html( $field ); ?></option><?php endif; ?></select></label>
			<label><span class="screen-reader-text"><?php esc_html_e( 'Field type', 'submission-inbox' ); ?></span><select name="conditions[<?php echo esc_attr( (string) absint( $index ) ); ?>][type]" data-subin-condition-type><?php foreach ( $field_types as $key => $label ) : ?><option value="<?php echo esc_attr( $key ); ?>" <?php selected( $type, $key ); ?>><?php echo esc_html( $label ); ?></option><?php endforeach; ?></select></label>
			<label><span class="screen-reader-text"><?php esc_html_e( 'Operator', 'submission-inbox' ); ?></span><select name="conditions[<?php echo esc_attr( (string) absint( $index ) ); ?>][operator]" data-subin-condition-operator><?php foreach ( $this->condition_operator_labels() as $key => $label ) : ?><option value="<?php echo esc_attr( $key ); ?>" <?php selected( $operator, $key ); ?>><?php echo esc_html( $label ); ?></option><?php endforeach; ?></select></label>
			<label><span class="screen-reader-text"><?php esc_html_e( 'Expected value', 'submission-inbox' ); ?></span><input type="text" name="conditions[<?php echo esc_attr( (string) absint( $index ) ); ?>][value]" value="<?php echo esc_attr( (string) $value ); ?>" placeholder="<?php esc_attr_e( 'Value', 'submission-inbox' ); ?>" data-subin-condition-value /></label>
			<button type="button" class="button-link subin-auto-reply-condition-remove" data-subin-remove-condition aria-label="<?php esc_attr_e( 'Remove condition', 'submission-inbox' ); ?>"><span class="dashicons dashicons-no-alt" aria-hidden="true"></span></button>
		</div>
		<?php
	}

	/**
	 * Human labels for all server-supported condition operators.
	 *
	 * @return array<string,string>
	 */
	private function condition_operator_labels() {
		return array(
			'equals'                => __( 'is', 'submission-inbox' ),
			'not_equals'            => __( 'is not', 'submission-inbox' ),
			'contains'              => __( 'contains', 'submission-inbox' ),
			'not_contains'          => __( 'does not contain', 'submission-inbox' ),
			'starts_with'           => __( 'starts with', 'submission-inbox' ),
			'ends_with'             => __( 'ends with', 'submission-inbox' ),
			'is_empty'              => __( 'is empty', 'submission-inbox' ),
			'is_not_empty'          => __( 'is not empty', 'submission-inbox' ),
			'in'                    => __( 'is one of', 'submission-inbox' ),
			'not_in'                => __( 'is not one of', 'submission-inbox' ),
			'greater_than'          => __( 'is greater than', 'submission-inbox' ),
			'greater_than_or_equal' => __( 'is at least', 'submission-inbox' ),
			'less_than'             => __( 'is less than', 'submission-inbox' ),
			'less_than_or_equal'    => __( 'is at most', 'submission-inbox' ),
			'before'                => __( 'is before', 'submission-inbox' ),
			'after'                 => __( 'is after', 'submission-inbox' ),
			'on_or_before'          => __( 'is on or before', 'submission-inbox' ),
			'on_or_after'           => __( 'is on or after', 'submission-inbox' ),
			'between'               => __( 'is between', 'submission-inbox' ),
			'not_between'           => __( 'is not between', 'submission-inbox' ),
		);
	}

	/**
	 * Store rule validation error state.
	 *
	 * @param string $field Field key.
	 * @param string $message Message.
	 * @return void
	 */
	private function set_rule_error( $field, $message ) {
		$this->rule_error_field = sanitize_key( $field );
		$this->error_message    = $message;
	}

	/**
	 * Project a canonical policy-service error onto the SSR editor.
	 *
	 * @param \WP_Error $error Policy error.
	 * @return void
	 */
	private function set_policy_error( \WP_Error $error ) {
		$data   = (array) $error->get_error_data();
		$fields = is_array( $data['fields'] ?? null ) ? $data['fields'] : array();
		$path   = (string) key( $fields );
		$field  = $path;
		if ( 'form_id' === $path ) {
			$field = 'form';
		} elseif ( 'template_id' === $path ) {
			$field = 'template';
		} elseif ( in_array( $path, array( 'subject', 'body' ), true ) ) {
			$field = 'content';
		} elseif ( 0 === strpos( $path, 'conditions' ) ) {
			$field = 'conditions';
		} elseif ( 0 === strpos( $path, 'from.' ) || 0 === strpos( $path, 'reply_to.' ) ) {
			$field = 'sender';
		} elseif ( 0 === strpos( $path, 'delivery.' ) || 'priority' === $path ) {
			$field = 'timing';
		}

		$this->rule_error_field = sanitize_key( $field );
		$this->error_message    = $error->get_error_message();
	}

	/**
	 * Render list view.
	 *
	 * @param string $message Optional inline message.
	 * @return void
	 */
	private function render_list( $message = '' ) {
		$templates = $this->templates->get_paginated(
			array(
				'per_page' => 50,
				'offset'   => 0,
			)
		);
		?>
		<?php if ( '' !== $message ) : ?>
			<div class="notice notice-error"><p><?php echo esc_html( $message ); ?></p></div>
		<?php endif; ?>

		<a class="subin-back-link" href="<?php echo esc_url( $this->rules_url() ); ?>"><?php esc_html_e( 'Back to auto-replies', 'submission-inbox' ); ?></a>
		<div class="subin-forms-section subin-auto-replies-section">
			<div class="subin-section-heading">
				<h2><?php esc_html_e( 'Saved email designs', 'submission-inbox' ); ?></h2>
				<p><?php esc_html_e( 'Manage reusable starting points for auto-reply content. Sending behavior remains configured in Auto-replies.', 'submission-inbox' ); ?></p>
			</div>

			<?php if ( empty( $templates ) ) : ?>
				<div class="subin-forms-empty-state subin-empty-state">
					<h2><?php esc_html_e( 'No saved designs yet', 'submission-inbox' ); ?></h2>
					<p><?php esc_html_e( 'Create a reusable email design, or choose a starter directly while editing an auto-reply.', 'submission-inbox' ); ?></p>
					<div class="subin-forms-empty-state__actions">
						<a class="button button-primary subin-btn subin-btn-primary" href="<?php echo esc_url( $this->new_url() ); ?>"><?php esc_html_e( 'Create saved design', 'submission-inbox' ); ?></a>
					</div>
				</div>
				<?php return; ?>
			<?php endif; ?>

			<div class="subin-auto-reply-card-list">
				<?php foreach ( $templates as $template ) : ?>
					<?php $this->render_template_card( $template ); ?>
				<?php endforeach; ?>
			</div>
		</div>
		<?php
	}

	/**
	 * Render one template card.
	 *
	 * @param array<string,mixed> $template Template row.
	 * @return void
	 */
	private function render_template_card( array $template ) {
		$template_id = absint( $template['id'] ?? 0 );
		$name        = (string) ( $template['name'] ?? __( 'Untitled design', 'submission-inbox' ) );
		$used_count  = $this->get_shared_rule_count( $template_id );
		$used_rules  = $this->get_rules_using_template( $template_id );
		$is_used     = $used_count > 0;
		?>
		<article class="subin-auto-reply-card subin-auto-reply-card--manager<?php echo $is_used ? ' subin-auto-reply-card--used' : ' subin-auto-reply-card--unused'; ?>">
			<div class="subin-auto-reply-card__preview">
				<?php $this->render_template_mini_preview( $template ); ?>
			</div>

			<div class="subin-auto-reply-card__content">
				<div class="subin-auto-reply-card__main">
					<div class="subin-auto-reply-card__title-row">
						<div class="subin-auto-reply-card__identity">
							<span class="subin-auto-reply-card__icon dashicons dashicons-email-alt2" aria-hidden="true"></span>
							<h3><a href="<?php echo esc_url( $this->edit_url( $template_id ) ); ?>"><?php echo esc_html( $name ); ?></a></h3>
						</div>
						<?php SUBIN_View::badge( $is_used ? __( 'Used', 'submission-inbox' ) : __( 'Not used', 'submission-inbox' ), $is_used ? 'success' : 'muted' ); ?>
					</div>

					<div class="subin-auto-reply-card__meta subin-meta">
						<span><?php esc_html_e( 'Last edited', 'submission-inbox' ); ?>: <?php echo esc_html( $this->format_date( (string) ( $template['updated_at'] ?? '' ) ) ); ?></span>
						<span><?php esc_html_e( 'Legacy shared links', 'submission-inbox' ); ?>: <?php echo esc_html( (string) $used_count ); ?></span>
					</div>

					<?php $this->render_shared_rules( $used_rules, $used_count ); ?>

				</div>

				<div class="subin-card-actions">
					<a class="button button-primary subin-btn subin-btn-primary" href="<?php echo esc_url( $this->edit_url( $template_id ) ); ?>"><?php esc_html_e( 'Edit design', 'submission-inbox' ); ?></a>
					<a class="subin-action-chip" href="<?php echo esc_url( $this->action_url( 'duplicate', $template_id ) ); ?>"><?php esc_html_e( 'Duplicate', 'submission-inbox' ); ?></a>
					<a class="subin-action-chip subin-action-chip-danger" href="<?php echo esc_url( $this->action_url( 'delete', $template_id ) ); ?>" onclick="return window.confirm('<?php echo esc_js( __( 'Delete this saved email design?', 'submission-inbox' ) ); ?>');"><?php esc_html_e( 'Delete', 'submission-inbox' ); ?></a>
				</div>
			</div>
		</article>
		<?php
	}

	/**
	 * Build template status display details.
	 *
	 * @param string $status Raw status.
	 * @return array{label:string,type:string}
	 */
	private function template_status_details( $status ) {
		$status = sanitize_key( $status );

		if ( AutoReplyTemplateRepository::STATUS_DRAFT === $status ) {
			return array(
				'label' => __( 'Draft', 'submission-inbox' ),
				'type'  => 'warning',
			);
		}

		if ( 'inactive' === $status ) {
			return array(
				'label' => __( 'Inactive', 'submission-inbox' ),
				'type'  => 'muted',
			);
		}

		return array(
			'label' => __( 'Active', 'submission-inbox' ),
			'type'  => 'success',
		);
	}

	/**
	 * Render compact supported variables row.
	 *
	 * @return void
	 */
	private function render_variables_row() {
		$variables = array();
		foreach ( $this->variable_groups() as $group_variables ) {
			foreach ( array_keys( $group_variables ) as $variable ) {
				$variables[] = $variable;
			}
		}
		$variables = array_slice( $variables, 0, 7 );
		?>
		<div class="subin-auto-reply-variables">
			<span class="subin-auto-reply-variables__label"><?php esc_html_e( 'Available variables', 'submission-inbox' ); ?></span>
			<div class="subin-auto-reply-variables__chips">
				<?php foreach ( $variables as $variable ) : ?>
					<code><?php echo esc_html( $variable ); ?></code>
				<?php endforeach; ?>
			</div>
		</div>
		<?php
	}

	/**
	 * Render starter template gallery.
	 *
	 * @return void
	 */
	private function render_gallery() {
		?>
		<a class="subin-back-link" href="<?php echo esc_url( $this->list_url() ); ?>"><?php esc_html_e( 'Back to saved designs', 'submission-inbox' ); ?></a>

		<div class="subin-template-grid subin-auto-reply-gallery">
			<?php foreach ( $this->library->all() as $template ) : ?>
				<div class="subin-template-card">
					<div class="subin-template-card__badge"><?php esc_html_e( 'Starter design', 'submission-inbox' ); ?></div>
					<h2 class="subin-template-card__title"><?php echo esc_html( $template['name'] ); ?></h2>
					<p class="subin-template-card__description"><?php echo esc_html( $template['description'] ); ?></p>
					<div class="subin-template-preview subin-auto-reply-template-preview" aria-hidden="true">
						<div class="subin-template-preview__viewport">
							<div class="subin-template-preview__scale subin-auto-reply-template-preview__scale">
								<style><?php echo esc_html( (string) ( $template['css'] ?? '' ) ); ?></style>
								<?php echo wp_kses( (string) ( $template['html'] ?? '' ), $this->email_preview_allowed_html(), array( 'http', 'https', 'mailto', 'tel' ) ); ?>
							</div>
						</div>
					</div>
					<div class="subin-template-card__actions">
						<a class="button button-primary subin-btn subin-btn-primary" href="<?php echo esc_url( $this->starter_editor_url( $template['key'] ) ); ?>"><?php esc_html_e( 'Customize design', 'submission-inbox' ); ?></a>
						<a class="button subin-btn subin-btn-secondary" href="<?php echo esc_url( $this->starter_preview_url( $template['key'] ) ); ?>"><?php esc_html_e( 'Preview', 'submission-inbox' ); ?></a>
					</div>
				</div>
			<?php endforeach; ?>
		</div>
		<?php
	}

	/**
	 * Render a larger starter template preview.
	 *
	 * @return void
	 */
	private function render_starter_preview() {
		$template_key = SUBIN_Request::get_key( 'template_key' );
		$template     = $this->library->get( $template_key );

		if ( ! $template ) {
			?>
			<a class="subin-back-link" href="<?php echo esc_url( $this->new_url() ); ?>"><?php esc_html_e( 'Back to starter designs', 'submission-inbox' ); ?></a>
			<div class="notice notice-error"><p><?php esc_html_e( 'Starter email design not found.', 'submission-inbox' ); ?></p></div>
			<?php
			return;
		}
		?>
		<div class="subin-page-actions">
			<a class="button button-primary subin-btn subin-btn-primary" href="<?php echo esc_url( $this->starter_editor_url( $template['key'] ) ); ?>"><?php esc_html_e( 'Customize design', 'submission-inbox' ); ?></a>
			<a class="button subin-btn subin-btn-secondary" href="<?php echo esc_url( $this->new_url() ); ?>"><?php esc_html_e( 'Back to starter designs', 'submission-inbox' ); ?></a>
		</div>
		<div class="subin-notice-box">
			<?php esc_html_e( 'This is a preview. “Customize design” opens an editable copy, so you can change only the words you need before saving it.', 'submission-inbox' ); ?>
		</div>

		<div class="subin-template-preview-screen">
			<div class="subin-template-preview-screen__content">
				<div class="subin-template-card__badge"><?php esc_html_e( 'Starter design', 'submission-inbox' ); ?></div>
				<h2><?php echo esc_html( $template['name'] ); ?></h2>
				<p><?php echo esc_html( $template['description'] ); ?></p>
				<p><?php esc_html_e( 'Subject and preview text are configured in each auto-reply rule.', 'submission-inbox' ); ?></p>
			</div>
			<div class="subin-template-preview-screen__visual">
				<div class="subin-template-preview subin-template-preview--large subin-auto-reply-template-preview" aria-hidden="true">
					<div class="subin-template-preview__viewport">
						<div class="subin-template-preview__scale subin-auto-reply-template-preview__scale">
							<style><?php echo esc_html( (string) ( $template['css'] ?? '' ) ); ?></style>
							<?php echo wp_kses( (string) ( $template['html'] ?? '' ), $this->email_preview_allowed_html(), array( 'http', 'https', 'mailto', 'tel' ) ); ?>
						</div>
					</div>
				</div>
			</div>
		</div>
		<?php
	}

	/**
	 * Render editor view.
	 *
	 * @param array<string,mixed>|null $template Template row.
	 * @return void
	 */
	private function render_editor( $template = null ) {
		$template = $template ? $template : $this->empty_template();
		$is_edit  = ! empty( $template['id'] );
		$template_id = absint( $template['id'] ?? 0 );
		$editor_html = $this->template_editor_html( $template );
		$save_label  = $is_edit ? __( 'Save changes', 'submission-inbox' ) : __( 'Save design', 'submission-inbox' );
		?>
		<div class="subin-auto-reply-editor">
			<a class="subin-back-link" href="<?php echo esc_url( $this->list_url() ); ?>"><?php esc_html_e( 'Back to saved designs', 'submission-inbox' ); ?></a>
				<form method="post" action="" class="subin-auto-reply-editor-form" data-subin-auto-reply-editor-form>
					<?php wp_nonce_field( self::NONCE_ACTION, self::NONCE_NAME ); ?>
					<input type="hidden" name="subin_auto_reply_save" value="1" />
					<input type="hidden" name="template_id" value="<?php echo esc_attr( (string) $template_id ); ?>" />
					<input type="hidden" name="template_key" value="<?php echo esc_attr( (string) ( $template['template_key'] ?? '' ) ); ?>" />

				<div class="subin-email-editor-shell">
					<section class="subin-email-settings-card">
						<div class="subin-email-settings-header">
							<div>
								<h3><?php esc_html_e( 'Design details', 'submission-inbox' ); ?></h3>
								<p><?php esc_html_e( 'Name this reusable design. Subject and preview text are configured in each auto-reply rule.', 'submission-inbox' ); ?></p>
							</div>
						</div>
						<div class="subin-email-settings-grid">
							<div class="subin-field subin-template-name-field">
								<label class="subin-field-label" for="subin-auto-reply-name"><?php esc_html_e( 'Design name', 'submission-inbox' ); ?></label>
								<input id="subin-auto-reply-name" class="subin-input subin-template-name" name="name" type="text" value="<?php echo esc_attr( (string) $template['name'] ); ?>" placeholder="<?php esc_attr_e( 'Request confirmation', 'submission-inbox' ); ?>" required />
							</div>
						</div>
					</section>

					<div class="subin-workspace-header">
						<div>
							<div class="subin-workspace-title"><?php esc_html_e( 'Email layout', 'submission-inbox' ); ?></div>
							<p class="subin-workspace-note"><?php esc_html_e( 'Click inside the email and edit only the text you need. The rest of the design stays in place.', 'submission-inbox' ); ?></p>
						</div>
						<div class="subin-preview-actions">
							<span class="subin-auto-reply-editable-badge"><?php esc_html_e( 'Editable', 'submission-inbox' ); ?></span>
							<button type="submit" class="subin-save-btn"><?php echo esc_html( $save_label ); ?></button>
						</div>
					</div>

					<div class="subin-auto-reply-workspace">
						<div class="subin-auto-reply-editor__main">
							<div class="subin-auto-reply-wp-editor-panel">
								<?php
								wp_editor(
									$editor_html,
									'subin_auto_reply_body_editor',
									array(
										'textarea_name' => 'body',
										'textarea_rows' => 24,
										'media_buttons' => true,
										'teeny'         => false,
										'quicktags'     => true,
										'tinymce'       => array(
											'wpautop'      => false,
											'toolbar1'     => 'formatselect,fontsizeselect,bold,italic,underline,forecolor,backcolor,alignleft,aligncenter,alignright,bullist,numlist,link,unlink,removeformat',
											'toolbar2'     => 'undo,redo,pastetext,charmap,hr,blockquote,code',
											'fontsize_formats' => '11px 12px 13px 14px 15px 16px 18px 20px 22px 24px 28px 32px 36px 42px 48px',
											'plugins'      => 'charmap colorpicker compat3x directionality hr lists media paste tabfocus textcolor wordpress wpautoresize wpdialogs wpeditimage wpemoji wpgallery wplink wptextpattern wpview',
										),
									)
								);
								?>
							</div>
						</div>

				<div class="subin-auto-reply-editor__side">
						<aside class="subin-auto-reply-side-panel subin-email-side-panel">
							<div class="subin-auto-reply-side-tabs subin-email-panel-tabs" role="tablist" aria-label="<?php esc_attr_e( 'Design tools', 'submission-inbox' ); ?>">
							<button type="button" class="subin-auto-reply-side-tab subin-email-panel-tab is-active subin-auto-reply-side-tab--active" data-subin-auto-reply-tab="variables" data-panel="variables"><?php esc_html_e( 'Variables', 'submission-inbox' ); ?></button>
						</div>
						<div class="subin-email-panel-body">
						<section id="subin-auto-reply-variables" class="subin-auto-reply-side-section subin-email-panel-view is-active" data-subin-auto-reply-panel="variables" data-panel-view="variables">
						<h2><?php esc_html_e( 'Variables', 'submission-inbox' ); ?></h2>
						<p class="description"><?php esc_html_e( 'General placeholders work in every auto-reply. Field placeholders are checked against the form selected in each rule.', 'submission-inbox' ); ?></p>
						<?php foreach ( $this->variable_groups() as $group_label => $variables ) : ?>
							<h3 class="subin-variable-group-heading"><?php echo esc_html( $group_label ); ?></h3>
							<div class="subin-variable-list">
								<?php foreach ( $variables as $variable => $label ) : ?>
									<div class="subin-variable-item subin-variable-card">
										<div>
											<code><?php echo esc_html( $variable ); ?></code>
											<div class="subin-variable-label"><?php echo esc_html( $label ); ?></div>
										</div>
										<button type="button" class="subin-copy-shortcode" data-subin-copy="<?php echo esc_attr( $variable ); ?>"><?php esc_html_e( 'Insert', 'submission-inbox' ); ?></button>
										<span class="subin-copy-feedback" aria-live="polite"></span>
									</div>
								<?php endforeach; ?>
							</div>
						<?php endforeach; ?>
						</section>
					</div>
					</aside>
					</div>
				</div>
					<div class="subin-sticky-save-bar">
						<div>
							<strong><?php esc_html_e( 'Email content', 'submission-inbox' ); ?></strong>
							<span><?php esc_html_e( 'Save changes before leaving this design.', 'submission-inbox' ); ?></span>
						</div>
						<button type="submit" class="subin-save-btn"><?php echo esc_html( $save_label ); ?></button>
					</div>
				</div>
			</form>
		</div>
		<?php
	}

	/**
	 * Save submitted template.
	 *
	 * @return void
	 */
	private function maybe_save_template() {
		$request_method = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ?? '' ) );
		if ( 'POST' !== strtoupper( $request_method ) || empty( $_POST['subin_auto_reply_save'] ) ) {
			return;
		}

		if ( ! current_user_can( SUBIN_AdminMenu::CAPABILITY ) ) {
			$this->error_message = __( 'You do not have permission to perform this action.', 'submission-inbox' );
			return;
		}

		if ( ! isset( $_POST[ self::NONCE_NAME ] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[ self::NONCE_NAME ] ) ), self::NONCE_ACTION ) ) {
			$this->error_message = __( 'Security check failed. Please try again.', 'submission-inbox' );
			return;
		}

		$template_id = isset( $_POST['template_id'] ) ? absint( wp_unslash( $_POST['template_id'] ) ) : 0;
		$data        = array(
			'template_key'  => $this->posted_string( 'template_key' ),
			'name'          => $this->posted_string( 'name' ),
			'status'        => AutoReplyTemplateRepository::STATUS_ACTIVE,
			'body'          => $this->posted_string( 'body' ),
			'project_json'  => '',
			'rendered_html' => $this->posted_string( 'body' ),
			'rendered_css'  => '',
		);
		$data['body'] = $data['rendered_html'];

		if ( '' === sanitize_text_field( is_scalar( $data['name'] ) ? (string) $data['name'] : '' ) ) {
			$this->error_message      = __( 'Design name is required.', 'submission-inbox' );
			$this->submitted_template = array_merge( $this->empty_template(), $data, array( 'id' => $template_id ) );
			return;
		}

		if ( $template_id > 0 ) {
			$saved = $this->templates->update_content( $template_id, $data );
			if ( $saved ) {
				$this->redirect_to_edit( $template_id, 'template_saved' );
			}
		} else {
			$template_id = $this->templates->create( $data );
			if ( $template_id > 0 ) {
				$this->redirect_to_edit( $template_id, 'template_created' );
			}
		}

		$this->error_message      = __( 'Email design could not be saved.', 'submission-inbox' );
		$this->submitted_template = array_merge( $this->empty_template(), $data, array( 'id' => $template_id ) );
	}

	/**
	 * Resolve editable HTML without treating an empty legacy body as authoritative.
	 *
	 * @param array<string,mixed> $template Template row.
	 * @return string
	 */
	private function template_editor_html( array $template ) {
		$body = (string) ( $template['body'] ?? '' );
		if ( '' !== trim( $body ) ) {
			return $body;
		}

		return (string) ( $template['rendered_html'] ?? '' );
	}

	/**
	 * Save submitted rule.
	 *
	 * @return void
	 */
	private function maybe_save_rule() {
		$request_method = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ?? '' ) );
		if ( 'POST' !== strtoupper( $request_method ) || empty( $_POST['subin_auto_reply_rule_save'] ) ) {
			return;
		}

		if ( ! current_user_can( SUBIN_AdminMenu::CAPABILITY ) ) {
			$this->error_message = __( 'You do not have permission to perform this action.', 'submission-inbox' );
			return;
		}

		if ( ! isset( $_POST[ self::RULE_NONCE_NAME ] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[ self::RULE_NONCE_NAME ] ) ), self::RULE_NONCE_ACTION ) ) {
			$this->error_message = __( 'Security check failed. Please try again.', 'submission-inbox' );
			return;
		}

		$rule_id  = isset( $_POST['rule_id'] ) ? absint( wp_unslash( $_POST['rule_id'] ) ) : 0;
		$current_rule = $rule_id > 0 ? $this->rules->find( $rule_id ) : null;
		$provider = $this->rules->sanitize_provider( sanitize_key( wp_unslash( $_POST['provider'] ?? '' ) ) );
		$form_id  = sanitize_text_field( wp_unslash( $_POST['form_id'] ?? '' ) );
		if ( false !== strpos( $form_id, '|' ) ) {
			$form_parts = explode( '|', $form_id, 2 );
			$provider   = $this->rules->sanitize_provider( $form_parts[0] ?? $provider );
			$form_id    = sanitize_text_field( $form_parts[1] ?? '' );
		}
		$field_key = sanitize_text_field( wp_unslash( $_POST['visitor_email_field'] ?? '' ) );
		if ( false !== strpos( $field_key, '|' ) ) {
			$field_parts = explode( '|', $field_key, 3 );
			$provider    = $this->rules->sanitize_provider( $field_parts[0] ?? $provider );
			$form_id     = sanitize_text_field( $field_parts[1] ?? $form_id );
			$field_key   = sanitize_key( $field_parts[2] ?? '' );
		} else {
			$field_key = sanitize_key( $field_key );
		}
		$form     = $this->providers->get_form( $provider, $form_id );
		$field    = $this->providers->get_email_field( $provider, $form_id, $field_key );
		$template_id = absint( wp_unslash( $_POST['template_id'] ?? 0 ) );
		$template    = $template_id > 0 ? $this->templates->get( $template_id ) : null;
		$intent      = sanitize_key( wp_unslash( $_POST['rule_intent'] ?? '' ) );
		$status      = sanitize_key( wp_unslash( $_POST['status'] ?? ( $current_rule['status'] ?? AutoReplyRuleRepository::STATUS_PUBLISHED ) ) );
		$enabled     = ! empty( $_POST['enabled'] ) ? 1 : 0;
		if ( 'draft' === $intent ) {
			$status  = AutoReplyRuleRepository::STATUS_DRAFT;
			$enabled = 0;
		} elseif ( 'publish' === $intent ) {
			$status  = AutoReplyRuleRepository::STATUS_PUBLISHED;
			$enabled = 1;
		} elseif ( 'save' === $intent && is_array( $current_rule ) ) {
			$status = (string) ( $current_rule['status'] ?? AutoReplyRuleRepository::STATUS_DRAFT );
		}
		if ( ! in_array( $status, array( AutoReplyRuleRepository::STATUS_DRAFT, AutoReplyRuleRepository::STATUS_PUBLISHED ), true ) ) {
			$status = AutoReplyRuleRepository::STATUS_DRAFT;
			$enabled = 0;
		}

		$subject = sanitize_text_field( wp_unslash( $_POST['subject'] ?? '' ) );
		$preheader = sanitize_textarea_field( wp_unslash( $_POST['preheader'] ?? '' ) );
		$body    = isset( $_POST['body'] ) && is_string( $_POST['body'] ) ? wp_unslash( $_POST['body'] ) : '';
		$from_name      = sanitize_text_field( wp_unslash( $_POST['from_name'] ?? '' ) );
		$from_email_raw = trim( (string) wp_unslash( $_POST['from_email'] ?? '' ) );
		$reply_name     = sanitize_text_field( wp_unslash( $_POST['reply_to_name'] ?? '' ) );
		$reply_raw      = trim( (string) wp_unslash( $_POST['reply_to_email'] ?? '' ) );
		$from_email     = sanitize_email( $from_email_raw );
		$reply_email    = sanitize_email( $reply_raw );
		$delivery_mode  = sanitize_key( wp_unslash( $_POST['delivery_mode'] ?? AutoReplyRuleRepository::DELIVERY_IMMEDIATE ) );
		$delay_minutes  = min( 10080, max( 1, absint( wp_unslash( $_POST['delay_minutes'] ?? 1 ) ) ) );
		$delay_seconds  = AutoReplyRuleRepository::DELIVERY_DELAY === $delivery_mode ? $delay_minutes * 60 : 0;
		$priority       = min( AutoReplyRuleRepository::MAX_PRIORITY, absint( wp_unslash( $_POST['priority'] ?? AutoReplyRuleRepository::DEFAULT_PRIORITY ) ) );
		$condition_match = 'any' === sanitize_key( wp_unslash( $_POST['condition_match'] ?? 'all' ) ) ? 'any' : 'all';
		$raw_conditions  = isset( $_POST['conditions_json'] ) && is_string( $_POST['conditions_json'] ) ? wp_unslash( $_POST['conditions_json'] ) : '';
		$conditions_doc  = '' !== trim( $raw_conditions ) ? json_decode( $raw_conditions, true ) : array();
		if ( ! is_array( $conditions_doc ) || ( empty( $conditions_doc ) && isset( $_POST['conditions'] ) && is_array( $_POST['conditions'] ) ) ) {
			$conditions_doc = array(
				'version'    => AutoReplyConditionEngine::VERSION,
				'mode'       => $condition_match,
				'conditions' => isset( $_POST['conditions'] ) && is_array( $_POST['conditions'] ) ? wp_unslash( $_POST['conditions'] ) : array(),
			);
		}
		$condition_engine = new AutoReplyConditionEngine();
		$condition_errors = $condition_engine->validate_conditions( $conditions_doc, $condition_match );
		$conditions_doc   = $condition_engine->sanitize_conditions( $conditions_doc, $condition_match );
		unset( $conditions_doc['valid'] );

		$submitted   = array(
			'id'                          => $rule_id,
			'name'                        => sanitize_text_field( wp_unslash( $_POST['name'] ?? '' ) ),
			'provider'                    => $provider,
			'form_id'                     => $form_id,
			'form_name'                   => $form ? $form['label'] : '',
			'visitor_email_field'         => $field_key,
			'visitor_email_field_label'   => $field ? $field['label'] : '',
			'template_id'                 => $template_id,
			'enabled'                     => $enabled,
			'status'                      => $status,
			'rule_version'                => isset( $_POST['expected_version'] ) ? max( 1, absint( wp_unslash( $_POST['expected_version'] ) ) ) : max( 1, absint( $current_rule['rule_version'] ?? 1 ) ),
			'priority'                    => $priority,
			'condition_match'             => $condition_match,
			'conditions'                  => $conditions_doc['conditions'] ?? array(),
			'conditions_document'         => $conditions_doc,
			'subject'                     => $subject,
			'preheader'                   => $preheader,
			'body'                        => $body,
			'from_name'                   => $from_name,
			'from_email'                  => $from_email,
			'reply_to_name'               => $reply_name,
			'reply_to_email'              => $reply_email,
			'delivery_mode'               => AutoReplyRuleRepository::DELIVERY_DELAY === $delivery_mode ? AutoReplyRuleRepository::DELIVERY_DELAY : AutoReplyRuleRepository::DELIVERY_IMMEDIATE,
			'delay_seconds'               => $delay_seconds,
		);
		$this->submitted_rule = array_merge( $this->empty_rule(), $submitted );

		if ( '' === $provider ) {
			$this->set_rule_error( 'provider', __( 'Provider is required.', 'submission-inbox' ) );
			return;
		}
		if ( ! $form ) {
			$this->set_rule_error( 'form', __( 'Select the form that should send this auto-reply.', 'submission-inbox' ) );
			return;
		}
		if ( ! $field && AutoReplyRuleRepository::STATUS_PUBLISHED === $status ) {
			$this->set_rule_error( 'visitor_email_field', __( 'Select the visitor email field for this form.', 'submission-inbox' ) );
			return;
		}
		if ( $template_id > 0 && ! $template ) {
			$this->set_rule_error( 'template', __( 'The selected saved design no longer exists.', 'submission-inbox' ) );
			return;
		}
		if ( AutoReplyRuleRepository::STATUS_PUBLISHED === $status && ! $template && '' === trim( wp_strip_all_tags( $body ) ) && false === stripos( $body, '<img' ) ) {
			$this->set_rule_error( 'content', __( 'Add a subject and body, or choose a starting design.', 'submission-inbox' ) );
			return;
		}
		if ( '' === $submitted['name'] ) {
			$submitted['name'] = sprintf(
				/* translators: %s: Form name. */
				__( '%s auto-reply', 'submission-inbox' ),
				$form['label']
			);
			$this->submitted_rule['name'] = $submitted['name'];
		}
		if ( ! empty( $condition_errors ) ) {
			$this->set_rule_error( 'conditions', __( 'One or more rule conditions are invalid.', 'submission-inbox' ) );
			return;
		}
		if ( '' !== $from_email_raw && ( false !== strpos( $from_email_raw, "\r" ) || false !== strpos( $from_email_raw, "\n" ) || ! is_email( $from_email ) ) ) {
			$this->set_rule_error( 'sender', __( 'Enter a valid From email address.', 'submission-inbox' ) );
			return;
		}
		if ( '' !== $reply_raw && ( false !== strpos( $reply_raw, "\r" ) || false !== strpos( $reply_raw, "\n" ) || ! is_email( $reply_email ) ) ) {
			$this->set_rule_error( 'sender', __( 'Enter a valid Reply-To email address.', 'submission-inbox' ) );
			return;
		}

		$data = array(
			'name'                      => $submitted['name'],
			'provider'                  => $provider,
			'form_id'                   => $form['id'],
			'form_name'                 => $form['label'],
			'visitor_email_field'       => $field ? $field['key'] : $field_key,
			'visitor_email_field_label' => $field ? $field['label'] : '',
			'template_id'               => $template_id,
			'enabled'                   => $enabled,
			'status'                    => $status,
			'priority'                  => $priority,
			'condition_match'           => $condition_match,
			'conditions'                => $conditions_doc,
			'subject'                   => $subject,
			'preheader'                 => $preheader,
			'body'                      => $body,
			'from_name'                 => $from_name,
			'from_email'                => $from_email,
			'reply_to_name'             => $reply_name,
			'reply_to_email'            => $reply_email,
			'delivery_mode'             => AutoReplyRuleRepository::DELIVERY_DELAY === $delivery_mode ? AutoReplyRuleRepository::DELIVERY_DELAY : AutoReplyRuleRepository::DELIVERY_IMMEDIATE,
			'delay_seconds'             => $delay_seconds,
		);

		if ( '' === $data['name'] ) {
			$this->set_rule_error( 'name', __( 'Rule name is required.', 'submission-inbox' ) );
			return;
		}

		$resource = array(
			'id'                    => $rule_id,
			'expected_version'      => isset( $_POST['expected_version'] ) ? absint( wp_unslash( $_POST['expected_version'] ) ) : absint( $current_rule['rule_version'] ?? 0 ),
			'name'                  => $data['name'],
			'provider'              => $data['provider'],
			'form_id'               => $data['form_id'],
			'visitor_email_field'   => $data['visitor_email_field'],
			'template_id'           => $data['template_id'],
			'enabled'               => ! empty( $data['enabled'] ),
			'priority'              => $data['priority'],
			'condition_match'       => $data['condition_match'],
			'conditions'            => $conditions_doc,
			'subject'               => $data['subject'],
			'preheader'             => $data['preheader'],
			'body'                  => $data['body'],
			'from'                  => array( 'name' => $data['from_name'], 'email' => $data['from_email'] ),
			'reply_to'              => array( 'name' => $data['reply_to_name'], 'email' => $data['reply_to_email'] ),
			'delivery'              => array( 'mode' => $data['delivery_mode'], 'delay_seconds' => $data['delay_seconds'] ),
		);
		$result = $this->policy->save( $resource, AutoReplyRuleRepository::STATUS_DRAFT === $status ? 'save_draft' : 'publish' );
		if ( is_wp_error( $result ) ) {
			$this->set_policy_error( $result );
			return;
		}

		$saved_id = absint( $result['rule']['id'] ?? 0 );
		$notice   = $rule_id > 0 ? 'rule_saved' : 'rule_created';
		$this->flash_notice( $notice );
		$this->safe_admin_redirect( $saved_id > 0 ? $this->rule_edit_url( $saved_id ) : $this->rules_url() );
	}

	/**
	 * Handle rule row actions.
	 *
	 * @return void
	 */
	private function maybe_handle_rule_action() {
		$action  = SUBIN_Request::action_key( 'subin_rule_action' );
		$rule_id = SUBIN_Request::action_absint( 'id' );
		if ( ! in_array( $action, array( 'duplicate', 'delete', 'enable', 'disable' ), true ) || $rule_id <= 0 ) {
			return;
		}

		if ( ! current_user_can( SUBIN_AdminMenu::CAPABILITY ) ) {
			$this->redirect_to_rules( 'permission_denied' );
		}

		$nonce = SUBIN_Request::action_text( '_wpnonce' );
		if ( ! wp_verify_nonce( $nonce, 'subin_auto_reply_rule_' . $action . '_' . $rule_id ) ) {
			$this->redirect_to_rules( 'security_check_failed' );
		}

		$notice = 'rule_not_saved';
		if ( 'duplicate' === $action ) {
			$notice = $this->rules->duplicate( $rule_id ) > 0 ? 'rule_duplicated' : 'rule_not_saved';
		} elseif ( 'delete' === $action ) {
			$notice = $this->rules->delete( $rule_id ) ? 'rule_deleted' : 'rule_not_saved';
		} else {
			$rule = $this->rules->find( $rule_id );
			if ( $rule ) {
				if ( 'enable' === $action ) {
					$resource            = $this->policy->resource_from_rule( $rule );
					$resource['enabled'] = true;
					$result               = $this->policy->save( $resource, 'publish' );
					$notice               = is_wp_error( $result ) ? 'rule_not_saved' : 'rule_enabled';
				} else {
					$rule['enabled'] = 0;
					$notice = $this->rules->update( $rule_id, $rule ) ? 'rule_disabled' : 'rule_not_saved';
				}
			}
		}

		$this->redirect_to_rules( $notice );
	}

	/**
	 * Handle duplicate and delete row actions.
	 *
	 * @return void
	 */
	private function maybe_handle_row_action() {
		$action      = SUBIN_Request::action_key( 'subin_action' );
		$template_id = SUBIN_Request::action_absint( 'id' );

		if ( ! in_array( $action, array( 'duplicate', 'delete' ), true ) || $template_id <= 0 ) {
			return;
		}

		if ( ! current_user_can( SUBIN_AdminMenu::CAPABILITY ) ) {
			$this->redirect_to_list( 'permission_denied' );
		}

		$nonce = SUBIN_Request::action_text( '_wpnonce' );
		if ( ! wp_verify_nonce( $nonce, 'subin_auto_reply_' . $action . '_' . $template_id ) ) {
			$this->redirect_to_list( 'security_check_failed' );
		}

		if ( 'duplicate' === $action ) {
			$new_id = $this->templates->duplicate( $template_id );
			$this->redirect_to_list( $new_id > 0 ? 'template_duplicated' : 'template_not_duplicated' );
		}

		if ( $this->get_shared_rule_count( $template_id ) > 0 ) {
			$this->redirect_to_list( 'template_in_use' );
		}

		$deleted = $this->templates->delete( $template_id );
		$this->redirect_to_list( $deleted ? 'template_deleted' : 'template_not_deleted' );
	}

	/**
	 * Render admin notices.
	 *
	 * @return void
	 */
	private function render_notices() {
		if ( '' !== $this->error_message ) {
			SUBIN_AdminNotices::render_notice( $this->error_message, 'error' );
		}
	}

	/**
	 * Get auto-reply notice details.
	 *
	 * @param string $notice Notice key.
	 * @return array{type:string,message:string}|null
	 */
	private function notice_details( $notice ) {
		$messages = array(
			'template_created'        => array( 'success', __( 'Saved email design created.', 'submission-inbox' ) ),
			'template_saved'          => array( 'success', __( 'Saved email design updated.', 'submission-inbox' ) ),
			'template_duplicated'     => array( 'success', __( 'Saved email design duplicated.', 'submission-inbox' ) ),
			'template_not_duplicated' => array( 'error', __( 'Saved email design could not be duplicated.', 'submission-inbox' ) ),
			'template_deleted'        => array( 'success', __( 'Saved email design deleted.', 'submission-inbox' ) ),
			'template_not_deleted'    => array( 'error', __( 'Saved email design could not be deleted.', 'submission-inbox' ) ),
			'template_in_use'         => array( 'error', __( 'This saved design is still shared by one or more legacy auto-replies. Make those messages independent before deleting it.', 'submission-inbox' ) ),
			'rule_created'            => array( 'success', __( 'Auto-reply rule created.', 'submission-inbox' ) ),
			'rule_saved'              => array( 'success', __( 'Auto-reply rule saved.', 'submission-inbox' ) ),
			'rule_not_saved'          => array( 'error', __( 'Auto-reply rule could not be saved.', 'submission-inbox' ) ),
			'rule_duplicated'         => array( 'success', __( 'Auto-reply rule duplicated as disabled.', 'submission-inbox' ) ),
			'rule_deleted'            => array( 'success', __( 'Auto-reply rule deleted.', 'submission-inbox' ) ),
			'rule_enabled'            => array( 'success', __( 'Auto-reply rule enabled.', 'submission-inbox' ) ),
			'rule_disabled'           => array( 'success', __( 'Auto-reply rule disabled.', 'submission-inbox' ) ),
			'rule_enabled_exists'     => array( 'error', __( 'This form already has an enabled auto-reply rule.', 'submission-inbox' ) ),
			'permission_denied'       => array( 'error', __( 'You do not have permission to perform this action.', 'submission-inbox' ) ),
			'security_check_failed'   => array( 'error', __( 'Security check failed. Please try again.', 'submission-inbox' ) ),
		);

		$notice = sanitize_key( $notice );
		if ( empty( $messages[ $notice ] ) ) {
			return null;
		}

		return array(
			'type'    => $messages[ $notice ][0],
			'message' => $messages[ $notice ][1],
		);
	}

	/**
	 * Store an auto-reply notice for the next page load.
	 *
	 * @param string $notice Notice key.
	 * @return void
	 */
	private function flash_notice( $notice ) {
		$details = $this->notice_details( $notice );
		if ( ! $details ) {
			return;
		}

		SUBIN_AdminNotices::flash( $details['message'], $details['type'], $notice );
	}

	/**
	 * Get a scalar POST value.
	 *
	 * @param string $key POST key.
	 * @return string
	 */
	private function posted_string( $key ) {
		if ( ! isset( $_POST[ $key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Caller verifies the auto-reply save nonce before reading submitted template fields.
			return '';
		}

		$value = wp_unslash( $_POST[ $key ] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Template HTML is sanitized by the repository according to the target field after the save nonce is verified.

		return is_scalar( $value ) ? (string) $value : '';
	}

	/**
	 * Count legacy rules that still inherit from a saved design.
	 *
	 * @param int $template_id Template id.
	 * @return int
	 */
	private function get_shared_rule_count( $template_id ) {
		$template_id = absint( $template_id );

		if ( $template_id <= 0 ) {
			return 0;
		}

		if ( null === $this->template_usage_counts ) {
			$this->template_usage_counts = $this->build_template_usage_counts();
		}

		return absint( $this->template_usage_counts[ $template_id ] ?? 0 );
	}

	/**
	 * Get legacy rules that still inherit from a saved design.
	 *
	 * @param int $template_id Template id.
	 * @return array<int,array<string,mixed>>
	 */
	private function get_rules_using_template( $template_id ) {
		$template_id = absint( $template_id );

		if ( $template_id <= 0 ) {
			return array();
		}

		if ( null === $this->template_usage_counts ) {
			$this->template_usage_counts = $this->build_template_usage_counts();
		}

		return $this->template_usage_counts[ $template_id . '_rules' ] ?? array();
	}

	/**
	 * Render legacy rules that still share this design.
	 *
	 * @param array<int,array<string,mixed>> $rules Rules.
	 * @param int                           $used_count Total usage count.
	 * @return void
	 */
	private function render_shared_rules( array $rules, $used_count ) {
		if ( empty( $rules ) ) {
			?>
			<div class="subin-template-used-by subin-template-used-by--empty">
				<span><?php esc_html_e( 'No legacy auto-replies inherit this design.', 'submission-inbox' ); ?></span>
			</div>
			<?php
			return;
		}

		$visible_rules = array_slice( $rules, 0, 4 );
		$remaining     = max( 0, absint( $used_count ) - count( $visible_rules ) );
		?>
		<div class="subin-template-used-by">
			<span class="subin-template-used-by__label"><?php esc_html_e( 'Legacy shared by', 'submission-inbox' ); ?></span>
			<div class="subin-template-used-by__chips">
				<?php foreach ( $visible_rules as $rule ) : ?>
					<a class="subin-template-used-by__chip" href="<?php echo esc_url( $this->rule_edit_url( absint( $rule['id'] ?? 0 ) ) ); ?>">
						<?php echo esc_html( (string) ( $rule['name'] ?? __( 'Untitled auto-reply', 'submission-inbox' ) ) ); ?>
					</a>
				<?php endforeach; ?>
				<?php if ( $remaining > 0 ) : ?>
					<span class="subin-template-used-by__more">
						<?php
						printf(
							/* translators: %d: Number of additional auto-replies. */
							esc_html__( '+%d more', 'submission-inbox' ),
							absint( $remaining )
						);
						?>
					</span>
				<?php endif; ?>
			</div>
		</div>
		<?php
	}

	/**
	 * Count every legacy shared rule without a silent result cap.
	 *
	 * @return array<int|string,mixed>
	 */
	private function build_template_usage_counts() {
		$counts = array();
		$offset = 0;
		$per_page = 250;
		do {
			$rules = $this->rules->list_rules(
				array(
					'per_page' => $per_page,
					'offset'   => $offset,
				)
			);
			foreach ( $rules as $rule ) {
				$template_id = absint( $rule['template_id'] ?? 0 );
				if ( $template_id <= 0 ) {
					continue;
				}
				if ( ! isset( $counts[ $template_id ] ) ) {
					$counts[ $template_id ]            = 0;
					$counts[ $template_id . '_rules' ] = array();
				}
				$counts[ $template_id ]++;
				$counts[ $template_id . '_rules' ][] = array(
					'id'   => absint( $rule['id'] ?? 0 ),
					'name' => sanitize_text_field( $rule['name'] ?? '' ),
				);
			}
			$offset += $per_page;
		} while ( count( $rules ) === $per_page );

		return $counts;
	}

	/**
	 * Render safe compact email preview.
	 *
	 * @param array<string,mixed> $template Template row.
	 * @return void
	 */
	private function render_template_mini_preview( array $template ) {
		$srcdoc = $this->template_preview_srcdoc( $template );
		if ( '' !== $srcdoc ) {
			?>
			<div class="subin-template-mini-preview">
				<iframe
					<?php /* translators: %s: auto-reply template name. */ ?>
					title="<?php echo esc_attr( sprintf( __( 'Preview: %s', 'submission-inbox' ), $template['name'] ?? __( 'Auto-reply design', 'submission-inbox' ) ) ); ?>"
					sandbox=""
					loading="lazy"
					scrolling="no"
					srcdoc="<?php echo esc_attr( $srcdoc ); ?>"
				></iframe>
			</div>
			<?php
			return;
		}

		?>
		<div class="subin-template-mini-preview subin-template-mini-preview--placeholder" aria-hidden="true">
			<strong><?php esc_html_e( 'No preview available', 'submission-inbox' ); ?></strong>
			<span><?php esc_html_e( 'Edit design to add content.', 'submission-inbox' ); ?></span>
		</div>
		<?php
	}

	/**
	 * Build sandboxed srcdoc for a real auto-reply preview.
	 *
	 * @param array<string,mixed> $template Template row.
	 * @return string
	 */
	private function template_preview_srcdoc( array $template ) {
		$html = AutoReplyTemplateRepository::effective_body( $template );

		if ( '' === trim( $html ) ) {
			return '';
		}

		return wp_kses(
			$html,
			AutoReplyTemplateRepository::allowed_email_html(),
			array( 'http', 'https', 'mailto', 'tel' )
		);
	}

	/**
	 * Build a new editor template from selected starter.
	 *
	 * @return array<string,mixed>
	 */
	private function editor_template_from_request() {
		if ( $this->submitted_template ) {
			return $this->submitted_template;
		}

		$key     = SUBIN_Request::get_key( 'template_key' );
		$starter = $this->library->get( $key );

		if ( ! $starter ) {
			return $this->empty_template();
		}

		return array_merge(
			$this->empty_template(),
			array(
				'template_key'  => $starter['key'],
				'name'          => $starter['name'],
				'body'          => $starter['html'],
				'rendered_html' => $starter['html'],
				'rendered_css'  => '',
				'project_json'  => '',
			)
		);
	}

	/**
	 * Get supported variables grouped by use.
	 *
	 * @return array<string,array<string,string>>
	 */
	private function variable_groups() {
		return array(
			__( 'General', 'submission-inbox' ) => array(
				'{site_name}'       => __( 'Site name', 'submission-inbox' ),
				'{form_name}'       => __( 'Form name', 'submission-inbox' ),
				'{submission_date}' => __( 'Submission date', 'submission-inbox' ),
			),
			__( 'Lead', 'submission-inbox' )    => array(
				'{lead_id}'       => __( 'Lead ID', 'submission-inbox' ),
				'{visitor_email}' => __( 'Visitor email', 'submission-inbox' ),
			),
			__( 'Fields', 'submission-inbox' )  => array(
				'{field:name}'    => __( 'Name field', 'submission-inbox' ),
				'{field:email}'   => __( 'Email field', 'submission-inbox' ),
				'{field:message}' => __( 'Message field', 'submission-inbox' ),
			),
		);
	}

	/**
	 * Allowed HTML for gallery previews.
	 *
	 * @return array<string,array<string,bool>>
	 */
	private function email_preview_allowed_html() {
		$attrs = array(
			'class'                    => true,
			'data-subin-component'       => true,
			'data-subin-email-component' => true,
			'data-subin-icon-align'      => true,
			'data-subin-icon-bg'         => true,
			'data-subin-icon-color'      => true,
			'data-subin-icon-key'        => true,
			'data-subin-icon-label'      => true,
			'data-subin-icon-radius'     => true,
			'data-subin-icon-size'       => true,
			'style'                    => true,
		);

		return array(
			'a'      => array_merge(
				$attrs,
				array(
					'href'   => true,
					'rel'    => true,
					'target' => true,
					'title'  => true,
				)
			),
			'b'      => array(),
			'br'     => array(),
			'div'    => $attrs,
			'em'     => array(),
			'h1'     => $attrs,
			'h2'     => $attrs,
			'h3'     => $attrs,
			'hr'     => array(),
			'i'      => array(),
			'img'    => array_merge(
				$attrs,
				array(
					'alt'    => true,
					'height' => true,
					'src'    => true,
					'title'  => true,
					'width'  => true,
				)
			),
			'li'     => $attrs,
			'ol'     => $attrs,
			'p'      => $attrs,
			'span'   => $attrs,
			'svg'    => array(
				'aria-hidden'      => true,
				'class'            => true,
				'fill'             => true,
				'focusable'        => true,
				'height'           => true,
				'role'             => true,
				'stroke'           => true,
				'stroke-linecap'   => true,
				'stroke-linejoin'  => true,
				'stroke-width'     => true,
				'viewbox'          => true,
				'viewBox'          => true,
				'width'            => true,
				'xmlns'            => true,
			),
			'path'   => array(
				'd' => true,
			),
			'circle' => array(
				'cx' => true,
				'cy' => true,
				'r'  => true,
			),
			'line'   => array(
				'x1' => true,
				'x2' => true,
				'y1' => true,
				'y2' => true,
			),
			'rect'   => array(
				'height' => true,
				'rx'     => true,
				'ry'     => true,
				'width'  => true,
				'x'      => true,
				'y'      => true,
			),
			'polyline' => array(
				'points' => true,
			),
			'polygon' => array(
				'points' => true,
			),
			'strong' => array(),
			'table'  => $attrs,
			'tbody'  => $attrs,
			'td'     => $attrs,
			'tr'     => $attrs,
			'ul'     => $attrs,
		);
	}

	/**
	 * Get empty template defaults.
	 *
	 * @return array<string,mixed>
	 */
	private function empty_template() {
		return array(
			'id'            => 0,
			'template_key'  => '',
			'name'          => '',
			'status'        => AutoReplyTemplateRepository::STATUS_ACTIVE,
			'subject'       => '',
			'body'          => '',
			'preheader'     => '',
			'project_json'  => '',
			'rendered_html' => '',
			'rendered_css'  => '',
		);
	}

	/**
	 * Format a database date.
	 *
	 * @param string $date Date.
	 * @return string
	 */
	private function format_date( $date ) {
		if ( '' === $date || '0000-00-00 00:00:00' === $date ) {
			return __( 'Unknown', 'submission-inbox' );
		}

		return mysql2date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $date );
	}

	/**
	 * Current main tab.
	 *
	 * @param string $view Template view.
	 * @return string
	 */
	private function current_tab( $view = '' ) {
		if ( in_array( $view, array( 'new', 'preview', 'editor', 'edit' ), true ) ) {
			return 'templates';
		}

		$rule_view = SUBIN_Request::get_key( 'rule_view' );
		if ( in_array( $rule_view, array( 'new', 'edit' ), true ) ) {
			return 'rules';
		}

		$tab = SUBIN_Request::get_key( 'subin_auto_replies_tab', 'rules' );

		return in_array( $tab, array( 'rules', 'templates' ), true ) ? $tab : 'rules';
	}

	/**
	 * Empty rule values.
	 *
	 * @return array<string,mixed>
	 */
	private function empty_rule() {
		return array(
			'id'                        => 0,
			'name'                      => '',
			'provider'                  => AutoReplyRuleRepository::PROVIDER_SUBMISSION_INBOX_FORM,
			'form_id'                   => '',
			'form_name'                 => '',
			'visitor_email_field'       => '',
			'visitor_email_field_label' => '',
			'template_id'               => 0,
			'enabled'                   => 0,
			'status'                    => AutoReplyRuleRepository::STATUS_DRAFT,
			'rule_version'              => 1,
			'priority'                  => AutoReplyRuleRepository::DEFAULT_PRIORITY,
			'condition_match'           => AutoReplyRuleRepository::MATCH_ALL,
			'conditions'                => array(),
			'conditions_document'       => array(
				'version'    => AutoReplyConditionEngine::VERSION,
				'mode'       => AutoReplyRuleRepository::MATCH_ALL,
				'conditions' => array(),
			),
			'subject'                   => '',
			'preheader'                 => '',
			'body'                      => '',
			'from_name'                 => '',
			'from_email'                => '',
			'reply_to_name'             => '',
			'reply_to_email'            => '',
			'delivery_mode'             => AutoReplyRuleRepository::DELIVERY_IMMEDIATE,
			'delay_seconds'             => 0,
		);
	}

	/**
	 * Build form choices for the selected provider only.
	 *
	 * @param string $provider_key Provider key.
	 * @return array<int,array<string,string>>
	 */
	private function provider_form_choices( $provider_key ) {
		$choices = array();
		$provider_key   = $this->rules->sanitize_provider( $provider_key );
		$provider_label = $this->providers->provider_label( $provider_key );
		foreach ( $this->providers->list_forms( $provider_key ) as $form ) {
			$choices[] = array(
				'value'    => $provider_key . '|' . sanitize_text_field( (string) ( $form['id'] ?? '' ) ),
				'provider' => $provider_key,
				'label'    => sprintf(
					/* translators: 1: provider label, 2: form label. */
					__( '%1$s - %2$s', 'submission-inbox' ),
					$provider_label,
					sanitize_text_field( (string) ( $form['label'] ?? '' ) )
				),
			);
		}

		return $choices;
	}

	/**
	 * Build email field choices for the selected form only.
	 *
	 * @param string $provider_key Provider key.
	 * @param string $form_id Form id.
	 * @return array<int,array<string,string>>
	 */
	private function provider_email_field_choices( $provider_key, $form_id ) {
		$choices = array();
		$provider_key = $this->rules->sanitize_provider( $provider_key );
		$form_id      = sanitize_text_field( (string) $form_id );
		$form          = $this->providers->get_form( $provider_key, $form_id );
		if ( ! $form ) {
			return $choices;
		}
		$provider_label = $this->providers->provider_label( $provider_key );
		$form_label     = sanitize_text_field( (string) ( $form['label'] ?? $form_id ) );
		foreach ( $this->providers->list_email_fields( $provider_key, $form_id ) as $field ) {
			$choices[] = array(
				'value'      => $provider_key . '|' . $form_id . '|' . sanitize_key( $field['key'] ?? '' ),
				'provider'   => $provider_key,
				'form_value' => $provider_key . '|' . $form_id,
				'label'      => sprintf(
					/* translators: 1: provider label, 2: form label, 3: email field label. */
					__( '%1$s - %2$s - %3$s', 'submission-inbox' ),
					$provider_label,
					$form_label,
					sanitize_text_field( (string) ( $field['label'] ?? '' ) )
				),
			);
		}

		return $choices;
	}

	/**
	 * Build rule status display details.
	 *
	 * @param array<string,mixed>      $rule Rule row.
	 * @param array<string,mixed>|null $template Template row.
	 * @return array{label:string,type:string}
	 */
	private function rule_status_details( array $rule, $template ) {
		$provider = $this->rules->sanitize_provider( (string) ( $rule['provider'] ?? '' ) );
		$form_id  = sanitize_text_field( (string) ( $rule['form_id'] ?? '' ) );
		$cache_key = $provider . '|' . $form_id;
		if ( ! isset( $this->rule_schema_cache[ $cache_key ] ) ) {
			$this->rule_schema_cache[ $cache_key ] = array(
				'form'   => '' !== $provider && '' !== $form_id ? $this->providers->get_form( $provider, $form_id ) : null,
				'fields' => '' !== $provider && '' !== $form_id ? $this->providers->list_fields( $provider, $form_id ) : array(),
			);
		}
		$schema = $this->rule_schema_cache[ $cache_key ];
		if ( ! $this->readiness ) {
			$this->readiness = new AutoReplyRuleReadiness( null, null, $this->rules, $this->templates );
		}
		$analysis = $this->readiness->analyze( $rule, (array) $schema['fields'], ! empty( $schema['form'] ), $template );
		if ( empty( $analysis['ready'] ) ) {
			return array(
				'label' => __( 'Needs setup', 'submission-inbox' ),
				'type'  => 'warning',
			);
		}
		if ( AutoReplyRuleRepository::STATUS_DRAFT === ( $rule['status'] ?? AutoReplyRuleRepository::STATUS_PUBLISHED ) ) {
			return array(
				'label' => __( 'Draft', 'submission-inbox' ),
				'type'  => 'warning',
			);
		}

		if ( empty( $rule['enabled'] ) ) {
			return array(
				'label' => __( 'Disabled', 'submission-inbox' ),
				'type'  => 'muted',
			);
		}

		return array(
			'label' => __( 'Published · enabled', 'submission-inbox' ),
			'type'  => 'success',
		);
	}

	/**
	 * Format a rule delay for compact list display.
	 *
	 * @param int $seconds Delay seconds.
	 * @return string
	 */
	private function format_rule_delay( $seconds ) {
		$seconds = absint( $seconds );
		if ( $seconds >= DAY_IN_SECONDS && 0 === $seconds % DAY_IN_SECONDS ) {
			$days = (int) ( $seconds / DAY_IN_SECONDS );
			/* translators: %d: delay in days before an auto-reply is sent. */
			return sprintf( _n( 'After %d day', 'After %d days', $days, 'submission-inbox' ), $days );
		}
		if ( $seconds >= HOUR_IN_SECONDS && 0 === $seconds % HOUR_IN_SECONDS ) {
			$hours = (int) ( $seconds / HOUR_IN_SECONDS );
			/* translators: %d: delay in hours before an auto-reply is sent. */
			return sprintf( _n( 'After %d hour', 'After %d hours', $hours, 'submission-inbox' ), $hours );
		}

		$minutes = max( 1, (int) ceil( $seconds / MINUTE_IN_SECONDS ) );
		/* translators: %d: delay in minutes before an auto-reply is sent. */
		return sprintf( _n( 'After %d minute', 'After %d minutes', $minutes, 'submission-inbox' ), $minutes );
	}

	/**
	 * List URL.
	 *
	 * @return string
	 */
	private function list_url() {
		return $this->templates_url();
	}

	/**
	 * Rules URL.
	 *
	 * @return string
	 */
	private function rules_url() {
		return add_query_arg(
			array(
				'page'                 => self::PAGE_SLUG,
				'subin_auto_replies_tab' => 'rules',
			),
			admin_url( 'admin.php' )
		);
	}

	/**
	 * Templates URL.
	 *
	 * @return string
	 */
	private function templates_url() {
		return add_query_arg(
			array(
				'page'                 => self::PAGE_SLUG,
				'subin_auto_replies_tab' => 'templates',
			),
			admin_url( 'admin.php' )
		);
	}

	/**
	 * Rule editor URL.
	 *
	 * @param int $rule_id Rule id.
	 * @return string
	 */
	private function rule_edit_url( $rule_id ) {
		$args = array(
			'rule_view'            => $rule_id > 0 ? 'edit' : 'new',
			'subin_auto_replies_tab' => 'rules',
		);
		if ( $rule_id > 0 ) {
			$args['id'] = absint( $rule_id );
		}

		return add_query_arg( $args, $this->rules_url() );
	}

	/**
	 * Rule row action URL.
	 *
	 * @param string $action Action.
	 * @param int    $rule_id Rule id.
	 * @return string
	 */
	private function rule_action_url( $action, $rule_id ) {
		$rule_id = absint( $rule_id );
		$action  = sanitize_key( $action );
		$args    = array(
			'subin_rule_action'    => $action,
			'id'                   => $rule_id,
			'subin_auto_replies_tab' => 'rules',
		);
		$url = add_query_arg( $args, $this->rules_url() );

		return wp_nonce_url( $url, 'subin_auto_reply_rule_' . $action . '_' . $rule_id );
	}

	/**
	 * New template URL.
	 *
	 * @return string
	 */
	private function new_url() {
		return add_query_arg( array( 'view' => 'new' ), $this->list_url() );
	}

	/**
	 * Starter editor URL.
	 *
	 * @param string $template_key Starter template key.
	 * @return string
	 */
	private function starter_editor_url( $template_key ) {
		return add_query_arg(
			array(
				'view'         => 'editor',
				'template_key' => sanitize_key( $template_key ),
			),
			$this->list_url()
		);
	}

	/**
	 * Starter preview URL.
	 *
	 * @param string $template_key Starter template key.
	 * @return string
	 */
	private function starter_preview_url( $template_key ) {
		return add_query_arg(
			array(
				'view'         => 'preview',
				'template_key' => sanitize_key( $template_key ),
			),
			$this->list_url()
		);
	}

	/**
	 * Edit template URL.
	 *
	 * @param int $template_id Template id.
	 * @return string
	 */
	private function edit_url( $template_id ) {
		$args = array(
			'view' => 'edit',
			'id'   => absint( $template_id ),
		);

		return add_query_arg( $args, $this->list_url() );
	}

	/**
	 * Row action URL.
	 *
	 * @param string $action Action.
	 * @param int    $template_id Template id.
	 * @return string
	 */
	private function action_url( $action, $template_id ) {
		$template_id = absint( $template_id );
		$action      = sanitize_key( $action );
		$url         = add_query_arg(
			array(
				'subin_action' => $action,
				'id'         => $template_id,
			),
			$this->list_url()
		);

		return wp_nonce_url( $url, 'subin_auto_reply_' . $action . '_' . $template_id );
	}

	/**
	 * Redirect to list screen.
	 *
	 * @param string $notice Notice key.
	 * @return void
	 */
	private function redirect_to_list( $notice ) {
		$this->flash_notice( $notice );
		$this->safe_admin_redirect( $this->list_url() );
	}

	/**
	 * Redirect to rules list.
	 *
	 * @param string $notice Notice key.
	 * @return void
	 */
	private function redirect_to_rules( $notice ) {
		$this->flash_notice( $notice );
		$this->safe_admin_redirect( $this->rules_url() );
	}

	/**
	 * Redirect to edit screen.
	 *
	 * @param int    $template_id Template id.
	 * @param string $notice Notice key.
	 * @return void
	 */
	private function redirect_to_edit( $template_id, $notice ) {
		$this->flash_notice( $notice );
		$this->safe_admin_redirect( $this->edit_url( $template_id ) );
	}

	/**
	 * Redirect from an admin page callback without header warnings.
	 *
	 * @param string $url Target URL.
	 * @return void
	 */
	private function safe_admin_redirect( $url ) {
		$url = esc_url_raw( $url );
		if ( ! headers_sent() ) {
			wp_safe_redirect( $url );
			exit;
		}

		printf(
			'<script>window.location.href=%1$s;</script><noscript><meta http-equiv="refresh" content="0;url=%2$s" /></noscript>',
			wp_json_encode( $url ),
			esc_url( $url )
		);
		exit;
	}
}
