<?php
/**
 * Inbox admin page.
 *
 * @package SubmissionInbox
 */

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

/**
 * Renders the leads inbox.
 */
class SUBIN_InboxPage {
	const PER_PAGE = 20;
	const DETAIL_FIELD_LIMIT = 12;
	const HIGHLIGHT_FIELD_LIMIT = 2;

	/**
	 * Lead repository.
	 *
	 * @var \SUBIN\Leads\LeadRepository
	 */
	private $leads;

	/**
	 * Field repository.
	 *
	 * @var \SUBIN\Leads\LeadFieldRepository
	 */
	private $fields;

	/**
	 * Mail event repository.
	 *
	 * @var \SUBIN\MailLog\MailEventRepository
	 */
	private $mail_events;

	/**
	 * Settings repository.
	 *
	 * @var \SUBIN_SettingsRepository
	 */
	private $settings;

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

	/**
	 * Auto-reply template repository.
	 *
	 * @var \SUBIN\AutoReplies\AutoReplyTemplateRepository
	 */
	private $auto_reply_templates;

	/**
	 * Lead workflow repository.
	 *
	 * @var \SUBIN\Leads\LeadWorkflowRepository
	 */
	private $workflow;

	/**
	 * Lead activity repository.
	 *
	 * @var \SUBIN\Leads\LeadActivityRepository
	 */
	private $activity;

	/**
	 * Provider registry.
	 *
	 * @var \SUBIN\Integrations\ProviderRegistry
	 */
	private $providers;

	/**
	 * Form submission context.
	 *
	 * @var \SUBIN\Forms\FormSubmissionContext|null
	 */
	private $form_context;

	/**
	 * Email error classifier.
	 *
	 * @var \SUBIN\Mail\EmailErrorClassifier
	 */
	private $error_classifier;

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

	/**
	 * Constructor.
	 *
	 * @param \SUBIN\Forms\FormSubmissionContext|null $form_context Form submission context.
	 */
	public function __construct( $form_context = null ) {
		$this->leads                = new \SUBIN\Leads\LeadRepository();
		$this->fields               = new \SUBIN\Leads\LeadFieldRepository();
		$this->mail_events          = new \SUBIN\MailLog\MailEventRepository();
		$this->settings             = new \SUBIN_SettingsRepository();
		$this->forms                = new \SUBIN\Forms\FormRepository();
		$this->auto_reply_templates = new \SUBIN\AutoReplies\AutoReplyTemplateRepository();
		$this->activity             = new \SUBIN\Leads\LeadActivityRepository();
		$this->workflow             = new \SUBIN\Leads\LeadWorkflowRepository( $this->activity );
		$this->providers            = new \SUBIN\Integrations\ProviderRegistry();
		$this->form_context         = $form_context;
		$this->error_classifier     = new \SUBIN\Mail\EmailErrorClassifier();
	}

	/**
	 * 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();

		$action  = SUBIN_Request::get_key( 'action' );
		$lead_id = SUBIN_Request::get_absint( 'lead_id' );

		if ( 'view' === $action && $lead_id > 0 ) {
			$this->render_detail( $lead_id );
			return;
		}

		$this->render_list();
	}

	/**
	 * 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_handle_action();
	}

	/**
	 * Handle CSV export before the admin page sends HTML.
	 *
	 * @return void
	 */
	public function handle_export_request() {
		if ( ! current_user_can( SUBIN_AdminMenu::CAPABILITY ) ) {
			return;
		}

		$this->maybe_export( $this->get_filters_from_request() );
	}

	/**
	 * Render inbox list.
	 *
	 * @return void
	 */
	private function render_list() {
		$filters     = $this->get_filters_from_request();
		$paged       = max( 1, SUBIN_Request::get_absint( 'paged', 1 ) );
		$total       = $this->leads->count_leads( $filters );
		$total_pages = max( 1, (int) ceil( $total / self::PER_PAGE ) );
		$paged       = min( $paged, $total_pages );

		$leads = $this->leads->get_paginated(
			array_merge(
				$filters,
				array(
					'per_page' => self::PER_PAGE,
					'offset'   => ( $paged - 1 ) * self::PER_PAGE,
				)
			)
		);

		SUBIN_View::page_header(
			__( 'Inbox', 'submission-inbox' ),
			__( 'Review saved form submissions and quickly spot notification issues.', 'submission-inbox' ),
			array(
				'primary_action'    => array(
					'label' => __( 'View Email Health', 'submission-inbox' ),
					'url'   => admin_url( 'admin.php?page=subin-email-status' ),
				),
				'secondary_actions' => array(
					array(
						'label' => __( 'Export CSV', 'submission-inbox' ),
						'url'   => $this->export_url( $filters ),
					),
				),
				'wrapper_class'     => 'subin-inbox-page',
			)
		);

		$this->maybe_add_list_notice();
		SUBIN_AdminNotices::render_settings_errors( 'subin_messages' );
		?>
		<div class="si-page">
			<?php $this->render_inbox_stats( $filters ); ?>
			<?php $this->render_inbox_toolbar( $filters ); ?>
			<?php $this->render_lead_cards( $leads, $total, $filters ); ?>
			<?php $this->render_pagination( $total, $paged, $filters ); ?>
		</div>
		<?php

		SUBIN_View::page_footer();
	}

	/**
	 * Render summary stats in the mockup card style.
	 *
	 * @param array<string,mixed> $filters Active filters.
	 * @return void
	 */
	private function render_inbox_stats( array $filters ) {
		$counts         = $this->leads->get_summary_counts();
		$new_lead_hours = $this->get_new_lead_hours();
		$new_threshold  = gmdate( 'Y-m-d H:i:s', current_time( 'timestamp' ) - ( $new_lead_hours * HOUR_IN_SECONDS ) );
		$stats          = array(
			array(
				'label' => __( 'Total leads', 'submission-inbox' ),
				'value' => $counts['total'] ?? 0,
				'url'   => $this->list_url( array(), 1 ),
				'key'   => 'total',
				'icon'  => 'dashicons-groups',
			),
			array(
				'label' => __( 'New leads', 'submission-inbox' ),
				'value' => $this->leads->count( array( 'submitted_after' => $new_threshold ) ),
				'key'   => 'new',
				'icon'  => 'dashicons-star-filled',
			),
			array(
				'label' => __( 'Unseen leads', 'submission-inbox' ),
				'value' => $this->leads->count( array( 'status' => \SUBIN\Leads\LeadRepository::STATUS_NEW ) ),
				'url'   => $this->list_url( $this->filters_for_quick_link( $filters, array( 'status' => 'new', 'email_status' => '', 'needs_attention' => '' ) ), 1 ),
				'key'   => 'unread',
				'icon'  => 'dashicons-email-alt',
			),
			array(
				'label' => __( 'Needs attention', 'submission-inbox' ),
				'value' => ( $counts['failed'] ?? 0 ) + ( $counts['no_email_generated'] ?? 0 ) + ( $counts['unknown'] ?? 0 ),
				'url'   => $this->list_url( $this->filters_for_quick_link( $filters, array( 'status' => '', 'email_status' => '', 'needs_attention' => '1' ) ), 1 ),
				'key'   => 'needs_attention',
				'icon'  => 'dashicons-warning',
			),
			array(
				'label' => __( 'Archived', 'submission-inbox' ),
				'value' => $this->leads->count( array( 'status' => \SUBIN\Leads\LeadRepository::STATUS_ARCHIVED ) ),
				'url'   => $this->list_url( $this->filters_for_quick_link( $filters, array( 'status' => 'archived', 'email_status' => '', 'needs_attention' => '' ) ), 1 ),
				'key'   => 'archived',
				'icon'  => 'dashicons-archive',
			),
		);
		?>
		<div class="si-stats">
			<?php foreach ( $stats as $stat ) : ?>
				<?php $icon_class = 'subin-status-icon subin-status-icon--' . sanitize_html_class( $stat['key'] ) . ' dashicons ' . $stat['icon']; ?>
				<?php if ( ! empty( $stat['url'] ) ) : ?>
					<a class="si-stat" href="<?php echo esc_url( $stat['url'] ); ?>">
						<span class="<?php echo esc_attr( $icon_class ); ?>" aria-hidden="true"></span>
						<span class="si-stat-copy">
							<strong><?php echo esc_html( (string) $stat['value'] ); ?></strong>
							<span><?php echo esc_html( $stat['label'] ); ?></span>
						</span>
					</a>
				<?php else : ?>
					<div class="si-stat">
						<span class="<?php echo esc_attr( $icon_class ); ?>" aria-hidden="true"></span>
						<span class="si-stat-copy">
							<strong><?php echo esc_html( (string) $stat['value'] ); ?></strong>
							<span><?php echo esc_html( $stat['label'] ); ?></span>
						</span>
					</div>
				<?php endif; ?>
			<?php endforeach; ?>
		</div>
		<?php
	}

	/**
	 * Render filters in the supplied toolbar layout.
	 *
	 * @param array<string,mixed> $filters Active filters.
	 * @return void
	 */
	private function render_inbox_toolbar( array $filters ) {
		$form_options = $this->leads->get_form_filter_options();
		?>
		<div class="si-toolbar">
			<nav class="si-tabs" aria-label="<?php esc_attr_e( 'Quick lead filters', 'submission-inbox' ); ?>">
				<?php foreach ( $this->quick_filter_chips( $filters ) as $chip ) : ?>
					<a class="si-tab<?php echo ! empty( $chip['active'] ) ? ' is-active' : ''; ?>" href="<?php echo esc_url( $chip['url'] ); ?>"<?php echo ! empty( $chip['active'] ) ? ' aria-current="page"' : ''; ?>>
						<?php echo esc_html( $chip['label'] ); ?>
					</a>
				<?php endforeach; ?>
			</nav>
			<form method="get" action="">
				<input type="hidden" name="page" value="<?php echo esc_attr( SUBIN_AdminMenu::MENU_SLUG ); ?>" />
				<div class="si-filters">
					<input class="si-input" type="search" name="s" value="<?php echo esc_attr( $filters['search'] ); ?>" placeholder="<?php esc_attr_e( 'Search leads by name, email, message, form...', 'submission-inbox' ); ?>" />
					<select class="si-select" name="subin_email_status" aria-label="<?php esc_attr_e( 'Email status', 'submission-inbox' ); ?>">
						<option value=""><?php esc_html_e( 'Status: All', 'submission-inbox' ); ?></option>
						<option value="failed" <?php selected( $filters['email_status'], 'failed' ); ?>><?php esc_html_e( 'Failed', 'submission-inbox' ); ?></option>
						<option value="sent" <?php selected( $filters['email_status'], 'sent' ); ?>><?php esc_html_e( 'Sent by WordPress', 'submission-inbox' ); ?></option>
						<option value="no_email_generated" <?php selected( $filters['email_status'], 'no_email_generated' ); ?>><?php esc_html_e( 'No email generated', 'submission-inbox' ); ?></option>
						<option value="unknown" <?php selected( $filters['email_status'], 'unknown' ); ?>><?php esc_html_e( 'Unknown', 'submission-inbox' ); ?></option>
					</select>
					<select class="si-select" name="subin_provider" aria-label="<?php esc_attr_e( 'Source', 'submission-inbox' ); ?>">
						<option value=""><?php esc_html_e( 'Source: All', 'submission-inbox' ); ?></option>
						<?php foreach ( $this->providers->active_keys() as $provider_key ) : ?>
							<option value="<?php echo esc_attr( $provider_key ); ?>" <?php selected( $filters['provider'], $provider_key ); ?>><?php echo esc_html( $this->providers->label( $provider_key ) ); ?></option>
						<?php endforeach; ?>
					</select>
					<select class="si-select" name="subin_form_id" aria-label="<?php esc_attr_e( 'Form', 'submission-inbox' ); ?>">
						<option value=""><?php esc_html_e( 'Form: All', 'submission-inbox' ); ?></option>
						<?php foreach ( $form_options as $form_option ) : ?>
							<?php
							$form_value = $form_option['provider'] . '|' . $form_option['form_id'];
							$form_label = $form_option['form_name'] ? $form_option['form_name'] : $form_option['form_id'];
							?>
							<option value="<?php echo esc_attr( $form_value ); ?>" <?php selected( $filters['form_filter'], $form_value ); ?>>
								<?php echo esc_html( $form_label ); ?>
							</option>
						<?php endforeach; ?>
					</select>
					<button class="si-btn-light" type="submit"><?php esc_html_e( 'Filter', 'submission-inbox' ); ?></button>
				</div>
			</form>
		</div>
		<?php
	}

	/**
	 * Render summary cards.
	 *
	 * @return void
	 */
	private function render_summary_cards( array $filters = array() ) {
		$counts              = $this->leads->get_summary_counts();
		$new_lead_hours      = $this->get_new_lead_hours();
		$new_lead_threshold  = gmdate( 'Y-m-d H:i:s', current_time( 'timestamp' ) - ( $new_lead_hours * HOUR_IN_SECONDS ) );
		$current_new         = $this->leads->count(
			array(
				'submitted_after' => $new_lead_threshold,
			)
		);
		$total_unseen        = $this->leads->count( array( 'status' => \SUBIN\Leads\LeadRepository::STATUS_NEW ) );
		$mark_all_seen_label = __( 'Mark all seen', 'submission-inbox' );
		$cards               = array(
			'total'           => array(
				'label'  => __( 'Total leads', 'submission-inbox' ),
				'value'  => $counts['total'] ?? 0,
				'icon'   => 'dashicons-groups',
				'url'    => $this->list_url( array(), 1 ),
				'active' => '' === ( $filters['status'] ?? '' ) && '' === ( $filters['email_status'] ?? '' ) && empty( $filters['needs_attention'] ),
			),
			'new'             => array(
				'label'       => __( 'New leads', 'submission-inbox' ),
				'value'       => $current_new,
				'icon'        => 'dashicons-star-filled',
				'description' => sprintf(
					/* translators: %d: number of hours. */
					__( 'Last %d hours', 'submission-inbox' ),
					$new_lead_hours
				),
			),
			'unread'          => array(
				'label'  => __( 'Unseen leads', 'submission-inbox' ),
				'value'  => $total_unseen,
				'icon'   => 'dashicons-email-alt',
				'url'    => $this->list_url( $this->filters_for_quick_link( $filters, array( 'status' => 'new', 'email_status' => '', 'needs_attention' => '' ) ), 1 ),
				'active' => 'new' === ( $filters['status'] ?? '' ),
				'action' => $total_unseen > 0 ? $mark_all_seen_label : '',
			),
			'needs_attention' => array(
				'label'  => __( 'Needs attention', 'submission-inbox' ),
				'value'  => ( $counts['failed'] ?? 0 ) + ( $counts['no_email_generated'] ?? 0 ) + ( $counts['unknown'] ?? 0 ),
				'icon'   => 'dashicons-warning',
				'url'    => $this->list_url( $this->filters_for_quick_link( $filters, array( 'status' => '', 'email_status' => '', 'needs_attention' => '1' ) ), 1 ),
				'active' => ! empty( $filters['needs_attention'] ),
			),
			'archived'        => array(
				'label'  => __( 'Archived', 'submission-inbox' ),
				'value'  => $this->leads->count( array( 'status' => \SUBIN\Leads\LeadRepository::STATUS_ARCHIVED ) ),
				'icon'   => 'dashicons-archive',
				'url'    => $this->list_url( $this->filters_for_quick_link( $filters, array( 'status' => 'archived', 'email_status' => '', 'needs_attention' => '' ) ), 1 ),
				'active' => 'archived' === ( $filters['status'] ?? '' ),
			),
		);
		?>
		<div class="subin-summary-grid subin-inbox-summary">
			<?php foreach ( $cards as $key => $card ) : ?>
				<div class="subin-summary-card<?php echo ! empty( $card['active'] ) ? ' is-active' : ''; ?>">
					<span class="<?php echo esc_attr( 'subin-status-icon subin-status-icon--' . sanitize_html_class( $key ) . ' dashicons ' . $card['icon'] ); ?>" aria-hidden="true"></span>
					<?php if ( ! empty( $card['url'] ) ) : ?>
						<a class="subin-summary-card__link" href="<?php echo esc_url( $card['url'] ); ?>"<?php echo ! empty( $card['active'] ) ? ' aria-current="page"' : ''; ?>>
							<span class="subin-summary-value"><?php echo esc_html( (string) $card['value'] ); ?></span>
							<span class="subin-summary-label"><?php echo esc_html( $card['label'] ); ?></span>
						</a>
					<?php else : ?>
						<span class="subin-summary-value"><?php echo esc_html( (string) $card['value'] ); ?></span>
						<span class="subin-summary-label"><?php echo esc_html( $card['label'] ); ?></span>
					<?php endif; ?>
					<?php if ( ! empty( $card['description'] ) ) : ?>
						<span class="subin-summary-description"><?php echo esc_html( $card['description'] ); ?></span>
					<?php endif; ?>
					<?php if ( ! empty( $card['action'] ) ) : ?>
						<form method="post" action="" class="subin-summary-action">
							<input type="hidden" name="subin_lead_action" value="mark_all_seen" />
							<?php wp_nonce_field( 'subin_mark_all_seen', 'subin_lead_nonce' ); ?>
							<button type="submit" class="subin-btn subin-btn-secondary subin-btn-small"><?php echo esc_html( $card['action'] ); ?></button>
						</form>
					<?php endif; ?>
				</div>
			<?php endforeach; ?>
		</div>
		<?php
	}

	/**
	 * Render filters and search.
	 *
	 * @param array<string,mixed> $filters Active filters.
	 * @return void
	 */
	private function render_filters( array $filters ) {
		$form_options = $this->leads->get_form_filter_options();
		$users        = get_users(
			array(
				'fields'  => array( 'ID', 'display_name' ),
				'orderby' => 'display_name',
			)
		);
		?>
		<div class="subin-filter-panel">
			<nav class="subin-filter-chips" aria-label="<?php esc_attr_e( 'Quick lead filters', 'submission-inbox' ); ?>">
				<?php foreach ( $this->quick_filter_chips( $filters ) as $chip ) : ?>
					<a class="subin-filter-chip<?php echo ! empty( $chip['active'] ) ? ' is-active' : ''; ?>" href="<?php echo esc_url( $chip['url'] ); ?>"<?php echo ! empty( $chip['active'] ) ? ' aria-current="page"' : ''; ?>>
						<?php echo esc_html( $chip['label'] ); ?>
					</a>
				<?php endforeach; ?>
			</nav>
			<form method="get" action="" class="subin-filter-form">
				<input type="hidden" name="page" value="<?php echo esc_attr( SUBIN_AdminMenu::MENU_SLUG ); ?>" />
				<div class="subin-filter-main subin-filter-main--inbox">
					<div class="subin-filter-field subin-filter-field--search">
						<label for="subin-inbox-search"><?php esc_html_e( 'Search', 'submission-inbox' ); ?></label>
						<input type="search" id="subin-inbox-search" name="s" value="<?php echo esc_attr( $filters['search'] ); ?>" placeholder="<?php esc_attr_e( 'Search leads', 'submission-inbox' ); ?>" />
					</div>
					<div class="subin-filter-field">
						<label for="subin-status"><?php esc_html_e( 'Status', 'submission-inbox' ); ?></label>
						<select id="subin-status" name="subin_status">
							<option value=""><?php esc_html_e( 'All', 'submission-inbox' ); ?></option>
							<option value="new" <?php selected( $filters['status'], 'new' ); ?>><?php esc_html_e( 'Unseen', 'submission-inbox' ); ?></option>
							<option value="seen" <?php selected( $filters['status'], 'seen' ); ?>><?php esc_html_e( 'Seen', 'submission-inbox' ); ?></option>
							<option value="archived" <?php selected( $filters['status'], 'archived' ); ?>><?php esc_html_e( 'Archived', 'submission-inbox' ); ?></option>
						</select>
					</div>
					<div class="subin-filter-field">
						<label for="subin-provider"><?php esc_html_e( 'Source', 'submission-inbox' ); ?></label>
						<select id="subin-provider" name="subin_provider">
							<option value=""><?php esc_html_e( 'All sources', 'submission-inbox' ); ?></option>
							<?php foreach ( $this->providers->active_keys() as $provider_key ) : ?>
								<option value="<?php echo esc_attr( $provider_key ); ?>" <?php selected( $filters['provider'], $provider_key ); ?>><?php echo esc_html( $this->providers->label( $provider_key ) ); ?></option>
							<?php endforeach; ?>
						</select>
					</div>
					<div class="subin-filter-field">
						<label for="subin-form"><?php esc_html_e( 'Form', 'submission-inbox' ); ?></label>
						<select id="subin-form" name="subin_form_id">
							<option value=""><?php esc_html_e( 'All forms', 'submission-inbox' ); ?></option>
							<?php foreach ( $form_options as $form_option ) : ?>
								<?php
								$form_value = $form_option['provider'] . '|' . $form_option['form_id'];
								$form_label = $form_option['form_name'] ? $form_option['form_name'] : $form_option['form_id'];
								?>
								<option value="<?php echo esc_attr( $form_value ); ?>" <?php selected( $filters['form_filter'], $form_value ); ?>>
									<?php echo esc_html( $form_label . ' - ' . $this->provider_label( $form_option['provider'] ) ); ?>
								</option>
							<?php endforeach; ?>
						</select>
					</div>
					<div class="subin-filter-actions">
						<button type="submit" class="button subin-btn subin-btn-primary"><?php esc_html_e( 'Filter', 'submission-inbox' ); ?></button>
						<a class="button subin-btn" href="<?php echo esc_url( $this->list_url( array(), 1 ) ); ?>"><?php esc_html_e( 'Reset', 'submission-inbox' ); ?></a>
					</div>
				</div>
				<details class="subin-advanced-filters subin-filter-advanced"<?php echo ( ! empty( $filters['email_status'] ) || ! empty( $filters['workflow_status'] ) || ! empty( $filters['priority'] ) || '' !== (string) ( $filters['assigned_user_id'] ?? '' ) || ! empty( $filters['overdue_follow_up'] ) || ! empty( $filters['date_from'] ) || ! empty( $filters['date_to'] ) ) ? ' open' : ''; ?>>
					<summary class="subin-filter-toggle"><?php esc_html_e( 'Advanced filters', 'submission-inbox' ); ?></summary>
					<div class="subin-advanced-filters__grid">
						<div class="subin-filter-field">
							<label for="subin-email-status"><?php esc_html_e( 'Email status', 'submission-inbox' ); ?></label>
							<select id="subin-email-status" name="subin_email_status">
								<option value=""><?php esc_html_e( 'All', 'submission-inbox' ); ?></option>
								<option value="sent" <?php selected( $filters['email_status'], 'sent' ); ?>><?php esc_html_e( 'Sent by WordPress', 'submission-inbox' ); ?></option>
								<option value="failed" <?php selected( $filters['email_status'], 'failed' ); ?>><?php esc_html_e( 'Failed', 'submission-inbox' ); ?></option>
								<option value="no_email_generated" <?php selected( $filters['email_status'], 'no_email_generated' ); ?>><?php esc_html_e( 'No email generated', 'submission-inbox' ); ?></option>
								<option value="unknown" <?php selected( $filters['email_status'], 'unknown' ); ?>><?php esc_html_e( 'Unknown', 'submission-inbox' ); ?></option>
							</select>
						</div>
						<div class="subin-filter-field">
							<label for="subin-workflow-status"><?php esc_html_e( 'Workflow', 'submission-inbox' ); ?></label>
							<select id="subin-workflow-status" name="subin_workflow_status">
								<option value=""><?php esc_html_e( 'All', 'submission-inbox' ); ?></option>
								<?php foreach ( $this->workflow->workflow_statuses() as $key => $label ) : ?>
									<option value="<?php echo esc_attr( $key ); ?>" <?php selected( $filters['workflow_status'], $key ); ?>><?php echo esc_html( $label ); ?></option>
								<?php endforeach; ?>
							</select>
						</div>
						<div class="subin-filter-field">
							<label for="subin-priority"><?php esc_html_e( 'Priority', 'submission-inbox' ); ?></label>
							<select id="subin-priority" name="subin_priority">
								<option value=""><?php esc_html_e( 'All', 'submission-inbox' ); ?></option>
								<?php foreach ( $this->workflow->priorities() as $key => $label ) : ?>
									<option value="<?php echo esc_attr( $key ); ?>" <?php selected( $filters['priority'], $key ); ?>><?php echo esc_html( $label ); ?></option>
								<?php endforeach; ?>
							</select>
						</div>
						<div class="subin-filter-field">
							<label for="subin-assigned-user"><?php esc_html_e( 'Assignee', 'submission-inbox' ); ?></label>
							<select id="subin-assigned-user" name="subin_assigned_user_id">
								<option value=""><?php esc_html_e( 'All', 'submission-inbox' ); ?></option>
								<option value="0" <?php selected( (string) $filters['assigned_user_id'], '0' ); ?>><?php esc_html_e( 'Unassigned', 'submission-inbox' ); ?></option>
								<?php foreach ( $users as $user ) : ?>
									<option value="<?php echo esc_attr( (string) $user->ID ); ?>" <?php selected( absint( $filters['assigned_user_id'] ), absint( $user->ID ) ); ?>><?php echo esc_html( $user->display_name ); ?></option>
								<?php endforeach; ?>
							</select>
						</div>
						<div class="subin-filter-field">
							<label for="subin-overdue-follow-up"><?php esc_html_e( 'Follow-up', 'submission-inbox' ); ?></label>
							<select id="subin-overdue-follow-up" name="subin_overdue_follow_up">
								<option value=""><?php esc_html_e( 'All', 'submission-inbox' ); ?></option>
								<option value="1" <?php selected( $filters['overdue_follow_up'], '1' ); ?>><?php esc_html_e( 'Overdue only', 'submission-inbox' ); ?></option>
							</select>
						</div>
						<div class="subin-filter-field">
							<label for="subin-date-from"><?php esc_html_e( 'From date', 'submission-inbox' ); ?></label>
							<input type="date" id="subin-date-from" name="subin_date_from" value="<?php echo esc_attr( $filters['date_from'] ); ?>" />
						</div>
						<div class="subin-filter-field">
							<label for="subin-date-to"><?php esc_html_e( 'To date', 'submission-inbox' ); ?></label>
							<input type="date" id="subin-date-to" name="subin_date_to" value="<?php echo esc_attr( $filters['date_to'] ); ?>" />
						</div>
					</div>
				</details>
			</form>
		</div>
		<?php
	}

	/**
	 * Build quick filter chips that reuse the server-side inbox filters.
	 *
	 * @param array<string,mixed> $filters Active filters.
	 * @return array<int,array{label:string,url:string,active:bool}>
	 */
	private function quick_filter_chips( array $filters ) {
		return array(
			array(
				'label'  => __( 'All', 'submission-inbox' ),
				'url'    => $this->list_url( array(), 1 ),
				'active' => '' === ( $filters['status'] ?? '' ) && '' === ( $filters['email_status'] ?? '' ) && empty( $filters['needs_attention'] ),
			),
			array(
				'label'  => __( 'Unseen', 'submission-inbox' ),
				'url'    => $this->list_url( $this->filters_for_quick_link( $filters, array( 'status' => 'new', 'email_status' => '', 'needs_attention' => '' ) ), 1 ),
				'active' => 'new' === ( $filters['status'] ?? '' ),
			),
			array(
				'label'  => __( 'Sent by WordPress', 'submission-inbox' ),
				'url'    => $this->list_url( $this->filters_for_quick_link( $filters, array( 'status' => '', 'email_status' => 'sent', 'needs_attention' => '' ) ), 1 ),
				'active' => 'sent' === ( $filters['email_status'] ?? '' ),
			),
			array(
				'label'  => __( 'Needs attention', 'submission-inbox' ),
				'url'    => $this->list_url( $this->filters_for_quick_link( $filters, array( 'status' => '', 'email_status' => '', 'needs_attention' => '1' ) ), 1 ),
				'active' => ! empty( $filters['needs_attention'] ),
			),
			array(
				'label'  => __( 'Failed', 'submission-inbox' ),
				'url'    => $this->list_url( $this->filters_for_quick_link( $filters, array( 'status' => '', 'email_status' => 'failed', 'needs_attention' => '' ) ), 1 ),
				'active' => 'failed' === ( $filters['email_status'] ?? '' ),
			),
			array(
				'label'  => __( 'No email generated', 'submission-inbox' ),
				'url'    => $this->list_url( $this->filters_for_quick_link( $filters, array( 'status' => '', 'email_status' => 'no_email_generated', 'needs_attention' => '' ) ), 1 ),
				'active' => 'no_email_generated' === ( $filters['email_status'] ?? '' ),
			),
			array(
				'label'  => __( 'Unknown', 'submission-inbox' ),
				'url'    => $this->list_url( $this->filters_for_quick_link( $filters, array( 'status' => '', 'email_status' => 'unknown', 'needs_attention' => '' ) ), 1 ),
				'active' => 'unknown' === ( $filters['email_status'] ?? '' ),
			),
			array(
				'label'  => __( 'Archived', 'submission-inbox' ),
				'url'    => $this->list_url( $this->filters_for_quick_link( $filters, array( 'status' => 'archived', 'email_status' => '', 'needs_attention' => '' ) ), 1 ),
				'active' => 'archived' === ( $filters['status'] ?? '' ),
			),
		);
	}

	/**
	 * Keep low-risk filters while switching primary status chips.
	 *
	 * @param array<string,mixed> $filters Active filters.
	 * @param array<string,mixed> $overrides Filter overrides.
	 * @return array<string,mixed>
	 */
	private function filters_for_quick_link( array $filters, array $overrides ) {
		return array_merge(
			$filters,
			array(
				'status'          => '',
				'email_status'    => '',
				'needs_attention' => '',
			),
			$overrides
		);
	}

	/**
	 * Render lead cards.
	 *
	 * @param array<int,object>  $leads Leads.
	 * @param int                $total Total.
	 * @param array<string,mixed> $filters Filters.
	 * @return void
	 */
	private function render_lead_cards( array $leads, $total, array $filters ) {
		if ( empty( $leads ) ) {
			if ( $this->has_active_filters( $filters ) || $total > 0 ) {
				SUBIN_View::empty_state( __( 'No leads match the current filters', 'submission-inbox' ), __( 'Try changing your filters or clearing the search.', 'submission-inbox' ) );
			} else {
				SUBIN_View::empty_state( __( 'No leads yet', 'submission-inbox' ), __( 'Saved form submissions will appear here after visitors submit your forms.', 'submission-inbox' ) );
			}
			return;
		}
		$items = $this->build_lead_list_items( $leads );
		?>
		<div class="si-list">
			<div class="si-list-head">
				<div></div>
				<div><?php esc_html_e( 'Lead', 'submission-inbox' ); ?></div>
				<div><?php esc_html_e( 'Message', 'submission-inbox' ); ?></div>
				<div><?php esc_html_e( 'Form', 'submission-inbox' ); ?></div>
				<div><?php esc_html_e( 'Email status', 'submission-inbox' ); ?></div>
				<div></div>
			</div>
			<?php foreach ( $items as $item ) : ?>
				<?php $this->render_lead_mockup_row( $item ); ?>
			<?php endforeach; ?>
		</div>
		<?php
	}

	/**
	 * Build display-ready lead list items.
	 *
	 * @param array<int,object> $leads Leads.
	 * @return array<int,array<string,mixed>>
	 */
	private function build_lead_list_items( array $leads ) {
		$lead_ids          = array_map( 'absint', wp_list_pluck( $leads, 'id' ) );
		$fields_by_lead_id = $this->fields->get_grouped_by_lead_ids( $lead_ids );
		$events_by_lead_id = $this->mail_events->get_grouped_by_lead_ids( $lead_ids );
		$items             = array();

		foreach ( $leads as $lead ) {
			$lead_id  = absint( $lead->id ?? 0 );
			$fields   = $fields_by_lead_id[ $lead_id ] ?? array();
			$events   = $events_by_lead_id[ $lead_id ] ?? array();
			$items[]  = $this->build_lead_list_item( $lead, $fields, $events );
		}

		return $items;
	}

	/**
	 * Build one display-ready lead list item.
	 *
	 * @param object            $lead Lead row.
	 * @param array<int,object> $fields Saved lead fields.
	 * @param array<int,object> $events Related email events.
	 * @return array<string,mixed>
	 */
	private function build_lead_list_item( $lead, array $fields, array $events ) {
		$lead_id          = absint( $lead->id );
		$email_status     = sanitize_key( $lead->email_status ?? 'unknown' );
		$needs_attention  = in_array( $email_status, array( 'failed', 'no_email_generated', 'unknown' ), true );
		$title            = '' !== trim( (string) ( $lead->customer_name ?? '' ) ) ? $lead->customer_name : __( 'No name provided', 'submission-inbox' );
		$preview          = $this->lead_card_preview( $lead, $fields );
		$notification     = $this->lead_notification_context( $lead, $events );
		$status_message   = $this->lead_card_email_status_message( $email_status, $notification['recipient'] );
		$form_settings_url = $this->form_settings_url_for_lead( $lead );
		$email_log_url    = $notification['event'] ? admin_url( 'admin.php?page=subin-email-log&s=' . rawurlencode( (string) absint( $notification['event']->id ) ) ) : admin_url( 'admin.php?page=subin-email-log&subin_status=' . rawurlencode( $email_status ) );
		$follow_up_at     = sanitize_text_field( $lead->follow_up_at ?? '' );
		$is_overdue       = '' !== $follow_up_at && strtotime( $follow_up_at ) && strtotime( $follow_up_at ) < current_time( 'timestamp' );
		$visible_fields   = $this->visible_lead_fields( $fields );

		return array(
			'lead'              => $lead,
			'lead_id'           => $lead_id,
			'email_status'      => $email_status,
			'needs_attention'   => $needs_attention,
			'title'             => $title,
			'preview'           => $preview,
			'status_message'    => $status_message,
			'form_settings_url' => $form_settings_url,
			'email_log_url'     => $email_log_url,
			'follow_up_at'      => $follow_up_at,
			'is_overdue'        => $is_overdue,
			'fields'            => $visible_fields,
			'field_highlights'  => $this->lead_field_highlights( $visible_fields ),
			'primary_meta'      => $this->lead_primary_meta( $lead ),
			'workflow_meta'     => $this->lead_workflow_meta( $lead, $follow_up_at, $is_overdue ),
			'detail_meta'       => $this->lead_detail_meta( $lead, $status_message ),
		);
	}

	/**
	 * Render one lead row using the supplied mockup structure.
	 *
	 * @param array<string,mixed> $item Display-ready lead item.
	 * @param bool                $open Whether row starts expanded.
	 * @return void
	 */
	private function render_lead_mockup_row( array $item, $open = false ) {
		$lead              = $item['lead'];
		$lead_id           = absint( $item['lead_id'] );
		$email_status      = sanitize_key( $item['email_status'] );
		$needs_attention   = ! empty( $item['needs_attention'] );
		$title             = (string) $item['title'];
		$preview           = (string) $item['preview'];
		$status_message    = (string) $item['status_message'];
		$form_settings_url = (string) $item['form_settings_url'];
		$email_log_url     = (string) $item['email_log_url'];
		$contact           = $this->lead_contact_line( $lead );
		$form_name         = $lead->form_name ? sanitize_text_field( $lead->form_name ) : __( 'Unknown form', 'submission-inbox' );
		?>
		<details class="si-row<?php echo $needs_attention ? ' needs-attention' : ''; ?>"<?php echo $open ? ' open' : ''; ?>>
			<summary class="si-row-main">
				<div class="si-check">
					<input type="checkbox" aria-label="<?php echo esc_attr( sprintf( __( 'Select lead %s', 'submission-inbox' ), $title ) ); ?>" onclick="event.stopPropagation();" />
				</div>

				<div class="si-person">
					<div class="si-name-line">
						<?php if ( 'new' === sanitize_key( $lead->status ?? '' ) ) : ?>
							<span class="si-dot" aria-hidden="true"></span>
						<?php endif; ?>
						<span class="si-name"><?php echo esc_html( $title ); ?></span>
					</div>
					<div class="si-email"><?php echo esc_html( '' !== $contact ? $contact : __( 'No contact details', 'submission-inbox' ) ); ?></div>
				</div>

				<div class="si-message">
					<div class="si-subject"><?php echo esc_html( '' !== $preview ? wp_trim_words( $preview, 16 ) : __( 'No message provided.', 'submission-inbox' ) ); ?></div>
					<div class="si-preview"><?php echo esc_html( $this->lead_preview_meta_line( $item ) ); ?></div>
				</div>

				<div class="si-meta">
					<strong><?php echo esc_html( $form_name ); ?></strong>
					<?php echo esc_html( $this->format_date( $lead->submitted_at ) ); ?>
				</div>

				<div class="si-status">
					<?php $this->render_si_email_badge( $email_status ); ?>
				</div>

				<div class="si-actions">
					<span class="si-icon-btn" aria-hidden="true">⋯</span>
				</div>
			</summary>

			<div class="si-row-extra">
				<div class="si-extra-card">
					<div>
						<?php $submitted_fields = $this->compact_submitted_fields( is_array( $item['fields'] ?? null ) ? $item['fields'] : array() ); ?>
						<?php if ( ! empty( $submitted_fields ) ) : ?>
							<h3 class="si-extra-title"><?php esc_html_e( 'Submitted fields', 'submission-inbox' ); ?></h3>
							<?php $this->render_si_field_rows( $submitted_fields ); ?>
						<?php else : ?>
							<h3 class="si-extra-title"><?php esc_html_e( 'Submitted fields', 'submission-inbox' ); ?></h3>
							<div class="si-message-box"><?php esc_html_e( 'No submitted fields to show.', 'submission-inbox' ); ?></div>
						<?php endif; ?>
					</div>

					<div>
						<h3 class="si-extra-title"><?php esc_html_e( 'Details', 'submission-inbox' ); ?></h3>
						<?php $this->render_si_field_rows( $item['detail_meta'] ); ?>
					</div>

					<div class="si-extra-actions">
						<a class="si-small-btn primary" href="<?php echo esc_url( $this->detail_url( $lead_id ) ); ?>"><?php esc_html_e( 'Open lead', 'submission-inbox' ); ?></a>
						<?php if ( 'failed' === $email_status ) : ?>
							<a class="si-small-btn" href="<?php echo esc_url( $email_log_url ); ?>"><?php esc_html_e( 'View email error', 'submission-inbox' ); ?></a>
						<?php elseif ( 'no_email_generated' === $email_status && '' !== $form_settings_url ) : ?>
							<a class="si-small-btn" href="<?php echo esc_url( $form_settings_url ); ?>"><?php esc_html_e( 'Check form settings', 'submission-inbox' ); ?></a>
						<?php endif; ?>
						<?php if ( 'new' === sanitize_key( $lead->status ?? '' ) ) : ?>
							<?php $this->render_status_action_button( $lead_id, 'seen', __( 'Mark seen', 'submission-inbox' ), 'si-small-btn' ); ?>
						<?php elseif ( 'archived' === sanitize_key( $lead->status ?? '' ) ) : ?>
							<?php $this->render_status_action_button( $lead_id, 'new', __( 'Restore', 'submission-inbox' ), 'si-small-btn' ); ?>
						<?php else : ?>
							<?php $this->render_status_action_button( $lead_id, 'new', __( 'Mark unseen', 'submission-inbox' ), 'si-small-btn' ); ?>
						<?php endif; ?>
						<?php if ( 'archived' !== sanitize_key( $lead->status ?? '' ) ) : ?>
							<?php $this->render_status_action_button( $lead_id, 'archived', __( 'Archive', 'submission-inbox' ), 'si-small-btn' ); ?>
						<?php endif; ?>
					</div>
				</div>
			</div>
		</details>
		<?php
	}

	/**
	 * Build compact contact line for the mockup row.
	 *
	 * @param object $lead Lead row.
	 * @return string
	 */
	private function lead_contact_line( $lead ) {
		$parts = array();

		if ( ! empty( $lead->customer_email ) ) {
			$parts[] = sanitize_text_field( (string) $lead->customer_email );
		}

		if ( ! empty( $lead->customer_phone ) ) {
			$parts[] = sanitize_text_field( (string) $lead->customer_phone );
		}

		return implode( ' · ', $parts );
	}

	/**
	 * Build the second line of compact lead metadata.
	 *
	 * @param array<string,mixed> $item Display-ready lead item.
	 * @return string
	 */
	private function lead_preview_meta_line( array $item ) {
		$parts = array();

		foreach ( is_array( $item['field_highlights'] ?? null ) ? $item['field_highlights'] : array() as $field ) {
			$parts[] = sanitize_text_field( $field['label'] ?? '' ) . ': ' . sanitize_text_field( $field['value'] ?? '' );
		}

		foreach ( is_array( $item['workflow_meta'] ?? null ) ? $item['workflow_meta'] : array() as $meta ) {
			$parts[] = sanitize_text_field( $meta['label'] ?? '' ) . ': ' . sanitize_text_field( $meta['value'] ?? '' );
		}

		return implode( ' · ', array_filter( $parts ) );
	}

	/**
	 * Render the email status badge used by the mockup.
	 *
	 * @param string $status Email status.
	 * @return void
	 */
	private function render_si_email_badge( $status ) {
		$status = sanitize_key( $status );
		$class  = 'unknown';
		$label  = $this->email_status_label( $status );

		if ( 'sent' === $status ) {
			$class = 'sent';
		} elseif ( 'failed' === $status ) {
			$class = 'failed';
		} elseif ( 'no_email_generated' === $status ) {
			$class = 'none';
			$label = __( 'No email', 'submission-inbox' );
		}

		printf(
			'<span class="si-badge %1$s">%2$s</span>',
			esc_attr( $class ),
			esc_html( $label )
		);
	}

	/**
	 * Render compact label/value rows in the expanded mockup card.
	 *
	 * @param array<int,array{label:string,value:string}> $rows Rows.
	 * @return void
	 */
	private function render_si_field_rows( array $rows ) {
		foreach ( $rows as $row ) {
			if ( empty( $row['label'] ) || '' === trim( (string) ( $row['value'] ?? '' ) ) ) {
				continue;
			}
			?>
			<div class="si-field">
				<span><?php echo esc_html( $row['label'] ); ?></span>
				<strong><?php echo esc_html( $row['value'] ); ?></strong>
			</div>
			<?php
		}
	}

	/**
	 * Prepare submitted fields for the compact expanded inbox card.
	 *
	 * @param array<int,array{label:string,value:string}> $fields Visible submitted fields.
	 * @return array<int,array{label:string,value:string}>
	 */
	private function compact_submitted_fields( array $fields ) {
		$regular = array();
		$message = array();

		foreach ( $fields as $field ) {
			$label = sanitize_text_field( $field['label'] ?? '' );
			$value = trim( sanitize_textarea_field( (string) ( $field['value'] ?? '' ) ) );
			if ( '' === $label || '' === $value ) {
				continue;
			}

			$row = array(
				'label' => $label,
				'value' => wp_trim_words( $value, 12, '...' ),
			);

			if ( 'message' === strtolower( $label ) ) {
				$message[] = $row;
			} else {
				$regular[] = $row;
			}
		}

		$rows = array_merge( $regular, $message );

		return array_slice( $rows, 0, self::DETAIL_FIELD_LIMIT );
	}

	/**
	 * Render compact expandable lead details for a table row.
	 *
	 * @param array<string,mixed> $item Display-ready lead item.
	 * @return void
	 */
	private function render_lead_row_details( array $item ) {
		$fields          = is_array( $item['fields'] ?? null ) ? $item['fields'] : array();
		$display_fields  = array_slice( $fields, 0, self::DETAIL_FIELD_LIMIT );
		$remaining_count = max( 0, count( $fields ) - count( $display_fields ) );
		?>
		<details class="subin-status-block">
			<summary class="subin-action-chip"><?php esc_html_e( 'Details', 'submission-inbox' ); ?></summary>
			<?php $this->render_lead_meta_list( $item['detail_meta'] ); ?>
			<?php if ( ! empty( $display_fields ) ) : ?>
				<?php $this->render_lead_meta_list( $display_fields ); ?>
			<?php endif; ?>
			<?php if ( $remaining_count > 0 ) : ?>
				<?php
				$this->render_lead_meta_list(
					array(
						array(
							'label' => __( 'More fields', 'submission-inbox' ),
							'value' => sprintf(
								/* translators: %d: number of hidden submitted fields. */
								_n( '%d additional field is available in the lead detail.', '%d additional fields are available in the lead detail.', $remaining_count, 'submission-inbox' ),
								$remaining_count
							),
						),
					)
				);
				?>
			<?php endif; ?>
		</details>
		<?php
	}

	/**
	 * Render a compact meta list.
	 *
	 * @param array<int,array{label:string,value:string,class?:string}> $items Meta items.
	 * @param string                                                    $extra_class Optional class.
	 * @return void
	 */
	private function render_lead_meta_list( array $items, $extra_class = '' ) {
		if ( empty( $items ) ) {
			return;
		}

		$class = 'subin-lead-card__meta';
		if ( '' !== $extra_class ) {
			$class .= ' ' . sanitize_html_class( $extra_class );
		}
		?>
		<div class="<?php echo esc_attr( $class ); ?>">
			<?php foreach ( $items as $item ) : ?>
				<?php
				$item_class = ! empty( $item['class'] ) ? ' class="' . esc_attr( sanitize_html_class( $item['class'] ) ) . '"' : '';
				?>
				<span<?php echo $item_class; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Built from sanitize_html_class() above. ?>>
					<?php echo esc_html( $item['label'] ); ?>:
					<strong><?php echo esc_html( $item['value'] ); ?></strong>
				</span>
			<?php endforeach; ?>
		</div>
		<?php
	}

	/**
	 * Get the best compact lead preview for the inbox card.
	 *
	 * @param object $lead Lead row.
	 * @param array<int,object>|null $fields Saved lead fields.
	 * @return string
	 */
	private function lead_card_preview( $lead, ?array $fields = null ) {
		if ( '' !== trim( (string) ( $lead->message_preview ?? '' ) ) ) {
			return sanitize_textarea_field( (string) $lead->message_preview );
		}

		if ( null === $fields ) {
			$fields = $this->fields->get_by_lead_id( absint( $lead->id ?? 0 ) );
		}

		foreach ( $fields as $field ) {
			if ( ! empty( $field->is_sensitive ) || '' === trim( (string) $field->field_value ) || $this->is_internal_field( $field ) || $this->is_contact_preview_field( $field ) ) {
				continue;
			}

			return sanitize_textarea_field( (string) $field->field_value );
		}

		return '';
	}

	/**
	 * Filter saved fields for compact inbox details.
	 *
	 * @param array<int,object> $fields Saved lead fields.
	 * @return array<int,array{label:string,value:string}>
	 */
	private function visible_lead_fields( array $fields ) {
		$visible = array();

		foreach ( $fields as $field ) {
			if ( ! empty( $field->is_sensitive ) || '' === trim( (string) $field->field_value ) || $this->is_internal_field( $field ) ) {
				continue;
			}

			$label     = '' !== trim( (string) ( $field->field_label ?? '' ) ) ? (string) $field->field_label : (string) ( $field->field_key ?? '' );
			$visible[] = array(
				'label' => sanitize_text_field( $label ),
				'value' => sanitize_textarea_field( (string) $field->field_value ),
			);
		}

		return $visible;
	}

	/**
	 * Pick a small set of submitted fields for the inbox card summary.
	 *
	 * @param array<int,array{label:string,value:string}> $fields Visible fields.
	 * @return array<int,array{label:string,value:string}>
	 */
	private function lead_field_highlights( array $fields ) {
		$highlights = array();

		foreach ( $fields as $field ) {
			$label = strtolower( (string) ( $field['label'] ?? '' ) );
			if ( $this->compact_field_is_identity_or_message( $label ) ) {
				continue;
			}

			$highlights[] = array(
				'label' => sanitize_text_field( $field['label'] ),
				'value' => wp_trim_words( sanitize_text_field( $field['value'] ), 8 ),
			);

			if ( count( $highlights ) >= self::HIGHLIGHT_FIELD_LIMIT ) {
				break;
			}
		}

		return $highlights;
	}

	/**
	 * Build stable primary meta for a lead card.
	 *
	 * @param object $lead Lead row.
	 * @return array<int,array{label:string,value:string}>
	 */
	private function lead_primary_meta( $lead ) {
		return array(
			array(
				'label' => __( 'Form', 'submission-inbox' ),
				'value' => $lead->form_name ? sanitize_text_field( $lead->form_name ) : __( 'Unknown form', 'submission-inbox' ),
			),
			array(
				'label' => __( 'Submitted', 'submission-inbox' ),
				'value' => $this->format_date( $lead->submitted_at ),
			),
		);
	}

	/**
	 * Build workflow meta for a lead card.
	 *
	 * @param object $lead Lead row.
	 * @param string $follow_up_at Follow-up datetime.
	 * @param bool   $is_overdue Whether follow-up is overdue.
	 * @return array<int,array{label:string,value:string,class?:string}>
	 */
	private function lead_workflow_meta( $lead, $follow_up_at, $is_overdue ) {
		$items = array(
			array(
				'label' => __( 'Workflow', 'submission-inbox' ),
				'value' => $this->workflow_status_label( $lead->workflow_status ?? 'open' ),
			),
			array(
				'label' => __( 'Priority', 'submission-inbox' ),
				'value' => $this->priority_label( $lead->priority ?? 'normal' ),
			),
			array(
				'label' => __( 'Assignee', 'submission-inbox' ),
				'value' => $this->assignee_label( $lead->assigned_user_id ?? 0 ),
			),
		);

		if ( '' !== $follow_up_at ) {
			$items[] = array(
				'label' => __( 'Follow-up', 'submission-inbox' ),
				'value' => $this->format_date( $follow_up_at ),
				'class' => $is_overdue ? 'subin-workflow-overdue' : '',
			);
		}

		return $items;
	}

	/**
	 * Build expandable detail meta for a lead card.
	 *
	 * @param object $lead Lead row.
	 * @param string $status_message Email health summary.
	 * @return array<int,array{label:string,value:string}>
	 */
	private function lead_detail_meta( $lead, $status_message ) {
		return array(
			array(
				'label' => __( 'Source', 'submission-inbox' ),
				'value' => $this->provider_label( $lead->provider ?? '' ),
			),
			array(
				'label' => __( 'Workflow', 'submission-inbox' ),
				'value' => $this->workflow_status_label( $lead->workflow_status ?? 'open' ),
			),
			array(
				'label' => __( 'Priority', 'submission-inbox' ),
				'value' => $this->priority_label( $lead->priority ?? 'normal' ),
			),
			array(
				'label' => __( 'Assignee', 'submission-inbox' ),
				'value' => $this->assignee_label( $lead->assigned_user_id ?? 0 ),
			),
			array(
				'label' => __( 'Email health', 'submission-inbox' ),
				'value' => sanitize_text_field( $status_message ),
			),
		);
	}

	/**
	 * Whether a compact field duplicates identity/contact/message content.
	 *
	 * @param string $label Field label.
	 * @return bool
	 */
	private function compact_field_is_identity_or_message( $label ) {
		foreach ( array( 'name', 'email', 'e-mail', 'phone', 'tel', 'mobile', 'message', 'comments', 'comment', 'enquiry', 'inquiry', 'details' ) as $needle ) {
			if ( false !== strpos( $label, $needle ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Whether a field duplicates the card identity/contact line.
	 *
	 * @param object $field Field row.
	 * @return bool
	 */
	private function is_contact_preview_field( $field ) {
		$key   = strtolower( (string) ( $field->field_key ?? '' ) );
		$label = strtolower( (string) ( $field->field_label ?? '' ) );
		$text  = $key . ' ' . $label;

		foreach ( array( 'name', 'email', 'e-mail', 'phone', 'tel', 'mobile' ) as $needle ) {
			if ( false !== strpos( $text, $needle ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Get compact notification context for an inbox card.
	 *
	 * @param object $lead Lead row.
	 * @param array<int,object>|null $events Related email events.
	 * @return array{event:object|null,recipient:string}
	 */
	private function lead_notification_context( $lead, ?array $events = null ) {
		if ( null === $events ) {
			$events = $this->mail_events->get_by_lead_id( absint( $lead->id ?? 0 ) );
		}

		$event  = $this->latest_admin_notification_event( $events );
		if ( $event && '' !== trim( (string) ( $event->to_email ?? '' ) ) ) {
			return array(
				'event'     => $event,
				'recipient' => sanitize_text_field( (string) $event->to_email ),
			);
		}

		$recipient = $this->notification_recipient_details_for_lead( $lead );
		return array(
			'event'     => $event,
			'recipient' => sanitize_text_field( $recipient['email'] ?? '' ),
		);
	}

	/**
	 * Message for the compact email status card.
	 *
	 * @param string $status Email status.
	 * @param string $recipient Recipient email.
	 * @return string
	 */
	private function lead_card_email_status_message( $status, $recipient = '' ) {
		$status    = sanitize_key( $status );
		$recipient = sanitize_text_field( $recipient );

		if ( 'sent' === $status && '' !== $recipient ) {
			return sprintf(
				/* translators: %s: notification recipient email. */
				__( 'Admin notification sent to %s.', 'submission-inbox' ),
				$recipient
			);
		}

		$messages = array(
			'sent'               => __( 'Admin notification sent by WordPress.', 'submission-inbox' ),
			'failed'             => __( 'Lead is saved, but the notification email failed.', 'submission-inbox' ),
			'no_email_generated' => __( 'This form submission was saved, but no notification email was created.', 'submission-inbox' ),
			'unknown'            => __( 'Lead is saved, but the notification status is unknown.', 'submission-inbox' ),
			'pending'            => __( 'Lead is saved, but the notification status is unknown.', 'submission-inbox' ),
		);

		return $messages[ $status ] ?? $messages['unknown'];
	}

	/**
	 * Render pagination.
	 *
	 * @param int    $total Total rows.
	 * @param int    $paged Current page.
	 * @param array<string,mixed> $filters Filters.
	 * @return void
	 */
	private function render_pagination( $total, $paged, array $filters ) {
		$total_pages = max( 1, (int) ceil( $total / self::PER_PAGE ) );

		if ( $total_pages <= 1 ) {
			return;
		}

		echo '<nav class="subin-pagination" aria-label="' . esc_attr__( 'Inbox pagination', 'submission-inbox' ) . '">';
		/* translators: 1: current page number, 2: total page count. */
		echo '<span class="subin-pagination__info">' . esc_html( sprintf( __( 'Page %1$d of %2$d', 'submission-inbox' ), absint( $paged ), absint( $total_pages ) ) ) . '</span>';
		echo '<div class="subin-pagination__links">';
		echo wp_kses_post(
			paginate_links(
				array(
					'base'      => add_query_arg( 'paged', '%#%', $this->list_url( $filters, 1 ) ),
					'format'    => '',
					'current'   => $paged,
					'total'     => $total_pages,
					'prev_text' => __( 'Previous', 'submission-inbox' ),
					'next_text' => __( 'Next', 'submission-inbox' ),
				)
			)
		);
		echo '</div></nav>';
	}

	/**
	 * Render lead detail.
	 *
	 * @param int $lead_id Lead id.
	 * @return void
	 */
	private function render_detail( $lead_id ) {
		$lead = $this->leads->get( $lead_id );

		if ( ! $lead ) {
			wp_die( esc_html__( 'Lead not found.', 'submission-inbox' ) );
		}

		$fields = $this->fields->get_by_lead_id( $lead_id );
		$events = $this->mail_events->get_related_events_for_lead( $lead_id );
		$notes  = $this->activity->get_notes( $lead_id );
		$timeline = $this->activity->get_timeline( $lead_id );

		SUBIN_View::page_header(
			__( 'Lead detail', 'submission-inbox' ),
			__( 'Review the saved form submission, contact details, and related WordPress email events.', 'submission-inbox' ),
			array(
				'secondary_actions' => array(
					array(
						'label' => __( 'Back to Inbox', 'submission-inbox' ),
						'url'   => $this->list_url( array(), 1 ),
					),
				),
				'wrapper_class'     => 'subin-lead-detail-page',
			)
		);

		$this->maybe_add_detail_notice();
		SUBIN_AdminNotices::render_settings_errors( 'subin_messages' );
		?>
		<section class="subin-lead-summary-card">
			<div class="subin-lead-summary-main">
				<div>
					<div class="subin-lead-summary-badges">
						<?php $this->status_badge( $lead->status, $this->lead_status_label( $lead->status ) ); ?>
						<?php $this->status_badge( $lead->email_status, $this->email_status_label( $lead->email_status ) ); ?>
					</div>
					<h2><?php echo esc_html( $lead->customer_name ? $lead->customer_name : __( 'No name provided', 'submission-inbox' ) ); ?></h2>
					<div class="subin-lead-card__contact">
						<?php if ( ! empty( $lead->customer_email ) ) : ?>
							<span><?php echo esc_html( $lead->customer_email ); ?></span>
						<?php endif; ?>
						<?php if ( ! empty( $lead->customer_phone ) ) : ?>
							<span><?php echo esc_html( $lead->customer_phone ); ?></span>
						<?php endif; ?>
					</div>
					<div class="subin-lead-summary-context">
						<?php echo esc_html( $lead->form_name ? $lead->form_name : __( 'Unknown form', 'submission-inbox' ) ); ?>
						<span aria-hidden="true">·</span>
						<?php echo esc_html( $this->format_date( $lead->submitted_at ) ); ?>
					</div>
				</div>
				<div class="subin-lead-summary-actions">
					<?php if ( 'new' === sanitize_key( $lead->status ?? '' ) ) : ?>
						<?php $this->render_status_action_button( $lead_id, 'seen', __( 'Mark as seen', 'submission-inbox' ), 'subin-action-chip' ); ?>
					<?php else : ?>
						<?php $this->render_status_action_button( $lead_id, 'new', __( 'Mark as unseen', 'submission-inbox' ), 'subin-action-chip' ); ?>
					<?php endif; ?>
					<?php if ( 'archived' !== sanitize_key( $lead->status ?? '' ) ) : ?>
						<?php $this->render_status_action_button( $lead_id, 'archived', __( 'Archive', 'submission-inbox' ), 'subin-action-chip' ); ?>
					<?php endif; ?>
				</div>
			</div>
		</section>
		<div class="subin-lead-detail-layout subin-lead-detail-layout--focused">
			<div class="subin-lead-detail-main">
				<section class="subin-detail-panel subin-submitted-details subin-submitted-details--primary">
					<h2>
						<?php esc_html_e( 'Submitted details', 'submission-inbox' ); ?>
						<?php SUBIN_View::help_tooltip( __( 'Fields submitted by the visitor. Sensitive/internal fields are not shown.', 'submission-inbox' ) ); ?>
					</h2>
					<?php $this->render_fields( $fields ); ?>
				</section>
				<section class="subin-detail-panel subin-notes-panel">
					<h2>
						<?php esc_html_e( 'Internal note', 'submission-inbox' ); ?>
						<?php SUBIN_View::help_tooltip( __( 'Private admin notes for this lead. Visitors do not see these notes.', 'submission-inbox' ) ); ?>
					</h2>
					<?php $this->render_notes_panel( $lead, $notes ); ?>
				</section>
			</div>
			<aside class="subin-lead-detail-sidebar">
				<section class="subin-detail-panel subin-lead-details-panel">
					<h2>
						<?php esc_html_e( 'Lead details', 'submission-inbox' ); ?>
						<?php SUBIN_View::help_tooltip( __( 'Current workflow, priority, assignee, and source for this lead.', 'submission-inbox' ) ); ?>
					</h2>
					<?php $this->render_lead_details_summary( $lead ); ?>
				</section>
				<details class="subin-detail-panel subin-detail-drawer subin-email-summary">
					<summary>
						<span class="subin-detail-drawer__label">
							<span><?php esc_html_e( 'Email summary', 'submission-inbox' ); ?></span>
							<?php SUBIN_View::help_tooltip( __( 'Latest notification status and quick email actions for this lead.', 'submission-inbox' ) ); ?>
						</span>
					</summary>
					<?php $this->render_email_summary( $lead, $events ); ?>
				</details>
				<details class="subin-detail-panel subin-detail-drawer subin-workflow-panel">
					<summary>
						<span class="subin-detail-drawer__label">
							<span><?php esc_html_e( 'Edit workflow', 'submission-inbox' ); ?></span>
							<?php SUBIN_View::help_tooltip( __( 'Update workflow, priority, assignee, and follow-up date for this lead.', 'submission-inbox' ) ); ?>
						</span>
					</summary>
					<?php $this->render_workflow_panel( $lead ); ?>
				</details>
				<details class="subin-detail-panel subin-detail-drawer subin-source-card">
					<summary>
						<span class="subin-detail-drawer__label">
							<span><?php esc_html_e( 'Source', 'submission-inbox' ); ?></span>
							<?php SUBIN_View::help_tooltip( __( 'Where this lead came from, including form and page details.', 'submission-inbox' ) ); ?>
						</span>
					</summary>
					<?php $this->render_source_details( $lead, $fields ); ?>
				</details>
				<details class="subin-detail-panel subin-detail-drawer">
					<summary>
						<span class="subin-detail-drawer__label">
							<span><?php esc_html_e( 'Email activity', 'submission-inbox' ); ?></span>
							<?php SUBIN_View::help_tooltip( __( 'WordPress email attempts related to this lead.', 'submission-inbox' ) ); ?>
						</span>
					</summary>
					<?php $this->render_email_activity( $lead, $events ); ?>
				</details>
				<details class="subin-detail-panel subin-detail-drawer">
					<summary>
						<span class="subin-detail-drawer__label">
							<span><?php esc_html_e( 'Activity', 'submission-inbox' ); ?></span>
							<?php SUBIN_View::help_tooltip( __( 'Chronological internal changes and events recorded for this lead.', 'submission-inbox' ) ); ?>
						</span>
					</summary>
					<?php $this->render_timeline_panel( $timeline ); ?>
				</details>
			</aside>
		</div>
		<?php
		SUBIN_View::page_footer();
	}

	/**
	 * Render compact lead metadata for the detail sidebar.
	 *
	 * @param object $lead Lead row.
	 * @return void
	 */
	private function render_lead_details_summary( $lead ) {
		$assigned_user_id = absint( $lead->assigned_user_id ?? 0 );
		$assigned_label   = __( 'Unassigned', 'submission-inbox' );
		if ( $assigned_user_id > 0 ) {
			$user = get_userdata( $assigned_user_id );
			if ( $user ) {
				$assigned_label = $user->display_name;
			}
		}
		?>
		<div class="subin-side-list">
			<div class="subin-side-list__item">
				<span><?php esc_html_e( 'Workflow', 'submission-inbox' ); ?></span>
				<strong><?php echo esc_html( $this->workflow->workflow_statuses()[ sanitize_key( $lead->workflow_status ?? 'open' ) ] ?? __( 'Open', 'submission-inbox' ) ); ?></strong>
			</div>
			<div class="subin-side-list__item">
				<span><?php esc_html_e( 'Priority', 'submission-inbox' ); ?></span>
				<strong><?php echo esc_html( $this->workflow->priorities()[ sanitize_key( $lead->priority ?? 'normal' ) ] ?? __( 'Normal', 'submission-inbox' ) ); ?></strong>
			</div>
			<div class="subin-side-list__item">
				<span><?php esc_html_e( 'Assignee', 'submission-inbox' ); ?></span>
				<strong><?php echo esc_html( $assigned_label ); ?></strong>
			</div>
			<div class="subin-side-list__item">
				<span><?php esc_html_e( 'Source', 'submission-inbox' ); ?></span>
				<strong><?php echo esc_html( $this->provider_label( $lead->provider ) ); ?></strong>
			</div>
		</div>
		<?php
	}

	/**
	 * Render fields list.
	 *
	 * @param array<int,object> $fields Fields.
	 * @return void
	 */
	private function render_fields( array $fields ) {
		if ( empty( $fields ) ) {
			SUBIN_View::empty_state( __( 'No submitted fields', 'submission-inbox' ), __( 'This lead was saved without visible form field values.', 'submission-inbox' ) );
			return;
		}
		$display_fields = array();
		$message_fields = array();

		foreach ( $fields as $field ) {
			if ( ! empty( $field->is_sensitive ) || '' === trim( (string) $field->field_value ) || $this->is_internal_field( $field ) ) {
				continue;
			}

			if ( $this->field_looks_like_message( $field ) ) {
				$message_fields[] = $field;
			} else {
				$display_fields[] = $field;
			}
		}

		$display_fields = array_merge( $display_fields, $message_fields );

		if ( empty( $display_fields ) ) {
			SUBIN_View::empty_state( __( 'No submitted fields', 'submission-inbox' ), __( 'This lead was saved without visible form field values.', 'submission-inbox' ) );
			return;
		}
		?>
		<div class="subin-submitted-details__table" role="table" aria-label="<?php esc_attr_e( 'Submitted details', 'submission-inbox' ); ?>">
			<?php foreach ( $display_fields as $field ) : ?>
				<?php
				$value       = (string) $field->field_value;
				$field_label = '' !== trim( (string) $field->field_label ) ? $field->field_label : $field->field_key;
				?>
				<div class="subin-submitted-details__row" role="row">
					<div class="subin-submitted-details__label" role="cell"><?php echo esc_html( $field_label ); ?></div>
					<div class="subin-submitted-details__value" role="cell"><?php echo nl2br( esc_html( $value ) ); ?></div>
				</div>
			<?php endforeach; ?>
		</div>
		<?php
	}

	/**
	 * Render compact source details.
	 *
	 * @param object $lead Lead row.
	 * @return void
	 */
	private function render_source_details( $lead, array $fields = array() ) {
		$provider       = sanitize_key( $lead->provider ?? '' );
		$entry_id       = '';
		$form_id_label  = __( 'Form ID', 'submission-inbox' );
		$entry_id_label = '';

		if ( 'wpforms' === $provider ) {
			$entry_id       = $this->external_entry_id_from_fields( $fields, '_wpforms_entry_id' );
			$form_id_label  = __( 'WPForms form ID', 'submission-inbox' );
			$entry_id_label = __( 'WPForms entry ID', 'submission-inbox' );
		} elseif ( 'fluent_forms' === $provider ) {
			$entry_id       = $this->external_entry_id_from_fields( $fields, '_fluent_forms_submission_id' );
			$form_id_label  = __( 'Fluent Forms form ID', 'submission-inbox' );
			$entry_id_label = __( 'Fluent Forms submission ID', 'submission-inbox' );
		} elseif ( 'forminator' === $provider ) {
			$entry_id       = $this->external_entry_id_from_fields( $fields, '_forminator_entry_id' );
			$form_id_label  = __( 'Forminator form ID', 'submission-inbox' );
			$entry_id_label = __( 'Forminator entry ID', 'submission-inbox' );
		} elseif ( 'ninja_forms' === $provider ) {
			$entry_id       = $this->external_entry_id_from_fields( $fields, '_ninja_forms_submission_id' );
			$form_id_label  = __( 'Ninja Forms form ID', 'submission-inbox' );
			$entry_id_label = __( 'Ninja Forms submission ID', 'submission-inbox' );
		}
		?>
		<div class="subin-side-list">
			<div class="subin-side-list__item">
				<span><?php esc_html_e( 'Source type', 'submission-inbox' ); ?></span>
				<strong><?php echo esc_html( $this->provider_label( $lead->provider ) ); ?></strong>
			</div>
			<div class="subin-side-list__item">
				<span><?php esc_html_e( 'Form name', 'submission-inbox' ); ?></span>
				<strong><?php echo esc_html( $lead->form_name ? $lead->form_name : __( 'Unknown form', 'submission-inbox' ) ); ?></strong>
			</div>
			<div class="subin-side-list__item">
				<span><?php echo esc_html( $form_id_label ); ?></span>
				<strong><?php echo esc_html( (string) $lead->form_id ); ?></strong>
			</div>
			<?php if ( '' !== $entry_id ) : ?>
				<div class="subin-side-list__item">
					<span><?php echo esc_html( $entry_id_label ); ?></span>
					<strong><?php echo esc_html( $entry_id ); ?></strong>
				</div>
			<?php endif; ?>
			<div class="subin-side-list__item">
				<span><?php esc_html_e( 'Submitted date', 'submission-inbox' ); ?></span>
				<strong><?php echo esc_html( $this->format_date( $lead->submitted_at ) ); ?></strong>
			</div>
			<div class="subin-side-list__item">
				<span><?php esc_html_e( 'Source URL', 'submission-inbox' ); ?></span>
				<strong><?php $this->source_link( $lead->source_url ); ?></strong>
			</div>
			<div class="subin-side-list__item">
				<span><?php esc_html_e( 'Referrer', 'submission-inbox' ); ?></span>
				<strong><?php $this->source_link( $lead->referrer ); ?></strong>
			</div>
		</div>
		<?php
	}

	/**
	 * Render workflow controls.
	 *
	 * @param object $lead Lead row.
	 * @return void
	 */
	private function render_workflow_panel( $lead ) {
		$lead_id = absint( $lead->id ?? 0 );
		$users   = get_users(
			array(
				'fields'  => array( 'ID', 'display_name' ),
				'orderby' => 'display_name',
			)
		);
		$follow_up_value = '';
		if ( ! empty( $lead->follow_up_at ) && strtotime( (string) $lead->follow_up_at ) ) {
			$follow_up_value = gmdate( 'Y-m-d', strtotime( (string) $lead->follow_up_at ) );
		}
		?>
		<form method="post" action="" class="subin-workflow-form">
			<input type="hidden" name="subin_lead_action" value="update_workflow" />
			<input type="hidden" name="lead_id" value="<?php echo esc_attr( (string) $lead_id ); ?>" />
			<?php wp_nonce_field( 'subin_update_lead_' . $lead_id, 'subin_lead_nonce' ); ?>
			<div class="subin-side-list">
				<div class="subin-side-list__item">
					<label for="subin-workflow-status-detail"><?php esc_html_e( 'Workflow status', 'submission-inbox' ); ?></label>
					<select id="subin-workflow-status-detail" name="workflow_status">
						<?php foreach ( $this->workflow->workflow_statuses() as $key => $label ) : ?>
							<option value="<?php echo esc_attr( $key ); ?>" <?php selected( sanitize_key( $lead->workflow_status ?? 'open' ), $key ); ?>><?php echo esc_html( $label ); ?></option>
						<?php endforeach; ?>
					</select>
				</div>
				<div class="subin-side-list__item">
					<label for="subin-priority-detail"><?php esc_html_e( 'Priority', 'submission-inbox' ); ?></label>
					<select id="subin-priority-detail" name="priority">
						<?php foreach ( $this->workflow->priorities() as $key => $label ) : ?>
							<option value="<?php echo esc_attr( $key ); ?>" <?php selected( sanitize_key( $lead->priority ?? 'normal' ), $key ); ?>><?php echo esc_html( $label ); ?></option>
						<?php endforeach; ?>
					</select>
				</div>
				<div class="subin-side-list__item">
					<label for="subin-assignee-detail"><?php esc_html_e( 'Assignee', 'submission-inbox' ); ?></label>
					<select id="subin-assignee-detail" name="assigned_user_id">
						<option value="0"><?php esc_html_e( 'Unassigned', 'submission-inbox' ); ?></option>
						<?php foreach ( $users as $user ) : ?>
							<option value="<?php echo esc_attr( (string) $user->ID ); ?>" <?php selected( absint( $lead->assigned_user_id ?? 0 ), absint( $user->ID ) ); ?>><?php echo esc_html( $user->display_name ); ?></option>
						<?php endforeach; ?>
					</select>
				</div>
				<div class="subin-side-list__item">
					<label for="subin-follow-up-detail"><?php esc_html_e( 'Follow-up date', 'submission-inbox' ); ?></label>
					<input id="subin-follow-up-detail" type="date" name="follow_up_at" value="<?php echo esc_attr( $follow_up_value ); ?>" />
				</div>
			</div>
			<p><button type="submit" class="button button-primary subin-btn subin-btn-primary"><?php esc_html_e( 'Save workflow', 'submission-inbox' ); ?></button></p>
		</form>
		<?php
	}

	/**
	 * Render lead notes and note form.
	 *
	 * @param object            $lead Lead row.
	 * @param array<int,object> $notes Notes.
	 * @return void
	 */
	private function render_notes_panel( $lead, array $notes ) {
		$lead_id = absint( $lead->id ?? 0 );
		?>
		<form method="post" action="" class="subin-note-form">
			<input type="hidden" name="subin_lead_action" value="add_note" />
			<input type="hidden" name="lead_id" value="<?php echo esc_attr( (string) $lead_id ); ?>" />
			<?php wp_nonce_field( 'subin_update_lead_' . $lead_id, 'subin_lead_nonce' ); ?>
			<div class="subin-note-form__row">
				<label class="screen-reader-text" for="subin-lead-note"><?php esc_html_e( 'Add note', 'submission-inbox' ); ?></label>
				<textarea id="subin-lead-note" name="lead_note" rows="1" class="large-text" placeholder="<?php esc_attr_e( 'Add a short note, for example: called, no answer...', 'submission-inbox' ); ?>"></textarea>
				<button type="submit" class="button button-primary subin-btn subin-btn-primary"><?php esc_html_e( 'Add note', 'submission-inbox' ); ?></button>
			</div>
		</form>

		<?php if ( ! empty( $notes ) ) : ?>
			<div class="subin-workflow-list">
				<?php foreach ( $notes as $note ) : ?>
					<article class="subin-workflow-item">
						<strong><?php echo esc_html( $note->display_name ? $note->display_name : __( 'WordPress user', 'submission-inbox' ) ); ?></strong>
						<p><?php echo nl2br( esc_html( $note->note ) ); ?></p>
						<span><?php echo esc_html( $this->format_date( $note->created_at ) ); ?></span>
						<div class="subin-note-actions">
							<details class="subin-note-edit">
								<summary><?php esc_html_e( 'Edit', 'submission-inbox' ); ?></summary>
								<?php $note_form_id = 'subin-lead-note-edit-form-' . absint( $note->id ?? 0 ); ?>
								<form id="<?php echo esc_attr( $note_form_id ); ?>" method="post" action="" class="subin-note-edit-form">
									<input type="hidden" name="subin_lead_action" value="update_note" />
									<input type="hidden" name="lead_id" value="<?php echo esc_attr( (string) $lead_id ); ?>" />
									<input type="hidden" name="note_id" value="<?php echo esc_attr( (string) absint( $note->id ?? 0 ) ); ?>" />
									<?php wp_nonce_field( 'subin_update_lead_' . $lead_id, 'subin_lead_nonce' ); ?>
									<label class="screen-reader-text" for="<?php echo esc_attr( 'subin-lead-note-edit-' . absint( $note->id ?? 0 ) ); ?>"><?php esc_html_e( 'Edit note', 'submission-inbox' ); ?></label>
									<textarea id="<?php echo esc_attr( 'subin-lead-note-edit-' . absint( $note->id ?? 0 ) ); ?>" name="lead_note" rows="3"><?php echo esc_textarea( (string) $note->note ); ?></textarea>
								</form>
								<div class="subin-note-edit-actions">
									<button type="submit" form="<?php echo esc_attr( $note_form_id ); ?>" class="button button-primary subin-btn subin-btn-primary"><?php esc_html_e( 'Save note', 'submission-inbox' ); ?></button>
									<form method="post" action="" class="subin-note-delete-form">
										<input type="hidden" name="subin_lead_action" value="delete_note" />
										<input type="hidden" name="lead_id" value="<?php echo esc_attr( (string) $lead_id ); ?>" />
										<input type="hidden" name="note_id" value="<?php echo esc_attr( (string) absint( $note->id ?? 0 ) ); ?>" />
										<?php wp_nonce_field( 'subin_update_lead_' . $lead_id, 'subin_lead_nonce' ); ?>
										<button type="submit" class="button subin-action-chip subin-action-chip-danger" onclick="return window.confirm('<?php echo esc_js( __( 'Delete this note?', 'submission-inbox' ) ); ?>');"><?php esc_html_e( 'Delete', 'submission-inbox' ); ?></button>
									</form>
								</div>
							</details>
						</div>
					</article>
				<?php endforeach; ?>
			</div>
		<?php endif; ?>
		<?php
	}

	/**
	 * Render lead activity timeline.
	 *
	 * @param array<int,object> $timeline Timeline.
	 * @return void
	 */
	private function render_timeline_panel( array $timeline ) {
		?>
		<?php if ( ! empty( $timeline ) ) : ?>
			<div class="subin-workflow-list">
				<?php foreach ( $timeline as $activity ) : ?>
					<article class="subin-workflow-item">
						<strong><?php echo esc_html( $activity->activity_message ); ?></strong>
						<span><?php echo esc_html( $this->format_date( $activity->created_at ) ); ?></span>
					</article>
				<?php endforeach; ?>
			</div>
		<?php else : ?>
			<?php SUBIN_View::empty_state( __( 'No activity yet', 'submission-inbox' ), __( 'Workflow changes and notes will appear here.', 'submission-inbox' ) ); ?>
		<?php endif; ?>
		<?php
	}

	/**
	 * Render sidebar email summary.
	 *
	 * @param object            $lead Lead row.
	 * @param array<int,object> $events Events.
	 * @return void
	 */
	private function render_email_summary( $lead, array $events ) {
		$admin_event  = $this->latest_admin_notification_event( $events );
		$admin_status = $admin_event ? sanitize_key( $admin_event->status ?? 'unknown' ) : sanitize_key( $lead->email_status ?? 'unknown' );
		$admin_to     = $admin_event ? sanitize_text_field( $admin_event->to_email ?? '' ) : $this->notification_recipient_details_for_lead( $lead )['email'];
		$auto_reply   = $this->auto_reply_details_for_lead( $lead, $events );
		?>
		<div class="subin-email-summary__list">
			<div class="subin-email-summary__item">
				<div>
					<strong><?php esc_html_e( 'Admin notification', 'submission-inbox' ); ?></strong>
					<?php if ( '' !== $admin_to ) : ?>
						<span><?php echo esc_html( $admin_to ); ?></span>
					<?php endif; ?>
				</div>
				<?php $this->status_badge( $admin_status, $this->email_status_label( $admin_status ) ); ?>
			</div>
			<?php $this->render_admin_notification_followup_actions( $lead, $admin_event, $admin_status ); ?>
			<?php if ( $auto_reply['event'] || $auto_reply['enabled'] ) : ?>
				<div class="subin-email-summary__item">
					<div>
						<strong><?php esc_html_e( 'Visitor auto-reply', 'submission-inbox' ); ?></strong>
						<?php if ( '' !== $auto_reply['recipient'] ) : ?>
							<span><?php echo esc_html( $auto_reply['recipient'] ); ?></span>
						<?php endif; ?>
					</div>
					<?php $this->status_badge( $auto_reply['status'], $this->email_status_label( $auto_reply['status'] ) ); ?>
				</div>
			<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * Render existing admin notification follow-up actions in the new layout.
	 *
	 * @param object      $lead Lead row.
	 * @param object|null $event Related admin notification event.
	 * @param string      $status Notification status.
	 * @return void
	 */
	private function render_admin_notification_followup_actions( $lead, $event, $status ) {
		$status        = sanitize_key( $status );
		$form_settings = $this->form_settings_url_for_lead( $lead );

		if ( 'failed' !== $status && ( 'no_email_generated' !== $status || '' === $form_settings ) ) {
			return;
		}

		$email_log_url      = $event ? admin_url( 'admin.php?page=subin-email-log&s=' . rawurlencode( (string) absint( $event->id ) ) ) : admin_url( 'admin.php?page=subin-email-log&subin_status=' . rawurlencode( $status ) );
		$issue_action_url   = admin_url( 'admin.php?page=subin-settings&subin_settings_tab=sending' );
		$issue_action_label = __( 'Open Sending settings', 'submission-inbox' );
		$issue              = ( $event && ! empty( $event->error_message ) ) ? $this->error_classifier->classify( (string) $event->error_message ) : array();

		if ( ! empty( $issue ) && 'form_notification_settings' === ( $issue['action_type'] ?? '' ) && '' !== $form_settings ) {
			$issue_action_url   = $form_settings;
			$issue_action_label = __( 'Check form settings', 'submission-inbox' );
		}
		?>
		<div class="subin-email-summary__actions">
			<?php if ( 'failed' === $status ) : ?>
				<a class="subin-action-chip" href="<?php echo esc_url( $email_log_url ); ?>"><?php esc_html_e( 'View Email Log', 'submission-inbox' ); ?></a>
				<a class="subin-action-chip" href="<?php echo esc_url( $issue_action_url ); ?>"><?php echo esc_html( $issue_action_label ); ?></a>
				<?php $this->render_status_action_button( absint( $lead->id ), 'resend_notification', __( 'Retry notification', 'submission-inbox' ), 'subin-action-chip subin-action-chip-warning' ); ?>
			<?php else : ?>
				<a class="subin-action-chip" href="<?php echo esc_url( $form_settings ); ?>"><?php esc_html_e( 'Check form settings', 'submission-inbox' ); ?></a>
			<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * Render combined email activity timeline.
	 *
	 * @param object            $lead Lead row.
	 * @param array<int,object> $events Events.
	 * @return void
	 */
	private function render_email_activity( $lead, array $events ) {
		if ( empty( $events ) ) {
			SUBIN_View::empty_state( __( 'No email activity', 'submission-inbox' ), __( 'No related WordPress email events were found for this lead.', 'submission-inbox' ) );
			return;
		}

		$auto_reply = $this->auto_reply_details_for_lead( $lead, $events );
		?>
		<div class="subin-email-activity__timeline">
			<?php foreach ( $events as $event ) : ?>
				<?php
				$event_status   = sanitize_key( $event->status ?? 'unknown' );
				$event_source   = sanitize_key( $event->source ?? '' );
				$is_auto_reply  = 'submission_inbox_auto_reply' === $event_source;
				$event_issue    = ( 'failed' === $event_status && ! empty( $event->error_message ) ) ? $this->error_classifier->classify( (string) $event->error_message ) : array();
				$recipient_info = $is_auto_reply ? '' : $this->notification_recipient_details_for_lead( $lead )['source'];
				?>
				<article class="subin-email-activity__event subin-email-activity__event--<?php echo esc_attr( $this->badge_type_for_status( $event_status ) ); ?>">
					<div class="subin-email-activity__marker" aria-hidden="true"></div>
					<div class="subin-email-activity__content">
						<div class="subin-email-activity__head">
							<div>
								<span class="subin-status-label"><?php echo esc_html( $this->mail_event_source_label( $event->source ?? '' ) ); ?></span>
								<h3><?php echo esc_html( $event->subject ? $event->subject : __( 'Email event', 'submission-inbox' ) ); ?></h3>
							</div>
							<?php $this->status_badge( $event_status, $this->email_status_label( $event_status ) ); ?>
						</div>
						<div class="subin-email-activity__meta">
							<div>
								<span><?php esc_html_e( 'To', 'submission-inbox' ); ?></span>
								<strong><?php echo esc_html( $event->to_email ? $event->to_email : __( 'Unknown', 'submission-inbox' ) ); ?></strong>
							</div>
							<div>
								<span><?php esc_html_e( 'Date', 'submission-inbox' ); ?></span>
								<strong><?php echo esc_html( $this->format_date( $event->created_at ) ); ?></strong>
							</div>
							<?php if ( $is_auto_reply && '' !== $auto_reply['template_name'] ) : ?>
								<div>
									<span><?php esc_html_e( 'Template', 'submission-inbox' ); ?></span>
									<strong><?php echo esc_html( $auto_reply['template_name'] ); ?></strong>
								</div>
							<?php endif; ?>
							<?php if ( '' !== $recipient_info ) : ?>
								<div>
									<span><?php esc_html_e( 'Recipient source', 'submission-inbox' ); ?></span>
									<strong><?php echo esc_html( $recipient_info ); ?></strong>
								</div>
							<?php endif; ?>
						</div>
						<?php if ( ! empty( $event->error_message ) ) : ?>
							<div class="subin-email-activity__note">
								<?php if ( ! empty( $event_issue ) ) : ?>
									<div class="subin-email-activity__guidance-row">
										<span><?php esc_html_e( 'Issue', 'submission-inbox' ); ?></span>
										<strong><?php echo esc_html( $event_issue['title'] ); ?></strong>
									</div>
									<div class="subin-email-activity__guidance-row">
										<span><?php esc_html_e( 'Explanation', 'submission-inbox' ); ?></span>
										<strong><?php echo esc_html( $event_issue['explanation'] ); ?></strong>
									</div>
									<div class="subin-email-activity__guidance-row">
										<span><?php esc_html_e( 'Recommended action', 'submission-inbox' ); ?></span>
										<strong><?php echo esc_html( $event_issue['recommended_action'] ); ?></strong>
									</div>
								<?php endif; ?>
								<div class="subin-email-activity__guidance-row">
									<span><?php esc_html_e( 'Technical error', 'submission-inbox' ); ?></span>
									<strong><?php echo esc_html( ! empty( $event_issue['technical_error'] ) ? $event_issue['technical_error'] : $this->error_classifier->sanitize_technical_error( (string) $event->error_message ) ); ?></strong>
								</div>
							</div>
						<?php endif; ?>
						<div class="subin-status-links">
							<a href="<?php echo esc_url( admin_url( 'admin.php?page=subin-email-log&s=' . rawurlencode( (string) absint( $event->id ) ) ) ); ?>"><?php esc_html_e( 'View related event', 'submission-inbox' ); ?></a>
						</div>
					</div>
				</article>
			<?php endforeach; ?>
		</div>
		<?php
	}

	/**
	 * Get an external entry id from saved hidden metadata fields.
	 *
	 * @param array<int,object> $fields Saved fields.
	 * @return string
	 */
	private function external_entry_id_from_fields( array $fields, $field_key ) {
		$field_key = sanitize_key( $field_key );
		foreach ( $fields as $field ) {
			if ( $field_key === sanitize_key( $field->field_key ?? '' ) ) {
				return sanitize_text_field( (string) ( $field->field_value ?? '' ) );
			}
		}

		return '';
	}

	/**
	 * Render email notification status card.
	 *
	 * @param object            $lead Lead row.
	 * @param array<int,object> $events Events.
	 * @return void
	 */
	private function render_notification_card( $lead, array $events ) {
		$status          = sanitize_key( $lead->email_status ?? 'unknown' );
		$event           = $this->latest_admin_notification_event( $events );
		$form_settings   = $this->form_settings_url_for_lead( $lead );
		$card_class      = in_array( $status, array( 'failed', 'no_email_generated' ), true ) ? ( 'failed' === $status ? ' subin-notification-card--failed' : ' subin-notification-card--warning' ) : '';
		$email_log_url   = $event ? admin_url( 'admin.php?page=subin-email-log&s=' . rawurlencode( (string) absint( $event->id ) ) ) : admin_url( 'admin.php?page=subin-email-log&subin_status=' . rawurlencode( $status ) );
		$message         = $this->notification_status_message( $status );
		$issue           = ( $event && ! empty( $event->error_message ) ) ? $this->error_classifier->classify( (string) $event->error_message ) : array();
		$issue_action_url = admin_url( 'admin.php?page=subin-settings&subin_settings_tab=sending' );
		$issue_action_label = __( 'Open Sending settings', 'submission-inbox' );
		$recipient_details = $this->notification_recipient_details_for_lead( $lead );

		if ( ! empty( $issue ) && 'form_notification_settings' === ( $issue['action_type'] ?? '' ) && '' !== $form_settings ) {
			$issue_action_url   = $form_settings;
			$issue_action_label = __( 'Check form settings', 'submission-inbox' );
		}
		?>
		<section class="subin-notification-card<?php echo esc_attr( $card_class ); ?>">
			<div class="subin-notification-card__head">
				<div>
					<h2><?php esc_html_e( 'Email notification', 'submission-inbox' ); ?></h2>
					<?php SUBIN_View::help_tooltip( __( 'This explains what happened when WordPress tried to send the notification email.', 'submission-inbox' ) ); ?>
					<p><?php echo esc_html( $message ); ?></p>
				</div>
				<?php $this->status_badge( $status, $this->email_status_label( $status ) ); ?>
			</div>
			<?php if ( $event && ( ! empty( $event->to_email ) || ! empty( $event->subject ) || ! empty( $event->error_message ) ) ) : ?>
				<div class="subin-notification-card__details">
					<?php if ( ! empty( $event->to_email ) ) : ?>
						<div class="subin-detail-item">
							<span><?php esc_html_e( 'Recipient', 'submission-inbox' ); ?></span>
							<strong><?php echo esc_html( $event->to_email ); ?></strong>
						</div>
					<?php endif; ?>
					<?php if ( '' !== $recipient_details['source'] ) : ?>
						<div class="subin-detail-item">
							<span><?php esc_html_e( 'Recipient source', 'submission-inbox' ); ?></span>
							<strong><?php echo esc_html( $recipient_details['source'] ); ?></strong>
						</div>
					<?php endif; ?>
					<?php if ( ! empty( $event->subject ) ) : ?>
						<div class="subin-detail-item">
							<span><?php esc_html_e( 'Subject', 'submission-inbox' ); ?></span>
							<strong><?php echo esc_html( $event->subject ); ?></strong>
						</div>
					<?php endif; ?>
					<?php if ( ! empty( $event->error_message ) ) : ?>
						<?php if ( ! empty( $issue ) ) : ?>
							<div class="subin-detail-item">
								<span><?php esc_html_e( 'Issue', 'submission-inbox' ); ?></span>
								<strong><?php echo esc_html( $issue['title'] ); ?></strong>
							</div>
							<div class="subin-detail-item subin-detail-message">
								<span><?php esc_html_e( 'Explanation', 'submission-inbox' ); ?></span>
								<strong><?php echo esc_html( $issue['explanation'] ); ?></strong>
							</div>
							<div class="subin-detail-item subin-detail-message">
								<span><?php esc_html_e( 'Recommended action', 'submission-inbox' ); ?></span>
								<strong><?php echo esc_html( $issue['recommended_action'] ); ?></strong>
							</div>
						<?php endif; ?>
						<div class="subin-detail-item subin-detail-message">
							<span><?php esc_html_e( 'Technical error', 'submission-inbox' ); ?></span>
							<strong><?php echo esc_html( ! empty( $issue['technical_error'] ) ? $issue['technical_error'] : $this->error_classifier->sanitize_technical_error( (string) $event->error_message ) ); ?></strong>
						</div>
					<?php endif; ?>
				</div>
			<?php endif; ?>
			<?php if ( 'failed' === $status || ( 'no_email_generated' === $status && '' !== $form_settings ) ) : ?>
				<div class="subin-notification-card__actions">
					<?php if ( 'failed' === $status ) : ?>
						<a class="subin-action-chip" href="<?php echo esc_url( $email_log_url ); ?>"><?php esc_html_e( 'View Email Log', 'submission-inbox' ); ?></a>
						<a class="subin-action-chip" href="<?php echo esc_url( $issue_action_url ); ?>"><?php echo esc_html( $issue_action_label ); ?></a>
						<?php $this->render_status_action_button( absint( $lead->id ), 'resend_notification', __( 'Retry notification', 'submission-inbox' ), 'subin-action-chip subin-action-chip-warning' ); ?>
						<?php SUBIN_View::help_tooltip( __( 'Attempts to send the notification email again. The lead is already saved.', 'submission-inbox' ) ); ?>
					<?php else : ?>
						<a class="subin-action-chip" href="<?php echo esc_url( $form_settings ); ?>"><?php esc_html_e( 'Check form settings', 'submission-inbox' ); ?></a>
					<?php endif; ?>
				</div>
			<?php endif; ?>
		</section>
		<?php
	}

	/**
	 * Render auto-reply summary for a lead.
	 *
	 * @param object            $lead Lead row.
	 * @param array<int,object> $events Related mail events.
	 * @return void
	 */
	private function render_auto_reply_summary( $lead, array $events ) {
		$auto_reply_event = null;
		foreach ( $events as $event ) {
			if ( 'submission_inbox_auto_reply' === sanitize_key( $event->source ?? '' ) ) {
				$auto_reply_event = $event;
				break;
			}
		}

		$template_name = '';
		$recipient     = '';
		$status        = 'no_email_generated';
		$reason        = __( 'Auto-reply disabled.', 'submission-inbox' );
		$form          = ( 'submission_inbox_form' === sanitize_key( $lead->provider ?? '' ) && ! empty( $lead->form_id ) ) ? $this->forms->get( absint( $lead->form_id ) ) : null;

		if ( $form ) {
			$settings   = $this->forms->decode_settings( $form );
			$config     = is_array( $settings['auto_reply'] ?? null ) ? $settings['auto_reply'] : array();
			$template_id = absint( $config['template_id'] ?? 0 );
			$template   = $template_id > 0 ? $this->auto_reply_templates->get( $template_id ) : null;
			if ( $template ) {
				$template_name = sanitize_text_field( $template['name'] ?? '' );
			}
			if ( ! empty( $config['enabled'] ) ) {
				$reason = __( 'No auto-reply email event was found for this lead.', 'submission-inbox' );
			}
		}

		if ( $auto_reply_event ) {
			$recipient = sanitize_text_field( $auto_reply_event->to_email ?? '' );
			$status    = sanitize_key( $auto_reply_event->status ?? 'unknown' );
			$reason    = $this->error_classifier->sanitize_technical_error( (string) ( $auto_reply_event->error_message ?? '' ) );
		}

		?>
		<div class="subin-auto-reply-card__content">
			<div class="subin-auto-reply-card__status">
				<span class="subin-status-label"><?php esc_html_e( 'Visitor auto-reply', 'submission-inbox' ); ?></span>
				<?php $this->status_badge( $status, $this->email_status_label( $status ) ); ?>
				<?php if ( ! $auto_reply_event ) : ?>
					<p><?php esc_html_e( 'No visitor auto-reply was generated for this lead.', 'submission-inbox' ); ?></p>
				<?php elseif ( '' !== $reason ) : ?>
					<p><?php echo esc_html( $reason ); ?></p>
				<?php endif; ?>
			</div>
			<div class="subin-source-card__grid">
				<div class="subin-detail-item">
					<span><?php esc_html_e( 'Template', 'submission-inbox' ); ?></span>
					<strong><?php echo esc_html( '' !== $template_name ? $template_name : __( 'Unknown', 'submission-inbox' ) ); ?></strong>
				</div>
				<div class="subin-detail-item">
					<span><?php esc_html_e( 'Recipient', 'submission-inbox' ); ?></span>
					<strong><?php echo esc_html( '' !== $recipient ? $recipient : __( 'Unknown', 'submission-inbox' ) ); ?></strong>
				</div>
			</div>
			<?php if ( $auto_reply_event ) : ?>
				<div class="subin-status-links">
					<a href="<?php echo esc_url( admin_url( 'admin.php?page=subin-email-log&s=' . rawurlencode( (string) absint( $auto_reply_event->id ) ) ) ); ?>"><?php esc_html_e( 'View related event', 'submission-inbox' ); ?></a>
				</div>
			<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * Render related email events.
	 *
	 * @param array<int,object> $events Events.
	 * @return void
	 */
	private function render_email_events( array $events ) {
		if ( empty( $events ) ) {
			echo '<p>' . esc_html__( 'No related email events.', 'submission-inbox' ) . '</p>';
			return;
		}
		?>
		<div class="subin-email-events__list">
			<?php foreach ( $events as $event ) : ?>
				<?php
				$event_status = sanitize_key( $event->status ?? 'unknown' );
				$event_issue  = ( 'failed' === $event_status && ! empty( $event->error_message ) ) ? $this->error_classifier->classify( (string) $event->error_message ) : array();
				?>
				<article class="subin-email-event-card">
					<div class="subin-email-event-card__head">
						<div>
							<span class="subin-status-label"><?php echo esc_html( $this->mail_event_source_label( $event->source ?? '' ) ); ?></span>
							<h3><?php echo esc_html( $event->subject ? $event->subject : __( 'Email event', 'submission-inbox' ) ); ?></h3>
						</div>
						<?php $this->status_badge( $event->status, $this->email_status_label( $event->status ) ); ?>
					</div>
					<div class="subin-source-card__grid">
						<div class="subin-detail-item">
							<span><?php esc_html_e( 'To', 'submission-inbox' ); ?></span>
							<strong><?php echo esc_html( $event->to_email ); ?></strong>
						</div>
						<div class="subin-detail-item">
							<span><?php esc_html_e( 'Date', 'submission-inbox' ); ?></span>
							<strong><?php echo esc_html( $this->format_date( $event->created_at ) ); ?></strong>
						</div>
					</div>
					<?php if ( ! empty( $event->error_message ) ) : ?>
						<?php if ( ! empty( $event_issue ) ) : ?>
							<div class="subin-detail-item">
								<span><?php esc_html_e( 'Issue', 'submission-inbox' ); ?></span>
								<strong><?php echo esc_html( $event_issue['title'] ); ?></strong>
							</div>
						<?php endif; ?>
						<div class="subin-detail-item subin-detail-message">
							<span><?php esc_html_e( 'Technical error', 'submission-inbox' ); ?></span>
							<strong><?php echo esc_html( ! empty( $event_issue['technical_error'] ) ? $event_issue['technical_error'] : $this->error_classifier->sanitize_technical_error( (string) $event->error_message ) ); ?></strong>
						</div>
					<?php endif; ?>
				</article>
			<?php endforeach; ?>
		</div>
		<?php
	}

	/**
	 * Handle POST actions.
	 *
	 * @return void
	 */
	private function maybe_handle_action() {
		$request_method = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ?? '' ) );
		if ( 'POST' !== strtoupper( $request_method ) ) {
			return;
		}

		$action  = sanitize_key( wp_unslash( $_POST['subin_lead_action'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified before the action is executed.
		$lead_id = absint( wp_unslash( $_POST['lead_id'] ?? 0 ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified before the action is executed.

		if ( 'mark_all_seen' === $action ) {
			if ( ! isset( $_POST['subin_lead_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['subin_lead_nonce'] ) ), 'subin_mark_all_seen' ) ) {
				add_settings_error(
					'subin_messages',
					'subin_security_check_failed',
					__( 'Security check failed. Please try again.', 'submission-inbox' ),
					'error'
				);
				return;
			}

			$result = $this->leads->update_status_bulk( \SUBIN\Leads\LeadRepository::STATUS_NEW, \SUBIN\Leads\LeadRepository::STATUS_SEEN );
			$this->safe_admin_redirect(
				add_query_arg(
					array(
						'page'   => SUBIN_AdminMenu::MENU_SLUG,
						'notice' => false === $result ? 'all_leads_mark_seen_failed' : 'all_leads_mark_seen',
					),
					admin_url( 'admin.php' )
				)
			);
		}

		if ( ! in_array( $action, array( 'new', 'seen', 'archived', 'delete', 'resend_notification', 'update_workflow', 'add_note', 'update_note', 'delete_note' ), true ) || $lead_id <= 0 ) {
			return;
		}

		if ( ! isset( $_POST['subin_lead_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['subin_lead_nonce'] ) ), 'subin_update_lead_' . $lead_id ) ) {
			add_settings_error(
				'subin_messages',
				'subin_security_check_failed',
				__( 'Security check failed. Please try again.', 'submission-inbox' ),
				'error'
			);
			return;
		}

		if ( 'resend_notification' === $action ) {
			$notice = $this->queue_notification_retry( $lead_id ) ? 'notification_queued' : 'notification_failed';
			$this->safe_admin_redirect( $this->detail_url( $lead_id, true, $notice ) );
		}

		if ( 'update_workflow' === $action ) {
			$updated = $this->workflow->update_workflow(
				$lead_id,
				array(
					'workflow_status'  => sanitize_key( wp_unslash( $_POST['workflow_status'] ?? 'open' ) ),
					'priority'         => sanitize_key( wp_unslash( $_POST['priority'] ?? 'normal' ) ),
					'assigned_user_id' => absint( wp_unslash( $_POST['assigned_user_id'] ?? 0 ) ),
					'follow_up_at'     => sanitize_text_field( wp_unslash( $_POST['follow_up_at'] ?? '' ) ),
				),
				get_current_user_id()
			);
			$this->safe_admin_redirect( $this->detail_url( $lead_id, true, $updated ? 'workflow_updated' : 'workflow_failed' ) );
		}

		if ( 'add_note' === $action ) {
			$note_id = $this->activity->add_note( $lead_id, wp_unslash( $_POST['lead_note'] ?? '' ), get_current_user_id() ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Repository sanitizes note text.
			$this->safe_admin_redirect( $this->detail_url( $lead_id, true, $note_id > 0 ? 'note_added' : 'note_failed' ) );
		}

		if ( 'update_note' === $action ) {
			$updated = $this->activity->update_note(
				absint( wp_unslash( $_POST['note_id'] ?? 0 ) ),
				$lead_id,
				wp_unslash( $_POST['lead_note'] ?? '' ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Repository sanitizes note text.
				get_current_user_id()
			);
			$this->safe_admin_redirect( $this->detail_url( $lead_id, true, $updated ? 'note_updated' : 'note_update_failed' ) );
		}

		if ( 'delete_note' === $action ) {
			$deleted = $this->activity->delete_note(
				absint( wp_unslash( $_POST['note_id'] ?? 0 ) ),
				$lead_id,
				get_current_user_id()
			);
			$this->safe_admin_redirect( $this->detail_url( $lead_id, true, $deleted ? 'note_deleted' : 'note_delete_failed' ) );
		}

		if ( 'delete' === $action ) {
			$this->activity->delete_by_lead_id( $lead_id );
			$this->fields->delete_by_lead_id( $lead_id );
			$notice = $this->leads->delete( $lead_id ) ? 'lead_deleted' : 'lead_delete_failed';
			$this->safe_admin_redirect(
				add_query_arg(
					array(
						'page'   => SUBIN_AdminMenu::MENU_SLUG,
						'notice' => $notice,
					),
					admin_url( 'admin.php' )
				)
			);
		}

		$this->leads->update_status( $lead_id, $action );
		$this->activity->add_activity(
			$lead_id,
			'lead_status_updated',
			sprintf(
				/* translators: %s: lead visibility status label. */
				__( 'Lead marked as %s.', 'submission-inbox' ),
				$this->lead_status_label( $action )
			),
			array( 'status' => $action ),
			get_current_user_id()
		);
		$this->safe_admin_redirect( $this->detail_url( $lead_id, true, $action ) );
	}

	/**
	 * Show list notice after list actions.
	 *
	 * @return void
	 */
	private function maybe_add_list_notice() {
		$notice = SUBIN_Request::get_key( 'notice' );

		if ( ! in_array( $notice, array( 'lead_deleted', 'lead_delete_failed', 'all_leads_mark_seen', 'all_leads_mark_seen_failed' ), true ) ) {
			return;
		}

		$messages = array(
			'lead_deleted'               => array( 'updated', __( 'Lead deleted.', 'submission-inbox' ) ),
			'lead_delete_failed'         => array( 'error', __( 'Lead could not be deleted.', 'submission-inbox' ) ),
			'all_leads_mark_seen'        => array( 'updated', __( 'Unseen leads marked as seen.', 'submission-inbox' ) ),
			'all_leads_mark_seen_failed' => array( 'error', __( 'Unseen leads could not be marked as seen.', 'submission-inbox' ) ),
		);

		add_settings_error(
			'subin_messages',
			'subin_lead_list_action',
			$messages[ $notice ][1],
			$messages[ $notice ][0]
		);
	}

	/**
	 * Show lead action notice after redirect.
	 *
	 * @return void
	 */
	private function maybe_add_detail_notice() {
		$notice = SUBIN_Request::get_key( 'subin_notice' );

		if ( ! in_array( $notice, array( 'new', 'seen', 'archived', 'notification_sent', 'notification_queued', 'notification_failed', 'workflow_updated', 'workflow_failed', 'note_added', 'note_failed', 'note_updated', 'note_update_failed', 'note_deleted', 'note_delete_failed' ), true ) ) {
			return;
		}

		$messages = array(
			'new'                 => array( 'updated', __( 'Lead marked as new.', 'submission-inbox' ) ),
			'seen'                => array( 'updated', __( 'Lead marked as seen.', 'submission-inbox' ) ),
			'archived'            => array( 'updated', __( 'Lead archived.', 'submission-inbox' ) ),
			'notification_sent'   => array( 'updated', __( 'Notification was sent by WordPress.', 'submission-inbox' ) ),
			'notification_queued' => array( 'updated', __( 'Notification retry queued.', 'submission-inbox' ) ),
			'notification_failed' => array( 'error', __( 'Notification could not be sent.', 'submission-inbox' ) ),
			'workflow_updated'    => array( 'updated', __( 'Workflow saved.', 'submission-inbox' ) ),
			'workflow_failed'     => array( 'error', __( 'Workflow could not be saved.', 'submission-inbox' ) ),
			'note_added'          => array( 'updated', __( 'Note added.', 'submission-inbox' ) ),
			'note_failed'         => array( 'error', __( 'Note could not be added.', 'submission-inbox' ) ),
			'note_updated'        => array( 'updated', __( 'Note updated.', 'submission-inbox' ) ),
			'note_update_failed'  => array( 'error', __( 'Note could not be updated.', 'submission-inbox' ) ),
			'note_deleted'        => array( 'updated', __( 'Note deleted.', 'submission-inbox' ) ),
			'note_delete_failed'  => array( 'error', __( 'Note could not be deleted.', 'submission-inbox' ) ),
		);

		add_settings_error(
			'subin_messages',
			'subin_lead_updated',
			$messages[ $notice ][1],
			$messages[ $notice ][0]
		);

	}

	/**
	 * Render a status action button.
	 *
	 * @param int    $lead_id Lead id.
	 * @param string $action Action.
	 * @param string $label Button label.
	 * @return void
	 */
	private function render_status_action_button( $lead_id, $action, $label, $button_class = '', $confirm = '' ) {
		$button_class = '' !== $button_class ? $button_class : 'button button-secondary';
		?>
		<form method="post" action="">
			<input type="hidden" name="subin_lead_action" value="<?php echo esc_attr( $action ); ?>" />
			<input type="hidden" name="lead_id" value="<?php echo esc_attr( (string) $lead_id ); ?>" />
			<?php wp_nonce_field( 'subin_update_lead_' . $lead_id, 'subin_lead_nonce' ); ?>
			<button type="submit" class="<?php echo esc_attr( $button_class ); ?>"<?php echo '' !== $confirm ? ' onclick="return confirm(\'' . esc_js( $confirm ) . '\');"' : ''; ?>><?php echo esc_html( $label ); ?></button>
		</form>
		<?php
	}

	/**
	 * Queue a saved lead notification retry.
	 *
	 * @param int $lead_id Lead id.
	 * @return bool
	 */
	private function queue_notification_retry( $lead_id ) {
		$lead_id = absint( $lead_id );
		$lead = $this->leads->get( $lead_id );
		if ( ! $lead ) {
			return false;
		}

		$args = array( $lead_id );
		if ( ! wp_next_scheduled( \SUBIN\Forms\FormSubmissionHandler::NOTIFICATION_HOOK, $args ) ) {
			wp_schedule_single_event( time(), \SUBIN\Forms\FormSubmissionHandler::NOTIFICATION_HOOK, $args );
		}

		$this->leads->update_email_status( $lead_id, \SUBIN\Leads\LeadRepository::EMAIL_STATUS_UNKNOWN );
		return true;
	}

	/**
	 * Get notification recipient.
	 *
	 * @return string
	 */
	private function notification_recipient() {
		$settings  = $this->settings->all();
		$recipient = sanitize_email( $settings['notification_recipient_email'] ?? '' );
		if ( is_email( $recipient ) ) {
			return $recipient;
		}

		return sanitize_email( get_option( 'admin_email' ) );
	}

	/**
	 * Build resend notification body.
	 *
	 * @param object            $lead Lead.
	 * @param array<int,object> $fields Fields.
	 * @return string
	 */
	private function notification_body( $lead, array $fields ) {
		$rows = '';
		foreach ( $fields as $field ) {
			if ( ! empty( $field->is_sensitive ) || '' === trim( (string) $field->field_value ) ) {
				continue;
			}

			$rows .= '<tr><th align="left" style="padding:6px 10px;border-bottom:1px solid #eee;">' . esc_html( $field->field_label ) . '</th><td style="padding:6px 10px;border-bottom:1px solid #eee;">' . nl2br( esc_html( $field->field_value ) ) . '</td></tr>';
		}

		if ( '' === $rows ) {
			$rows = '<tr><td colspan="2" style="padding:6px 10px;border-bottom:1px solid #eee;">' . esc_html__( 'No saved fields.', 'submission-inbox' ) . '</td></tr>';
		}

		$detail_url = $this->detail_url( absint( $lead->id ) );

		/* translators: %s: form name. */
		return '<h2>' . esc_html( sprintf( __( 'New lead from %s', 'submission-inbox' ), $lead->form_name ) ) . '</h2>'
			. '<p><strong>' . esc_html__( 'Submitted at:', 'submission-inbox' ) . '</strong> ' . esc_html( $this->format_date( $lead->submitted_at ) ) . '</p>'
			. '<p><strong>' . esc_html__( 'Source:', 'submission-inbox' ) . '</strong> ' . esc_html( $this->provider_label( $lead->provider ) ) . '</p>'
			. '<table cellspacing="0" cellpadding="0" style="border-collapse:collapse;width:100%;max-width:680px;">' . $rows . '</table>'
			. '<p><a href="' . esc_url( $detail_url ) . '">' . esc_html__( 'View lead in WordPress', 'submission-inbox' ) . '</a></p>'
			. '<p>' . esc_html__( 'Sent by InboxMend.', 'submission-inbox' ) . '</p>';
	}

	/**
	 * Export URL for current filters.
	 *
	 * @param array<string,mixed> $filters Filters.
	 * @return string
	 */
	private function export_url( array $filters ) {
		return wp_nonce_url(
			add_query_arg( array_merge( $this->url_args_from_filters( $filters ), array( 'subin_export' => 'leads' ) ), admin_url( 'admin.php' ) ),
			'subin_export_leads',
			'subin_export_nonce'
		);
	}

	/**
	 * Export filtered leads when requested.
	 *
	 * @param array<string,mixed> $filters Filters.
	 * @return void
	 */
	private function maybe_export( array $filters ) {
		if ( 'leads' !== sanitize_key( wp_unslash( $_GET['subin_export'] ?? '' ) ) ) {
			return;
		}

		if ( ! isset( $_GET['subin_export_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['subin_export_nonce'] ) ), 'subin_export_leads' ) ) {
			add_settings_error( 'subin_messages', 'subin_export_invalid', __( 'Security check failed. Please try again.', 'submission-inbox' ), 'error' );
			return;
		}

		$limit           = 5000;
		$leads           = $this->leads->get_leads_for_export( $filters, $limit );
		$field_summaries = $this->fields->get_non_sensitive_summaries_by_lead_ids( wp_list_pluck( $leads, 'id' ) );
		$rows            = array(
			array(
				'Lead ID',
				'Status',
				'Workflow Status',
				'Priority',
				'Assigned User',
				'Follow-up At',
				'Email Health',
				'Source',
				'Form ID',
				'Form Name',
				'Customer Name',
				'Customer Email',
				'Customer Phone',
				'Message Preview',
				'Source URL',
				'Referrer',
				'Submitted At',
				'Created At',
				'Fields Summary',
			),
		);

		foreach ( $leads as $lead ) {
			$rows[] = array(
				$lead->id,
				$this->lead_status_label( $lead->status ),
				$this->workflow_status_label( $lead->workflow_status ?? 'open' ),
				$this->priority_label( $lead->priority ?? 'normal' ),
				$this->assignee_label( $lead->assigned_user_id ?? 0 ),
				$lead->follow_up_at ?? '',
				$this->email_status_label( $lead->email_status ),
				$this->provider_label( $lead->provider ),
				$lead->form_id,
				$lead->form_name,
				$lead->customer_name,
				$lead->customer_email,
				$lead->customer_phone,
				$lead->message_preview,
				$lead->source_url,
				$lead->referrer,
				$lead->submitted_at,
				$lead->created_at,
				$field_summaries[ absint( $lead->id ) ] ?? '',
			);
		}

		if ( count( $leads ) >= $limit ) {
			$rows[] = array( 'Export limited to 5000 rows.' );
		}

		$exporter = new \SUBIN\Export\CsvExporter();
		$exporter->export_leads( $rows, 'submission-inbox-leads-' . gmdate( 'Y-m-d' ) . '.csv' );
	}

	/**
	 * Get request filters.
	 *
	 * @return array<string,string>
	 */
	private function get_filters_from_request() {
		$status       = SUBIN_Request::get_key( 'subin_status' );
		$email_status = SUBIN_Request::get_key( 'subin_email_status' );
		$provider     = SUBIN_Request::get_key( 'subin_provider' );
		$form_filter  = SUBIN_Request::get_text( 'subin_form_id' );
		$attention    = SUBIN_Request::get_key( 'subin_attention' );
		$workflow_status = SUBIN_Request::get_key( 'subin_workflow_status' );
		$priority     = SUBIN_Request::get_key( 'subin_priority' );
		$assigned_user_id = SUBIN_Request::get_text( 'subin_assigned_user_id' );
		$overdue_follow_up = SUBIN_Request::get_key( 'subin_overdue_follow_up' );
		$form_provider = '';
		$form_id       = '';

		if ( '' !== $form_filter && false !== strpos( $form_filter, '|' ) ) {
			$form_parts    = explode( '|', $form_filter, 2 );
			$form_provider = sanitize_key( $form_parts[0] ?? '' );
			$form_id       = sanitize_text_field( $form_parts[1] ?? '' );
		} elseif ( '' !== $form_filter ) {
			$form_id = $form_filter;
		}

		return array(
			'status'       => in_array( $status, array( 'new', 'seen', 'archived' ), true ) ? $status : '',
			'email_status' => in_array( $email_status, array( 'sent', 'failed', 'no_email_generated', 'unknown' ), true ) ? $email_status : '',
			'needs_attention' => '1' === $attention ? '1' : '',
			'provider'     => $this->providers->sanitize( $provider ),
			'form_provider' => $this->providers->sanitize( $form_provider ),
			'form_id'      => $form_id,
			'form_filter'  => $form_filter,
			'workflow_status' => array_key_exists( $workflow_status, $this->workflow->workflow_statuses() ) ? $workflow_status : '',
			'priority'     => array_key_exists( $priority, $this->workflow->priorities() ) ? $priority : '',
			'assigned_user_id' => ( '' === $assigned_user_id || '0' === $assigned_user_id || absint( $assigned_user_id ) > 0 ) ? $assigned_user_id : '',
			'overdue_follow_up' => '1' === $overdue_follow_up ? '1' : '',
			'form'         => SUBIN_Request::get_text( 'subin_form' ),
			'date_from'    => $this->sanitize_date( SUBIN_Request::get_text( 'subin_date_from' ) ),
			'date_to'      => $this->sanitize_date( SUBIN_Request::get_text( 'subin_date_to' ) ),
			'search'       => SUBIN_Request::get_text( 's' ),
		);
	}

	/**
	 * Sanitize date input.
	 *
	 * @param mixed $date Date.
	 * @return string
	 */
	private function sanitize_date( $date ) {
		$date = sanitize_text_field( wp_unslash( $date ) );
		if ( 1 !== preg_match( '/^\d{4}-\d{2}-\d{2}$/', $date ) ) {
			return '';
		}

		$parts = explode( '-', $date );

		return checkdate( absint( $parts[1] ), absint( $parts[2] ), absint( $parts[0] ) ) ? $date : '';
	}

	/**
	 * Check active filters.
	 *
	 * @param array<string,mixed> $filters Filters.
	 * @return bool
	 */
	private function has_active_filters( array $filters ) {
		return '' !== implode( '', array_map( 'strval', $filters ) );
	}

	/**
	 * Build URL args from filters.
	 *
	 * @param array<string,mixed> $filters Filters.
	 * @return array<string,string>
	 */
	private function url_args_from_filters( array $filters ) {
		return array_filter(
			array(
				'page'             => SUBIN_AdminMenu::MENU_SLUG,
				'subin_status'       => $filters['status'] ?? '',
				'subin_email_status' => $filters['email_status'] ?? '',
				'subin_attention'    => $filters['needs_attention'] ?? '',
				'subin_provider'     => $filters['provider'] ?? '',
				'subin_form_id'      => $filters['form_filter'] ?? '',
				'subin_workflow_status' => $filters['workflow_status'] ?? '',
				'subin_priority'     => $filters['priority'] ?? '',
				'subin_assigned_user_id' => $filters['assigned_user_id'] ?? '',
				'subin_overdue_follow_up' => $filters['overdue_follow_up'] ?? '',
				'subin_form'         => $filters['form'] ?? '',
				'subin_date_from'    => $filters['date_from'] ?? '',
				'subin_date_to'      => $filters['date_to'] ?? '',
				's'                => $filters['search'] ?? '',
			)
		);
	}

	/**
	 * Render status badge.
	 *
	 * @param string $status Status.
	 * @param string $label Label.
	 * @return void
	 */
	private function status_badge( $status, $label ) {
		SUBIN_View::badge( $label, $this->badge_type_for_status( $status ) );
	}

	/**
	 * Badge type for status.
	 *
	 * @param string $status Status.
	 * @return string
	 */
	private function badge_type_for_status( $status ) {
		if ( in_array( $status, array( 'sent', 'detected' ), true ) ) {
			return 'success';
		}

		if ( 'failed' === $status ) {
			return 'danger';
		}

		if ( in_array( $status, array( 'no_email_generated' ), true ) ) {
			return 'warning';
		}

		if ( 'new' === $status ) {
			return 'info';
		}

		return 'muted';
	}

	/**
	 * Summarize related email events for the lead hero.
	 *
	 * @param object            $lead Lead row.
	 * @param array<int,object> $events Events.
	 * @return string
	 */
	private function lead_email_result_summary( $lead, array $events ) {
		$sent      = 0;
		$failed    = 0;
		$no_email  = 0;
		$event_num = count( $events );

		foreach ( $events as $event ) {
			$status = sanitize_key( $event->status ?? '' );
			if ( 'sent' === $status ) {
				++$sent;
			} elseif ( 'failed' === $status ) {
				++$failed;
			} elseif ( 'no_email_generated' === $status ) {
				++$no_email;
			}
		}

		if ( $failed > 0 ) {
			return sprintf(
				/* translators: %d: failed email event count. */
				_n( '%d email event failed', '%d email events failed', $failed, 'submission-inbox' ),
				$failed
			);
		}

		if ( $sent > 0 ) {
			return sprintf(
				/* translators: %d: sent email event count. */
				_n( '%d email event sent by WordPress', '%d email events sent by WordPress', $sent, 'submission-inbox' ),
				$sent
			);
		}

		if ( $no_email > 0 || 'no_email_generated' === sanitize_key( $lead->email_status ?? '' ) ) {
			return __( 'No email generated', 'submission-inbox' );
		}

		if ( $event_num > 0 ) {
			return sprintf(
				/* translators: %d: email event count. */
				_n( '%d related email event', '%d related email events', $event_num, 'submission-inbox' ),
				$event_num
			);
		}

		return $this->email_status_label( sanitize_key( $lead->email_status ?? 'unknown' ) );
	}

	/**
	 * Lead status label.
	 *
	 * @param string $status Status.
	 * @return string
	 */
	private function lead_status_label( $status ) {
		$labels = array(
			'new'      => __( 'Unseen', 'submission-inbox' ),
			'seen'     => __( 'Seen', 'submission-inbox' ),
			'archived' => __( 'Archived', 'submission-inbox' ),
		);

		return $labels[ $status ] ?? __( 'Unknown', 'submission-inbox' );
	}

	/**
	 * Get the configured unread lead freshness window.
	 *
	 * @return int
	 */
	private function get_new_lead_hours() {
		$settings = $this->settings->all();
		$hours    = absint( $settings['new_lead_hours'] ?? 24 );
		$allowed  = array( 6, 12, 24, 48, 72, 168 );

		return in_array( $hours, $allowed, true ) ? $hours : 24;
	}

	/**
	 * Email status label.
	 *
	 * @param string $status Status.
	 * @return string
	 */
	private function email_status_label( $status ) {
		$labels = array(
			'sent'               => __( 'Sent by WordPress', 'submission-inbox' ),
			'failed'             => __( 'Failed', 'submission-inbox' ),
			'no_email_generated' => __( 'No email generated', 'submission-inbox' ),
			'unknown'            => __( 'Unknown', 'submission-inbox' ),
			'pending'            => __( 'Unknown', 'submission-inbox' ),
		);

		return $labels[ $status ] ?? __( 'Unknown', 'submission-inbox' );
	}

	/**
	 * Dashicon class for lead source/provider.
	 *
	 * @param string $provider Provider key.
	 * @return string
	 */
	private function provider_icon( $provider ) {
		return $this->providers->icon( $provider );
	}

	/**
	 * Short explanation for email notification status.
	 *
	 * @param string $status Email status.
	 * @return string
	 */
	private function email_status_explanation( $status ) {
		$messages = array(
			'sent'               => __( 'Lead is saved in Inbox.', 'submission-inbox' ),
			'failed'             => __( 'Lead is saved. Check Email Log for the error.', 'submission-inbox' ),
			'no_email_generated' => __( 'This form submission was saved, but no notification email was created.', 'submission-inbox' ),
			'unknown'            => __( 'Lead is saved, but the notification status is unknown.', 'submission-inbox' ),
			'pending'            => __( 'Lead is saved, but the notification status is unknown.', 'submission-inbox' ),
		);

		return $messages[ $status ] ?? $messages['unknown'];
	}

	/**
	 * Lead detail notification message.
	 *
	 * @param string $status Email status.
	 * @return string
	 */
	private function notification_status_message( $status ) {
		$messages = array(
			'sent'               => __( 'Lead is saved in InboxMend and the notification email was sent by WordPress.', 'submission-inbox' ),
			'failed'             => __( 'Lead is saved in InboxMend, but the admin notification email could not be sent.', 'submission-inbox' ),
			'no_email_generated' => __( 'Lead is saved, but this form did not create a notification email.', 'submission-inbox' ),
			'unknown'            => __( 'Lead is saved, but the notification status is unknown.', 'submission-inbox' ),
			'pending'            => __( 'Lead is saved, but the notification status is unknown.', 'submission-inbox' ),
		);

		return $messages[ $status ] ?? $messages['unknown'];
	}

	/**
	 * Find latest non-auto-reply notification event.
	 *
	 * @param array<int,object> $events Events.
	 * @return object|null
	 */
	private function latest_admin_notification_event( array $events ) {
		foreach ( $events as $event ) {
			if ( 'submission_inbox_auto_reply' !== sanitize_key( $event->source ?? '' ) ) {
				return $event;
			}
		}

		return null;
	}

	/**
	 * Get visitor auto-reply details for summary and activity sections.
	 *
	 * @param object            $lead Lead row.
	 * @param array<int,object> $events Events.
	 * @return array{event:object|null,enabled:bool,template_name:string,recipient:string,status:string}
	 */
	private function auto_reply_details_for_lead( $lead, array $events ) {
		$auto_reply_event = null;
		foreach ( $events as $event ) {
			if ( 'submission_inbox_auto_reply' === sanitize_key( $event->source ?? '' ) ) {
				$auto_reply_event = $event;
				break;
			}
		}

		$template_name = '';
		$enabled       = false;
		$form          = ( 'submission_inbox_form' === sanitize_key( $lead->provider ?? '' ) && ! empty( $lead->form_id ) ) ? $this->forms->get( absint( $lead->form_id ) ) : null;

		if ( $form ) {
			$settings    = $this->forms->decode_settings( $form );
			$config      = is_array( $settings['auto_reply'] ?? null ) ? $settings['auto_reply'] : array();
			$enabled     = ! empty( $config['enabled'] );
			$template_id = absint( $config['template_id'] ?? 0 );
			$template    = $template_id > 0 ? $this->auto_reply_templates->get( $template_id ) : null;
			if ( $template ) {
				$template_name = sanitize_text_field( $template['name'] ?? '' );
			}
		}

		if ( $auto_reply_event ) {
			$enabled = true;
		}

		return array(
			'event'         => $auto_reply_event,
			'enabled'       => $enabled,
			'template_name' => $template_name,
			'recipient'     => $auto_reply_event ? sanitize_text_field( $auto_reply_event->to_email ?? '' ) : '',
			'status'        => $auto_reply_event ? sanitize_key( $auto_reply_event->status ?? 'unknown' ) : 'no_email_generated',
		);
	}

	/**
	 * Form settings URL for a built-in form lead.
	 *
	 * @param object $lead Lead row.
	 * @return string
	 */
	private function form_settings_url_for_lead( $lead ) {
		if ( 'submission_inbox_form' !== sanitize_key( $lead->provider ?? '' ) || absint( $lead->form_id ?? 0 ) <= 0 ) {
			return '';
		}

		return add_query_arg(
			array(
				'page'    => 'submission-inbox-forms',
				'view'    => 'edit',
				'form_id' => absint( $lead->form_id ),
				'tab'     => 'settings',
			),
			admin_url( 'admin.php' )
		);
	}

	/**
	 * Explain where the admin notification recipient came from.
	 *
	 * @param object $lead Lead row.
	 * @return array{email:string,source:string}
	 */
	private function notification_recipient_details_for_lead( $lead ) {
		if ( 'submission_inbox_form' !== sanitize_key( $lead->provider ?? '' ) || absint( $lead->form_id ?? 0 ) <= 0 ) {
			return array(
				'email'  => '',
				'source' => '',
			);
		}

		$form = $this->forms->get( absint( $lead->form_id ) );
		if ( ! $form || empty( $form['notification_enabled'] ) ) {
			return array(
				'email'  => '',
				'source' => __( 'Admin notification is disabled for this form.', 'submission-inbox' ),
			);
		}

		$form_settings = $this->forms->decode_settings( $form );
		$notification  = is_array( $form_settings['notification'] ?? null ) ? $form_settings['notification'] : array();
		$mode          = sanitize_key( $notification['recipient_mode'] ?? '' );
		$form_email    = sanitize_email( $form['notification_email'] ?? '' );

		if ( '' === $mode ) {
			$mode = is_email( $form_email ) ? 'custom' : 'default';
		}

		if ( 'custom' === $mode && is_email( $form_email ) ) {
			return array(
				'email'  => $form_email,
				'source' => __( 'Form settings custom recipient.', 'submission-inbox' ),
			);
		}

		$settings = $this->settings->all();
		$default  = sanitize_email( $settings['notification_recipient_email'] ?? '' );
		if ( is_email( $default ) ) {
			return array(
				'email'  => $default,
				'source' => __( 'Default notification recipient from Settings.', 'submission-inbox' ),
			);
		}

		$admin_email = sanitize_email( get_option( 'admin_email' ) );
		return array(
			'email'  => is_email( $admin_email ) ? $admin_email : '',
			'source' => __( 'WordPress admin email fallback.', 'submission-inbox' ),
		);
	}

	/**
	 * Whether a submitted field is internal/security metadata.
	 *
	 * @param object $field Field row.
	 * @return bool
	 */
	private function is_internal_field( $field ) {
		$key   = strtolower( (string) ( $field->field_key ?? '' ) );
		$label = strtolower( (string) ( $field->field_label ?? '' ) );
		$text  = $key . ' ' . $label;

		foreach ( array( 'captcha', 'recaptcha', 'g-recaptcha', 'nonce', '_wpnonce', 'token', 'csrf', 'honeypot', 'security', 'subin_' ) as $needle ) {
			if ( false !== strpos( $text, $needle ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Check whether a saved field appears to be the submitted message field.
	 *
	 * @param object $field Field row.
	 * @return bool
	 */
	private function field_looks_like_message( $field ) {
		$key   = strtolower( (string) ( $field->field_key ?? '' ) );
		$label = strtolower( (string) ( $field->field_label ?? '' ) );
		$text  = $key . ' ' . $label;

		foreach ( array( 'message', 'comments', 'comment', 'enquiry', 'inquiry', 'details' ) as $needle ) {
			if ( false !== strpos( $text, $needle ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Human mail event source label.
	 *
	 * @param string $source Event source.
	 * @return string
	 */
	private function mail_event_source_label( $source ) {
		$labels = array(
			'submission_inbox_form'       => __( 'Admin notification', 'submission-inbox' ),
			'submission_inbox_auto_reply' => __( 'Visitor auto-reply', 'submission-inbox' ),
			'contact_form_7'          => __( 'Contact Form 7', 'submission-inbox' ),
			'wpforms'                 => __( 'WPForms', 'submission-inbox' ),
			'fluent_forms'            => __( 'Fluent Forms', 'submission-inbox' ),
			'forminator'              => __( 'Forminator', 'submission-inbox' ),
			'ninja_forms'             => __( 'Ninja Forms', 'submission-inbox' ),
			'wp_mail'                 => __( 'WordPress email', 'submission-inbox' ),
			'wordpress'               => __( 'WordPress email', 'submission-inbox' ),
			'plugin'                  => __( 'Plugin email', 'submission-inbox' ),
		);

		$source = sanitize_key( $source );
		return $labels[ $source ] ?? __( 'Email event', 'submission-inbox' );
	}

	/**
	 * Human source label.
	 *
	 * @param string $provider Provider.
	 * @return string
	 */
	private function provider_label( $provider ) {
		return $this->providers->label( $provider );
	}

	/**
	 * Workflow status label.
	 *
	 * @param string $status Status.
	 * @return string
	 */
	private function workflow_status_label( $status ) {
		$labels = $this->workflow->workflow_statuses();
		$status = sanitize_key( $status );

		return $labels[ $status ] ?? $labels['open'];
	}

	/**
	 * Priority label.
	 *
	 * @param string $priority Priority.
	 * @return string
	 */
	private function priority_label( $priority ) {
		$labels   = $this->workflow->priorities();
		$priority = sanitize_key( $priority );

		return $labels[ $priority ] ?? $labels['normal'];
	}

	/**
	 * Assignee display label.
	 *
	 * @param int $user_id User id.
	 * @return string
	 */
	private function assignee_label( $user_id ) {
		$user = get_userdata( absint( $user_id ) );

		return $user ? $user->display_name : __( 'Unassigned', 'submission-inbox' );
	}

	/**
	 * Render source link.
	 *
	 * @param string $url URL.
	 * @return void
	 */
	private function source_link( $url ) {
		if ( empty( $url ) ) {
			echo esc_html__( 'Not recorded', 'submission-inbox' );
			return;
		}

		printf(
			'<a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>',
			esc_url( $url ),
			esc_html( wp_parse_url( $url, PHP_URL_HOST ) ? wp_parse_url( $url, PHP_URL_HOST ) : $url )
		);
	}

	/**
	 * Format date.
	 *
	 * @param string $date Date.
	 * @return string
	 */
	private function format_date( $date ) {
		if ( empty( $date ) ) {
			return '';
		}

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

	/**
	 * List URL.
	 *
	 * @param array<string,mixed> $filters Filters.
	 * @param int                 $paged Page.
	 * @return string
	 */
	private function list_url( array $filters, $paged ) {
		$args = $this->url_args_from_filters( $filters );
		if ( $paged > 1 ) {
			$args['paged'] = $paged;
		}

		return add_query_arg(
			$args,
			admin_url( 'admin.php' )
		);
	}

	/**
	 * Detail URL.
	 *
	 * @param int  $lead_id Lead id.
	 * @param bool   $updated Include updated flag.
	 * @param string $notice Notice key.
	 * @return string
	 */
	private function detail_url( $lead_id, $updated = false, $notice = '' ) {
		$args = array(
			'page'    => SUBIN_AdminMenu::MENU_SLUG,
			'action'  => 'view',
			'lead_id' => absint( $lead_id ),
		);

		if ( $updated ) {
			$args['subin_updated'] = 1;
		}

		if ( '' !== $notice ) {
			$args['subin_notice'] = sanitize_key( $notice );
		}

		return add_query_arg( $args, admin_url( 'admin.php' ) );
	}

	/**
	 * 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;
	}
}
