<?php
/**
 * Forms portfolio command center.
 *
 * @package SubmissionInbox
 */

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

/**
 * Renders and operates the compact Forms portfolio screen.
 */
class SUBIN_FormsCommandCenter {
	const PER_PAGE = 20;
	const NONCE_ACTION = 'subin_forms_command';
	const NONCE_NAME = 'subin_forms_command_nonce';

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

	/** @var \SUBIN\Forms\FormsOverviewRepository */
	private $overview;

	/** @var \SUBIN\Forms\FormOrganizationRepository */
	private $organization;

	/** @var \SUBIN\Forms\FormAnalyticsRepository */
	private $analytics;

	/** @var \SUBIN\Forms\FormLocationService */
	private $locations;

	/** @var \SUBIN\Forms\FormPermanentDeletionService */
	private $permanent_deletion;

	/**
	 * Constructor.
	 *
	 * @param \SUBIN\Forms\FormRepository|null             $forms Form repository.
	 * @param \SUBIN\Forms\FormsOverviewRepository|null    $overview Overview repository.
	 * @param \SUBIN\Forms\FormOrganizationRepository|null $organization Organization repository.
	 * @param \SUBIN\Forms\FormAnalyticsRepository|null    $analytics Analytics repository.
	 * @param \SUBIN\Forms\FormLocationService|null        $locations Location service.
	 * @param \SUBIN\Forms\FormPermanentDeletionService|null $permanent_deletion Permanent deletion service.
	 */
	public function __construct( $forms = null, $overview = null, $organization = null, $analytics = null, $locations = null, $permanent_deletion = null ) {
		$this->forms        = $forms ? $forms : new \SUBIN\Forms\FormRepository();
		$this->overview     = $overview ? $overview : new \SUBIN\Forms\FormsOverviewRepository();
		$this->organization = $organization ? $organization : new \SUBIN\Forms\FormOrganizationRepository();
		$this->analytics    = $analytics ? $analytics : new \SUBIN\Forms\FormAnalyticsRepository();
		$this->locations    = $locations ? $locations : new \SUBIN\Forms\FormLocationService();
		$this->permanent_deletion = $permanent_deletion ? $permanent_deletion : new \SUBIN\Forms\FormPermanentDeletionService();
	}

	/**
	 * Handle portfolio POST commands before admin headers are sent.
	 *
	 * @return void
	 */
	public function handle_post() {
		$request_method = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ?? '' ) );
		$action         = isset( $_POST['subin_forms_action'] ) ? sanitize_key( wp_unslash( $_POST['subin_forms_action'] ) ) : '';
		if ( 'POST' !== strtoupper( $request_method ) || '' === $action ) {
			return;
		}

		$required_capability = $this->required_capability_for_action( $action );
		if ( '' === $required_capability || ! \SUBIN\Security\Capabilities::can_current_user( $required_capability ) ) {
			wp_die( esc_html__( 'You do not have permission to perform this action.', 'submission-inbox' ) );
		}

		$nonce = isset( $_POST[ self::NONCE_NAME ] ) ? sanitize_text_field( wp_unslash( $_POST[ self::NONCE_NAME ] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, self::NONCE_ACTION ) ) {
			$this->redirect( 'security_failed' );
		}

		if ( 'create_folder' === $action ) {
			$folder_id = $this->organization->create_folder( wp_unslash( $_POST['folder_name'] ?? '' ) );
			$this->redirect( $folder_id > 0 ? 'folder_created' : 'organization_failed' );
		}

		if ( 'create_tag' === $action ) {
			$tag_id = $this->organization->create_tag( wp_unslash( $_POST['tag_name'] ?? '' ) );
			$this->redirect( $tag_id > 0 ? 'tag_created' : 'organization_failed' );
		}

		$form_ids = isset( $_POST['form_ids'] ) && is_array( $_POST['form_ids'] )
			? array_values( array_unique( array_filter( array_map( 'absint', wp_unslash( $_POST['form_ids'] ) ) ) ) )
			: array();
		if ( empty( $form_ids ) ) {
			$this->redirect( 'forms_not_selected' );
		}

		$notice = $this->run_command( $action, $form_ids );
		$this->redirect( $notice );
	}

	/**
	 * Resolve the narrow capability required by a portfolio command.
	 *
	 * @param string $action Command key.
	 * @return string Empty for unsupported commands.
	 */
	private function required_capability_for_action( $action ) {
		$action = sanitize_key( (string) $action );
		if ( 'delete_permanently' === $action ) {
			return \SUBIN\Security\Capabilities::DELETE_FORMS;
		}

		if ( in_array( $action, array( 'create_folder', 'create_tag', 'activate', 'deactivate', 'trash', 'restore', 'duplicate', 'move_folder', 'add_tag', 'remove_tag' ), true ) ) {
			return \SUBIN\Security\Capabilities::MANAGE_FORMS;
		}

		return '';
	}

	/**
	 * Render the complete portfolio screen.
	 *
	 * @return void
	 */
	public function render() {
		$filters = $this->filters_from_request();
		$data    = $this->load_portfolio( $filters );
		$filters = $data['filters'];

		SUBIN_View::page_header(
			__( 'Forms', 'submission-inbox' ),
			__( 'Monitor performance, submissions, delivery, and form readiness from one workspace.', 'submission-inbox' ),
			array(
				'wrapper_class'  => 'subin-forms-page subin-forms-command-center',
				'primary_action' => array(
					'label' => __( 'Create Form', 'submission-inbox' ),
					'url'   => $this->templates_url(),
				),
			)
		);

		$this->render_notice();
		$this->render_global_health( $data['global_issues'] );
		$this->render_kpis( $data['summary'], $filters );
		$this->render_tabs( $data['tabs'], $filters );
		$this->render_toolbar( $filters, $data['folders'], $data['tags'], $data['filtered_total'] );

		if ( empty( $data['forms'] ) ) {
			$this->render_empty_state( $data['all_total'], $filters );
		} else {
			$this->render_bulk_toolbar( $data['folders'], $data['tags'], $filters['state'] );
			$this->render_forms_table( $data['forms'], $filters );
			$this->render_pagination( $data['filtered_total'], $filters );
		}

		$this->render_diagnostic_guide();
		SUBIN_View::page_footer();
	}

	/**
	 * Execute a validated state-changing command.
	 *
	 * @param string         $action Command.
	 * @param array<int,int> $form_ids Form ids.
	 * @return string Notice key.
	 */
	private function run_command( $action, array $form_ids ) {
		$success        = 0;
		$total          = count( $form_ids );
		$resolved_forms = array();
		foreach ( $form_ids as $form_id ) {
			$form = $this->forms->get( $form_id );
			if ( is_array( $form ) ) {
				$resolved_forms[ $form_id ] = $form;
			}
		}

		$organization_ids = array_keys( array_filter( $resolved_forms, function ( $form ) {
			return \SUBIN\Forms\FormRepository::STATUS_TRASHED !== sanitize_key( $form['status'] ?? '' );
		} ) );

		if ( 'move_folder' === $action ) {
			$folder_id = absint( wp_unslash( $_POST['folder_id'] ?? 0 ) );
			$ok        = ! empty( $organization_ids ) && $this->organization->move_forms( $organization_ids, $folder_id );
			return $ok ? ( count( $organization_ids ) === $total ? 'forms_organized' : 'command_partially_completed' ) : 'organization_failed';
		}

		if ( in_array( $action, array( 'add_tag', 'remove_tag' ), true ) ) {
			$tag_id = absint( wp_unslash( $_POST['tag_id'] ?? 0 ) );
			$ok     = ! empty( $organization_ids ) && ( 'add_tag' === $action
				? $this->organization->add_tag( $organization_ids, $tag_id )
				: $this->organization->remove_tag( $organization_ids, $tag_id ) );
			return $ok ? ( count( $organization_ids ) === $total ? 'forms_organized' : 'command_partially_completed' ) : 'organization_failed';
		}

		foreach ( $resolved_forms as $form_id => $form ) {
			$is_trash = \SUBIN\Forms\FormRepository::STATUS_TRASHED === sanitize_key( $form['status'] ?? '' );
			if ( ( $is_trash && ! in_array( $action, array( 'restore', 'delete_permanently' ), true ) )
				|| ( ! $is_trash && in_array( $action, array( 'restore', 'delete_permanently' ), true ) ) ) {
				continue;
			}

			switch ( $action ) {
				case 'activate':
					$success += $this->forms->update_status( $form_id, \SUBIN\Forms\FormRepository::STATUS_ACTIVE ) ? 1 : 0;
					break;
				case 'deactivate':
					$success += $this->forms->update_status( $form_id, \SUBIN\Forms\FormRepository::STATUS_INACTIVE ) ? 1 : 0;
					break;
				case 'trash':
					$success += $this->forms->update_status( $form_id, \SUBIN\Forms\FormRepository::STATUS_TRASHED ) ? 1 : 0;
					break;
				case 'restore':
					$success += $this->forms->update_status( $form_id, \SUBIN\Forms\FormRepository::STATUS_INACTIVE ) ? 1 : 0;
					break;
				case 'duplicate':
					$new_form_id = $this->forms->duplicate( $form_id );
					if ( $new_form_id > 0 ) {
						$this->organization->copy_assignments( $form_id, $new_form_id );
						++$success;
					}
					break;
				case 'delete_permanently':
					if ( \SUBIN\Forms\FormRepository::STATUS_TRASHED !== sanitize_key( $form['status'] ?? '' ) ) {
						break;
					}
					if ( $this->permanent_deletion->delete( $form_id ) ) {
						++$success;
					}
					break;
			}
		}

		if ( $success <= 0 ) {
			return 'command_failed';
		}

		return $success === $total ? 'command_completed' : 'command_partially_completed';
	}

	/**
	 * Load, enrich, filter, sort, and paginate the portfolio.
	 *
	 * @param array<string,mixed> $filters Filters.
	 * @return array<string,mixed>
	 */
	private function load_portfolio( array $filters ) {
		$overview = $this->overview->get_overview( array( 'period_days' => $filters['period'] ) );
		$forms    = is_array( $overview['forms'] ?? null ) ? $overview['forms'] : array();
		$form_ids = array_values( array_filter( array_map( 'absint', wp_list_pluck( $forms, 'id' ) ) ) );
		$folders  = $this->organization->get_folders();
		$tags     = $this->organization->get_tags();
		$org      = $this->organization->get_assignments( $form_ids );
		$funnels  = $this->analytics->get_funnel_aggregates( $form_ids );
		$locations = $this->locations->get_locations( $form_ids );

		foreach ( $forms as &$form ) {
			$form_id              = absint( $form['id'] ?? 0 );
			$form['organization'] = $org[ $form_id ] ?? array( 'folder' => null, 'tags' => array() );
			$form['analytics']    = $funnels[ $form_id ] ?? array( '7d' => $this->empty_funnel(), '30d' => $this->empty_funnel() );
			$form['locations']    = $locations[ $form_id ] ?? array( 'locations' => array(), 'count' => 0, 'orphaned' => true );
		}
		unset( $form );

		$tabs     = $this->tab_counts( $forms );
		$summary  = $this->portfolio_summary( $forms, $filters['period'] );
		$filtered = array_values( array_filter( $forms, function ( $form ) use ( $filters ) {
			return $this->matches_filters( $form, $filters );
		} ) );
		$this->sort_forms( $filtered, $filters );

		$filtered_total = count( $filtered );
		$total_pages    = max( 1, (int) ceil( $filtered_total / self::PER_PAGE ) );
		$filters['paged'] = min( $filters['paged'], $total_pages );
		$offset          = ( $filters['paged'] - 1 ) * self::PER_PAGE;

		return array(
			'forms'          => array_slice( $filtered, $offset, self::PER_PAGE ),
			'filtered_total' => $filtered_total,
			'filters'        => $filters,
			'all_total'      => $tabs['all'],
			'tabs'           => $tabs,
			'summary'        => $summary,
			'folders'        => $folders,
			'tags'           => $tags,
			'global_issues'  => is_array( $overview['global_issues'] ?? null ) ? $overview['global_issues'] : array(),
		);
	}

	/**
	 * Read safe filters from the query string.
	 *
	 * @return array<string,mixed>
	 */
	private function filters_from_request() {
		$state  = SUBIN_Request::get_key( 'subin_form_state', 'all' );
		$health = SUBIN_Request::get_key( 'subin_health' );
		$sort   = SUBIN_Request::get_key( 'subin_sort', 'updated' );
		$order  = SUBIN_Request::get_key( 'subin_order', 'title' === $sort ? 'asc' : 'desc' );
		$period = SUBIN_Request::get_absint( 'subin_period', 30 );

		return array(
			'search' => SUBIN_Request::get_text( 's' ),
			'state'  => in_array( $state, array( 'all', 'attention', 'active', 'inactive', 'drafts', 'trash' ), true ) ? $state : 'all',
			'health' => in_array( $health, array( 'healthy', 'attention', 'critical' ), true ) ? $health : '',
			'folder' => SUBIN_Request::get_text( 'subin_folder' ),
			'tag'    => SUBIN_Request::get_absint( 'subin_tag' ),
			'sort'   => in_array( $sort, array( 'updated', 'title', 'leads', 'unread', 'conversion', 'health' ), true ) ? $sort : 'updated',
			'order'  => 'asc' === $order ? 'asc' : 'desc',
			'period' => in_array( $period, array( 7, 30 ), true ) ? $period : 30,
			'paged'  => max( 1, SUBIN_Request::get_absint( 'paged', 1 ) ),
		);
	}

	/**
	 * Check one form against portfolio filters.
	 *
	 * @param array<string,mixed> $form Form.
	 * @param array<string,mixed> $filters Filters.
	 * @return bool
	 */
	private function matches_filters( array $form, array $filters ) {
		$status    = sanitize_key( $form['status'] ?? '' );
		$is_trash  = \SUBIN\Forms\FormRepository::STATUS_TRASHED === $status;
		$health    = sanitize_key( $form['health']['status'] ?? 'healthy' );
		$is_dirty  = ! empty( $form['publishing']['is_dirty'] );

		switch ( $filters['state'] ) {
			case 'trash':
				if ( ! $is_trash ) {
					return false;
				}
				break;
			case 'attention':
				if ( $is_trash || 'healthy' === $health ) {
					return false;
				}
				break;
			case 'active':
				if ( $is_trash || \SUBIN\Forms\FormRepository::STATUS_ACTIVE !== $status ) {
					return false;
				}
				break;
			case 'inactive':
				if ( \SUBIN\Forms\FormRepository::STATUS_INACTIVE !== $status ) {
					return false;
				}
				break;
			case 'drafts':
				if ( $is_trash || ! $is_dirty ) {
					return false;
				}
				break;
			default:
				if ( $is_trash ) {
					return false;
				}
		}

		if ( '' !== $filters['health'] && $filters['health'] !== $health ) {
			return false;
		}

		$folder = $form['organization']['folder'] ?? null;
		if ( 'unfiled' === $filters['folder'] && is_array( $folder ) ) {
			return false;
		}
		if ( '' !== $filters['folder'] && 'unfiled' !== $filters['folder'] && absint( $filters['folder'] ) !== absint( $folder['id'] ?? 0 ) ) {
			return false;
		}

		if ( $filters['tag'] > 0 ) {
			$tag_ids = array_map( 'absint', wp_list_pluck( (array) ( $form['organization']['tags'] ?? array() ), 'id' ) );
			if ( ! in_array( $filters['tag'], $tag_ids, true ) ) {
				return false;
			}
		}

		if ( '' !== $filters['search'] ) {
			$haystack = strtolower( implode( ' ', array(
				(string) ( $form['title'] ?? '' ),
				(string) ( $form['slug'] ?? '' ),
				(string) ( $form['id'] ?? '' ),
				(string) ( $folder['name'] ?? '' ),
				implode( ' ', wp_list_pluck( (array) ( $form['organization']['tags'] ?? array() ), 'name' ) ),
			) ) );
			if ( false === strpos( $haystack, strtolower( $filters['search'] ) ) ) {
				return false;
			}
		}

		return true;
	}

	/**
	 * Sort enriched rows.
	 *
	 * @param array<int,array<string,mixed>> $forms Forms by reference.
	 * @param array<string,mixed>            $filters Filters.
	 * @return void
	 */
	private function sort_forms( array &$forms, array $filters ) {
		$period = $filters['period'] . 'd';
		usort( $forms, function ( $left, $right ) use ( $filters, $period ) {
			switch ( $filters['sort'] ) {
				case 'title':
					$a = strtolower( (string) ( $left['title'] ?? '' ) );
					$b = strtolower( (string) ( $right['title'] ?? '' ) );
					break;
				case 'leads':
					$a = absint( $left['leads']['period_count'] ?? 0 );
					$b = absint( $right['leads']['period_count'] ?? 0 );
					break;
				case 'unread':
					$a = absint( $left['leads']['unread'] ?? 0 );
					$b = absint( $right['leads']['unread'] ?? 0 );
					break;
				case 'conversion':
					$a = (float) ( $left['analytics'][ $period ]['conversion_rate'] ?? 0 );
					$b = (float) ( $right['analytics'][ $period ]['conversion_rate'] ?? 0 );
					break;
				case 'health':
					$weights = array( 'healthy' => 0, 'attention' => 1, 'critical' => 2 );
					$a = $weights[ $left['health']['status'] ?? 'healthy' ] ?? 0;
					$b = $weights[ $right['health']['status'] ?? 'healthy' ] ?? 0;
					break;
				default:
					$a = strtotime( (string) ( $left['updated_at'] ?? '' ) ) ?: 0;
					$b = strtotime( (string) ( $right['updated_at'] ?? '' ) ) ?: 0;
			}

			$result = $a <=> $b;
			if ( 0 === $result ) {
				$result = absint( $left['id'] ?? 0 ) <=> absint( $right['id'] ?? 0 );
			}
			return 'asc' === $filters['order'] ? $result : -$result;
		} );
	}

	/**
	 * Count states for tabs.
	 *
	 * @param array<int,array<string,mixed>> $forms Forms.
	 * @return array<string,int>
	 */
	private function tab_counts( array $forms ) {
		$counts = array( 'all' => 0, 'attention' => 0, 'active' => 0, 'inactive' => 0, 'drafts' => 0, 'trash' => 0 );
		foreach ( $forms as $form ) {
			$status = sanitize_key( $form['status'] ?? '' );
			if ( \SUBIN\Forms\FormRepository::STATUS_TRASHED === $status ) {
				++$counts['trash'];
				continue;
			}
			++$counts['all'];
			if ( \SUBIN\Forms\FormRepository::STATUS_ACTIVE === $status ) {
				++$counts['active'];
			} else {
				++$counts['inactive'];
			}
			if ( 'healthy' !== ( $form['health']['status'] ?? 'healthy' ) ) {
				++$counts['attention'];
			}
			if ( ! empty( $form['publishing']['is_dirty'] ) ) {
				++$counts['drafts'];
			}
		}
		return $counts;
	}

	/**
	 * Portfolio KPI values excluding trash.
	 *
	 * @param array<int,array<string,mixed>> $forms Forms.
	 * @param int                            $period Period.
	 * @return array<string,int|float>
	 */
	private function portfolio_summary( array $forms, $period ) {
		$summary = array(
			'active' => 0, 'attention' => 0, 'leads' => 0, 'unread' => 0,
			'failed' => 0, 'views' => 0, 'submissions' => 0, 'conversion' => 0.0,
		);
		$key = absint( $period ) . 'd';
		foreach ( $forms as $form ) {
			if ( \SUBIN\Forms\FormRepository::STATUS_TRASHED === sanitize_key( $form['status'] ?? '' ) ) {
				continue;
			}
			$summary['active']    += ! empty( $form['is_active'] ) ? 1 : 0;
			$summary['attention'] += 'healthy' !== ( $form['health']['status'] ?? 'healthy' ) ? 1 : 0;
			$summary['leads']     += absint( $form['leads']['period_count'] ?? 0 );
			$summary['unread']    += absint( $form['leads']['unread'] ?? 0 );
			$summary['failed']    += absint( $form['email']['failed_period'] ?? 0 );
			$summary['views']     += absint( $form['analytics'][ $key ]['views'] ?? 0 );
			$summary['submissions'] += absint( $form['analytics'][ $key ]['submissions'] ?? 0 );
		}
		$summary['conversion'] = $summary['views'] > 0 ? round( ( $summary['submissions'] / $summary['views'] ) * 100, 1 ) : 0.0;
		return $summary;
	}

	/**
	 * Render global health once for the whole portfolio.
	 *
	 * @param array<int,array<string,mixed>> $issues Issues.
	 * @return void
	 */
	private function render_global_health( array $issues ) {
		if ( empty( $issues ) ) {
			return;
		}
		$issue = reset( $issues );
		?>
		<div class="subin-portfolio-alert subin-portfolio-alert--<?php echo esc_attr( sanitize_html_class( $issue['severity'] ?? 'warning' ) ); ?>">
			<span class="dashicons dashicons-warning" aria-hidden="true"></span>
			<div class="subin-portfolio-alert__content">
				<strong><?php echo esc_html( $issue['title'] ?? __( 'Delivery setup needs attention', 'submission-inbox' ) ); ?></strong>
				<span><?php echo esc_html( $issue['message'] ?? '' ); ?></span>
			</div>
			<a class="button subin-btn subin-btn-secondary" href="<?php echo esc_url( admin_url( 'admin.php?page=subin-settings&subin_settings_tab=sending' ) ); ?>"><?php echo esc_html( $issue['action']['label'] ?? __( 'Configure SMTP', 'submission-inbox' ) ); ?></a>
			<a class="subin-inline-link" href="<?php echo esc_url( admin_url( 'admin.php?page=subin-email-status' ) ); ?>"><?php esc_html_e( 'Email Health', 'submission-inbox' ); ?></a>
		</div>
		<?php
	}

	/**
	 * Render portfolio KPI cards.
	 *
	 * @param array<string,int|float> $summary Summary.
	 * @param array<string,mixed>     $filters Filters.
	 * @return void
	 */
	private function render_kpis( array $summary, array $filters ) {
		$cards = array(
			array( 'key' => 'active', 'label' => __( 'Active forms', 'submission-inbox' ), 'value' => $summary['active'], 'hint' => __( 'Currently accepting submissions', 'submission-inbox' ), 'icon' => 'dashicons-forms', 'url' => $this->list_url( $filters, array( 'state' => 'active', 'paged' => 1 ) ) ),
			array( 'key' => 'attention', 'label' => __( 'Needs attention', 'submission-inbox' ), 'value' => $summary['attention'], 'hint' => __( 'Actionable form issues', 'submission-inbox' ), 'icon' => 'dashicons-warning', 'url' => $this->list_url( $filters, array( 'state' => 'attention', 'paged' => 1 ) ) ),
			/* translators: %d: number of days in the reporting period. */
			array( 'key' => 'leads', 'label' => sprintf( __( 'Leads · %dd', 'submission-inbox' ), $filters['period'] ), 'value' => $summary['leads'], 'hint' => __( 'Accepted submissions', 'submission-inbox' ), 'icon' => 'dashicons-groups', 'url' => admin_url( 'admin.php?page=subin-inbox&subin_provider=submission_inbox_form' ) ),
			array( 'key' => 'unread', 'label' => __( 'Unseen leads', 'submission-inbox' ), 'value' => $summary['unread'], 'hint' => __( 'Waiting in Inbox', 'submission-inbox' ), 'icon' => 'dashicons-email-alt', 'url' => admin_url( 'admin.php?page=subin-inbox&subin_provider=submission_inbox_form&subin_status=new' ) ),
			/* translators: %1$d: submitted forms, %2$d: form views. */
			array( 'key' => 'conversion', 'label' => __( 'Conversion', 'submission-inbox' ), 'value' => number_format_i18n( $summary['conversion'], 1 ) . '%', 'hint' => $summary['views'] > 0 ? sprintf( __( '%1$d submissions / %2$d views', 'submission-inbox' ), $summary['submissions'], $summary['views'] ) : __( 'Collecting anonymous funnel data', 'submission-inbox' ), 'icon' => 'dashicons-chart-line', 'url' => '' ),
			/* translators: %d: number of days in the reporting period. */
			array( 'key' => 'failed', 'label' => __( 'Delivery failures', 'submission-inbox' ), 'value' => $summary['failed'], 'hint' => sprintf( __( 'Last %d days', 'submission-inbox' ), $filters['period'] ), 'icon' => 'dashicons-dismiss', 'url' => admin_url( 'admin.php?page=subin-email-log&subin_source=submission_inbox_form&subin_status=failed&subin_date_range=' . $filters['period'] ) ),
		);
		?>
		<div class="subin-portfolio-kpis">
			<?php foreach ( $cards as $card ) : ?>
				<?php $tag = '' !== $card['url'] ? 'a' : 'div'; ?>
				<<?php echo esc_html( $tag ); ?> class="subin-portfolio-kpi subin-portfolio-kpi--<?php echo esc_attr( $card['key'] ); ?>"<?php echo '' !== $card['url'] ? ' href="' . esc_url( $card['url'] ) . '"' : ''; ?>>
					<span class="subin-portfolio-kpi__icon dashicons <?php echo esc_attr( $card['icon'] ); ?>" aria-hidden="true"></span>
					<span class="subin-portfolio-kpi__body"><strong><?php echo esc_html( (string) $card['value'] ); ?></strong><span><?php echo esc_html( $card['label'] ); ?></span><small><?php echo esc_html( $card['hint'] ); ?></small></span>
				</<?php echo esc_html( $tag ); ?>>
			<?php endforeach; ?>
		</div>
		<?php
	}

	/**
	 * Render state tabs.
	 *
	 * @param array<string,int>   $counts Counts.
	 * @param array<string,mixed> $filters Filters.
	 * @return void
	 */
	private function render_tabs( array $counts, array $filters ) {
		$labels = array(
			'all' => __( 'All forms', 'submission-inbox' ), 'attention' => __( 'Needs attention', 'submission-inbox' ),
			'active' => __( 'Active', 'submission-inbox' ), 'inactive' => __( 'Inactive', 'submission-inbox' ),
			'drafts' => __( 'Unpublished changes', 'submission-inbox' ), 'trash' => __( 'Trash', 'submission-inbox' ),
		);
		?>
		<nav class="subin-portfolio-tabs" aria-label="<?php esc_attr_e( 'Form status views', 'submission-inbox' ); ?>">
			<?php foreach ( $labels as $key => $label ) : ?>
				<a class="subin-portfolio-tab<?php echo $filters['state'] === $key ? ' is-active' : ''; ?>" href="<?php echo esc_url( $this->list_url( $filters, array( 'state' => $key, 'paged' => 1 ) ) ); ?>"<?php echo $filters['state'] === $key ? ' aria-current="page"' : ''; ?>><?php echo esc_html( $label ); ?> <span><?php echo esc_html( (string) ( $counts[ $key ] ?? 0 ) ); ?></span></a>
			<?php endforeach; ?>
		</nav>
		<?php
	}

	/**
	 * Render search and filters.
	 *
	 * @param array<string,mixed>             $filters Filters.
	 * @param array<int,array<string,mixed>>  $folders Folders.
	 * @param array<int,array<string,mixed>>  $tags Tags.
	 * @param int                             $result_count Result count.
	 * @return void
	 */
	private function render_toolbar( array $filters, array $folders, array $tags, $result_count ) {
		?>
		<div class="subin-portfolio-toolbar">
			<form method="get" action="" class="subin-portfolio-filters">
				<input type="hidden" name="page" value="submission-inbox-forms" />
				<input type="hidden" name="subin_form_state" value="<?php echo esc_attr( $filters['state'] ); ?>" />
				<label class="subin-portfolio-search"><span class="dashicons dashicons-search" aria-hidden="true"></span><span class="screen-reader-text"><?php esc_html_e( 'Search forms', 'submission-inbox' ); ?></span><input type="search" name="s" value="<?php echo esc_attr( $filters['search'] ); ?>" placeholder="<?php esc_attr_e( 'Search forms, tags, folders…', 'submission-inbox' ); ?>" /></label>
				<select name="subin_health" aria-label="<?php esc_attr_e( 'Health', 'submission-inbox' ); ?>">
					<option value=""><?php esc_html_e( 'All health states', 'submission-inbox' ); ?></option>
					<option value="critical" <?php selected( $filters['health'], 'critical' ); ?>><?php esc_html_e( 'Critical', 'submission-inbox' ); ?></option>
					<option value="attention" <?php selected( $filters['health'], 'attention' ); ?>><?php esc_html_e( 'Needs attention', 'submission-inbox' ); ?></option>
					<option value="healthy" <?php selected( $filters['health'], 'healthy' ); ?>><?php esc_html_e( 'Healthy', 'submission-inbox' ); ?></option>
				</select>
				<select name="subin_folder" aria-label="<?php esc_attr_e( 'Folder', 'submission-inbox' ); ?>">
					<option value=""><?php esc_html_e( 'All folders', 'submission-inbox' ); ?></option>
					<option value="unfiled" <?php selected( $filters['folder'], 'unfiled' ); ?>><?php esc_html_e( 'Unfiled', 'submission-inbox' ); ?></option>
					<?php foreach ( $folders as $folder ) : ?><option value="<?php echo esc_attr( (string) absint( $folder['id'] ?? 0 ) ); ?>" <?php selected( (string) $filters['folder'], (string) absint( $folder['id'] ?? 0 ) ); ?>><?php echo esc_html( $folder['name'] ?? '' ); ?></option><?php endforeach; ?>
				</select>
				<select name="subin_tag" aria-label="<?php esc_attr_e( 'Tag', 'submission-inbox' ); ?>">
					<option value="0"><?php esc_html_e( 'All tags', 'submission-inbox' ); ?></option>
					<?php foreach ( $tags as $tag ) : ?><option value="<?php echo esc_attr( (string) absint( $tag['id'] ?? 0 ) ); ?>" <?php selected( $filters['tag'], absint( $tag['id'] ?? 0 ) ); ?>><?php echo esc_html( $tag['name'] ?? '' ); ?></option><?php endforeach; ?>
				</select>
				<select name="subin_period" aria-label="<?php esc_attr_e( 'Reporting period', 'submission-inbox' ); ?>"><option value="7" <?php selected( $filters['period'], 7 ); ?>><?php esc_html_e( 'Last 7 days', 'submission-inbox' ); ?></option><option value="30" <?php selected( $filters['period'], 30 ); ?>><?php esc_html_e( 'Last 30 days', 'submission-inbox' ); ?></option></select>
				<select name="subin_sort" aria-label="<?php esc_attr_e( 'Sort forms', 'submission-inbox' ); ?>">
					<option value="updated" <?php selected( $filters['sort'], 'updated' ); ?>><?php esc_html_e( 'Recently updated', 'submission-inbox' ); ?></option><option value="title" <?php selected( $filters['sort'], 'title' ); ?>><?php esc_html_e( 'Name', 'submission-inbox' ); ?></option><option value="leads" <?php selected( $filters['sort'], 'leads' ); ?>><?php esc_html_e( 'Most leads', 'submission-inbox' ); ?></option><option value="unread" <?php selected( $filters['sort'], 'unread' ); ?>><?php esc_html_e( 'Most unseen', 'submission-inbox' ); ?></option><option value="conversion" <?php selected( $filters['sort'], 'conversion' ); ?>><?php esc_html_e( 'Best conversion', 'submission-inbox' ); ?></option><option value="health" <?php selected( $filters['sort'], 'health' ); ?>><?php esc_html_e( 'Health severity', 'submission-inbox' ); ?></option>
				</select>
				<button type="submit" class="button subin-btn subin-btn-primary"><?php esc_html_e( 'Apply', 'submission-inbox' ); ?></button>
				<a class="button subin-btn" href="<?php echo esc_url( admin_url( 'admin.php?page=submission-inbox-forms' ) ); ?>"><?php esc_html_e( 'Reset', 'submission-inbox' ); ?></a>
			</form>
			<div class="subin-portfolio-toolbar__meta"><strong><?php echo esc_html( number_format_i18n( $result_count ) ); ?></strong> <?php esc_html_e( 'forms', 'submission-inbox' ); ?></div>
			<?php $this->render_organization_creator(); ?>
		</div>
		<?php
	}

	/** Render create-folder/tag controls. */
	private function render_organization_creator() {
		?>
		<details class="subin-organize-menu">
			<summary class="button subin-btn"><span class="dashicons dashicons-category" aria-hidden="true"></span><?php esc_html_e( 'Organize', 'submission-inbox' ); ?></summary>
			<div class="subin-organize-menu__popover">
				<strong><?php esc_html_e( 'Create folder or tag', 'submission-inbox' ); ?></strong>
				<form method="post" action=""><input type="hidden" name="subin_forms_action" value="create_folder" /><?php wp_nonce_field( self::NONCE_ACTION, self::NONCE_NAME ); ?><label><?php esc_html_e( 'Folder name', 'submission-inbox' ); ?><span><input type="text" name="folder_name" maxlength="100" required /><button class="button" type="submit"><?php esc_html_e( 'Create', 'submission-inbox' ); ?></button></span></label></form>
				<form method="post" action=""><input type="hidden" name="subin_forms_action" value="create_tag" /><?php wp_nonce_field( self::NONCE_ACTION, self::NONCE_NAME ); ?><label><?php esc_html_e( 'Tag name', 'submission-inbox' ); ?><span><input type="text" name="tag_name" maxlength="100" required /><button class="button" type="submit"><?php esc_html_e( 'Create', 'submission-inbox' ); ?></button></span></label></form>
			</div>
		</details>
		<?php
	}

	/** Render bulk controls. */
	private function render_bulk_toolbar( array $folders, array $tags, $state ) {
		$is_trash   = 'trash' === $state;
		$can_delete = \SUBIN\Security\Capabilities::can_current_user( \SUBIN\Security\Capabilities::DELETE_FORMS );
		?>
		<form id="subin-forms-bulk" class="subin-forms-bulk" method="post" action="" data-subin-trash-confirm="<?php esc_attr_e( 'Move the selected forms to Trash?', 'submission-inbox' ); ?>" data-subin-permanent-confirm="<?php esc_attr_e( 'Delete the selected forms permanently? Saved leads and email history will remain, and already scheduled emails may still be sent.', 'submission-inbox' ); ?>">
			<?php wp_nonce_field( self::NONCE_ACTION, self::NONCE_NAME ); ?>
			<label><span class="screen-reader-text"><?php esc_html_e( 'Bulk action', 'submission-inbox' ); ?></span><select name="subin_forms_action" data-subin-bulk-action>
				<option value=""><?php esc_html_e( 'Bulk actions', 'submission-inbox' ); ?></option>
				<?php if ( $is_trash ) : ?>
					<option value="restore"><?php esc_html_e( 'Restore as inactive', 'submission-inbox' ); ?></option>
					<?php if ( $can_delete ) : ?><option value="delete_permanently"><?php esc_html_e( 'Delete permanently', 'submission-inbox' ); ?></option><?php endif; ?>
				<?php else : ?>
					<option value="activate"><?php esc_html_e( 'Activate', 'submission-inbox' ); ?></option>
					<option value="deactivate"><?php esc_html_e( 'Deactivate', 'submission-inbox' ); ?></option>
					<option value="duplicate"><?php esc_html_e( 'Duplicate', 'submission-inbox' ); ?></option>
					<option value="move_folder"><?php esc_html_e( 'Move to folder', 'submission-inbox' ); ?></option>
					<option value="add_tag"><?php esc_html_e( 'Add tag', 'submission-inbox' ); ?></option>
					<option value="remove_tag"><?php esc_html_e( 'Remove tag', 'submission-inbox' ); ?></option>
					<option value="trash"><?php esc_html_e( 'Move to Trash', 'submission-inbox' ); ?></option>
				<?php endif; ?>
			</select></label>
			<select name="folder_id" data-subin-bulk-target="folder" hidden><option value="0"><?php esc_html_e( 'Unfiled', 'submission-inbox' ); ?></option><?php foreach ( $folders as $folder ) : ?><option value="<?php echo esc_attr( (string) absint( $folder['id'] ?? 0 ) ); ?>"><?php echo esc_html( $folder['name'] ?? '' ); ?></option><?php endforeach; ?></select>
			<select name="tag_id" data-subin-bulk-target="tag" hidden><option value="0"><?php esc_html_e( 'Choose tag', 'submission-inbox' ); ?></option><?php foreach ( $tags as $tag ) : ?><option value="<?php echo esc_attr( (string) absint( $tag['id'] ?? 0 ) ); ?>"><?php echo esc_html( $tag['name'] ?? '' ); ?></option><?php endforeach; ?></select>
			<button type="submit" class="button subin-btn" data-subin-bulk-submit disabled><?php esc_html_e( 'Apply', 'submission-inbox' ); ?></button>
			<span class="subin-forms-bulk__count" aria-live="polite" data-subin-selected-count><?php esc_html_e( '0 selected', 'submission-inbox' ); ?></span>
			<?php if ( $is_trash && $can_delete ) : ?><span class="subin-forms-bulk__retention-note"><?php esc_html_e( 'Permanent deletion removes the form setup. Saved leads and email history remain.', 'submission-inbox' ); ?></span><?php endif; ?>
		</form>
		<?php
	}

	/**
	 * Render the compact forms table and expandable details.
	 *
	 * @param array<int,array<string,mixed>> $forms Forms.
	 * @param array<string,mixed>            $filters Filters.
	 * @return void
	 */
	private function render_forms_table( array $forms, array $filters ) {
		?>
		<div class="subin-forms-table-wrap">
		<table class="subin-forms-table">
			<thead><tr><th class="subin-forms-table__check"><input type="checkbox" data-subin-select-all aria-label="<?php esc_attr_e( 'Select all forms on this page', 'submission-inbox' ); ?>" /></th><th><?php esc_html_e( 'Form', 'submission-inbox' ); ?></th><th><?php esc_html_e( 'Performance', 'submission-inbox' ); ?></th><th><?php esc_html_e( 'Inbox', 'submission-inbox' ); ?></th><th><?php esc_html_e( 'Delivery', 'submission-inbox' ); ?></th><th><?php esc_html_e( 'Health', 'submission-inbox' ); ?></th><th><?php esc_html_e( 'Updated', 'submission-inbox' ); ?></th><th><span class="screen-reader-text"><?php esc_html_e( 'Actions', 'submission-inbox' ); ?></span></th></tr></thead>
			<tbody>
			<?php foreach ( $forms as $form ) : ?>
				<?php $this->render_form_row( $form, $filters ); ?>
			<?php endforeach; ?>
			</tbody>
		</table>
		</div>
		<?php
	}

	/** Render one form row plus details. */
	private function render_form_row( array $form, array $filters ) {
		$form_id     = absint( $form['id'] ?? 0 );
		$status      = sanitize_key( $form['status'] ?? '' );
		$is_trash    = \SUBIN\Forms\FormRepository::STATUS_TRASHED === $status;
		$period_key  = $filters['period'] . 'd';
		$funnel      = $form['analytics'][ $period_key ] ?? $this->empty_funnel();
		$health      = sanitize_key( $form['health']['status'] ?? 'healthy' );
		$issues      = (array) ( $form['health']['issues'] ?? array() );
		$details_id  = 'subin-form-details-' . $form_id;
		$folder      = $form['organization']['folder'] ?? null;
		$tags        = (array) ( $form['organization']['tags'] ?? array() );
		$last_submit = $form['leads']['last_submission'] ?? '';
		?>
		<tr class="subin-form-portfolio-row subin-form-portfolio-row--<?php echo esc_attr( $health ); ?>">
			<?php /* translators: %s: form title. */ ?>
			<td class="subin-forms-table__check"><input type="checkbox" name="form_ids[]" value="<?php echo esc_attr( (string) $form_id ); ?>" form="subin-forms-bulk" data-subin-form-select aria-label="<?php echo esc_attr( sprintf( __( 'Select %s', 'submission-inbox' ), $form['title'] ?? '' ) ); ?>" /></td>
			<td class="subin-form-cell">
				<div class="subin-form-cell__title">
					<?php if ( $is_trash ) : ?><span class="subin-form-name"><?php echo esc_html( $form['title'] ?? __( 'Untitled form', 'submission-inbox' ) ); ?></span><?php else : ?><a href="<?php echo esc_url( $this->edit_url( $form_id ) ); ?>"><?php echo esc_html( $form['title'] ?? __( 'Untitled form', 'submission-inbox' ) ); ?></a><?php endif; ?>
					<?php $this->render_status_badge( $status ); ?><?php if ( ! empty( $form['publishing']['is_dirty'] ) ) : ?><span class="subin-draft-dot" title="<?php esc_attr_e( 'Unpublished changes', 'submission-inbox' ); ?>"></span><?php endif; ?>
				</div>
				<div class="subin-form-cell__meta"><span>#<?php echo esc_html( (string) $form_id ); ?></span><span><?php echo esc_html( $form['slug'] ?? '' ); ?></span><?php if ( is_array( $folder ) ) : ?><span class="subin-folder-chip"><span class="dashicons dashicons-category" aria-hidden="true"></span><?php echo esc_html( $folder['name'] ?? '' ); ?></span><?php endif; ?><?php $this->render_auto_reply_status( (array) ( $form['auto_reply'] ?? array() ), $form_id ); ?></div>
				<?php if ( ! empty( $tags ) ) : ?><div class="subin-form-tags"><?php foreach ( array_slice( $tags, 0, 3 ) as $tag ) : ?><span><?php echo esc_html( $tag['name'] ?? '' ); ?></span><?php endforeach; ?></div><?php endif; ?>
			</td>
			<?php /* translators: %1$s: localized form-view count, %2$s: localized submission count. */ ?>
			<td><div class="subin-metric-primary"><?php echo esc_html( number_format_i18n( (float) ( $funnel['conversion_rate'] ?? 0 ), 1 ) ); ?>%</div><div class="subin-metric-secondary"><?php echo esc_html( sprintf( __( '%1$s views · %2$s submits', 'submission-inbox' ), number_format_i18n( absint( $funnel['views'] ?? 0 ) ), number_format_i18n( absint( $funnel['submissions'] ?? 0 ) ) ) ); ?></div></td>
			<?php /* translators: %d: number of unseen leads for the form. */ ?>
			<td><a class="subin-metric-link" href="<?php echo esc_url( $this->inbox_url( $form_id ) ); ?>"><strong><?php echo esc_html( number_format_i18n( absint( $form['leads']['total'] ?? 0 ) ) ); ?></strong><?php if ( absint( $form['leads']['unread'] ?? 0 ) > 0 ) : ?><span><?php echo esc_html( sprintf( __( '%d unseen', 'submission-inbox' ), absint( $form['leads']['unread'] ) ) ); ?></span><?php else : ?><span><?php esc_html_e( 'All reviewed', 'submission-inbox' ); ?></span><?php endif; ?></a><?php if ( $last_submit ) : ?><small><?php echo esc_html( $this->relative_date( $last_submit ) ); ?></small><?php endif; ?></td>
			<td><?php $this->render_delivery_cell( $form, $form_id, $filters['period'] ); ?></td>
			<td><?php $this->render_health_cell( $health, $issues, $form_id, $filters['period'] ); ?></td>
			<td class="subin-updated-cell"><span><?php echo esc_html( $this->relative_date( $form['updated_at'] ?? '' ) ); ?></span><small><?php echo esc_html( $this->format_date( $form['updated_at'] ?? '' ) ); ?></small></td>
			<td class="subin-row-actions"><div class="subin-row-actions__group"><?php $this->render_primary_row_action( $form_id, $is_trash ); ?><button type="button" class="button subin-icon-button" data-subin-toggle-details aria-expanded="false" aria-controls="<?php echo esc_attr( $details_id ); ?>" title="<?php esc_attr_e( 'Open details', 'submission-inbox' ); ?>"><span class="dashicons dashicons-arrow-down-alt2" aria-hidden="true"></span></button><?php $this->render_more_menu( $form_id, $status ); ?></div></td>
		</tr>
		<tr id="<?php echo esc_attr( $details_id ); ?>" class="subin-form-details-row" hidden><td colspan="8"><?php $this->render_form_details( $form, $funnel, $filters ); ?></td></tr>
		<?php
	}

	/** Render delivery signal cell. */
	private function render_delivery_cell( array $form, $form_id, $period ) {
		$failed = absint( $form['email']['period_failed'] ?? $form['email']['failed_period'] ?? 0 );
		$total  = absint( $form['email']['period_total'] ?? 0 );
		$rate   = $form['email']['period_failure_rate'] ?? null;
		if ( $failed > 0 ) {
			/* translators: %d: number of failed email events. */
			?><a class="subin-delivery-state subin-delivery-state--failed" href="<?php echo esc_url( $this->email_log_url( $form_id, 'failed', $period ) ); ?>"><strong><?php echo esc_html( sprintf( _n( '%d failed', '%d failed', $failed, 'submission-inbox' ), $failed ) ); ?></strong><span><?php echo null === $rate ? esc_html__( 'Needs investigation', 'submission-inbox' ) : esc_html( number_format_i18n( (float) $rate, 1 ) . '% ' . __( 'failure rate', 'submission-inbox' ) ); ?></span></a><?php
		} elseif ( $total > 0 ) {
			/* translators: %d: total number of email events. */
			?><a class="subin-delivery-state subin-delivery-state--healthy" href="<?php echo esc_url( $this->email_log_url( $form_id, '', $period ) ); ?>"><strong><?php esc_html_e( 'Healthy', 'submission-inbox' ); ?></strong><span><?php echo esc_html( sprintf( __( '%d email events', 'submission-inbox' ), $total ) ); ?></span></a><?php
		} else {
			?><span class="subin-delivery-state subin-delivery-state--empty"><strong><?php esc_html_e( 'No events', 'submission-inbox' ); ?></strong><span><?php esc_html_e( 'Waiting for submissions', 'submission-inbox' ); ?></span></span><?php
		}
	}

	/** Render a compact policy status without duplicating delivery history. */
	private function render_auto_reply_status( array $summary, $form_id ) {
		$active    = absint( $summary['active_count'] ?? 0 );
		$attention = absint( $summary['attention_count'] ?? 0 );
		$state     = 'off';
		$label     = __( 'Auto-reply: Off', 'submission-inbox' );

		if ( $attention > 0 ) {
			$state = 'attention';
			$label = __( 'Auto-reply: Needs attention', 'submission-inbox' );
		} elseif ( 1 === $active ) {
			$state = 'active';
			$label = __( 'Auto-reply: 1 active', 'submission-inbox' );
		} elseif ( $active > 1 ) {
			$state = 'active';
			$label = sprintf(
				/* translators: %d: Number of active auto-reply rules. */
				__( 'Auto-reply: %d active', 'submission-inbox' ),
				$active
			);
		} elseif ( absint( $summary['draft_count'] ?? 0 ) > 0 ) {
			$state = 'draft';
			$label = __( 'Auto-reply: Draft', 'submission-inbox' );
		}

		?>
		<a class="subin-auto-reply-chip subin-auto-reply-chip--<?php echo esc_attr( $state ); ?>" href="<?php echo esc_url( $this->auto_reply_url( $form_id ) ); ?>" title="<?php esc_attr_e( 'Manage this form’s auto-reply rules', 'submission-inbox' ); ?>"><?php echo esc_html( $label ); ?></a>
		<?php
	}

	/** Render health badge and primary issue. */
	private function render_health_cell( $health, array $issues, $form_id, $period ) {
		$labels = array( 'healthy' => __( 'Healthy', 'submission-inbox' ), 'attention' => __( 'Attention', 'submission-inbox' ), 'critical' => __( 'Critical', 'submission-inbox' ) );
		?><a class="subin-health-link" href="<?php echo esc_url( $this->email_health_url( $form_id, $period ) ); ?>" title="<?php esc_attr_e( 'Open form-scoped Email Health', 'submission-inbox' ); ?>"><span class="subin-health-pill subin-health-pill--<?php echo esc_attr( $health ); ?>"><i aria-hidden="true"></i><?php echo esc_html( $labels[ $health ] ?? $labels['healthy'] ); ?><?php if ( count( $issues ) > 0 ) : ?><b><?php echo esc_html( (string) count( $issues ) ); ?></b><?php endif; ?></span></a><?php
		if ( ! empty( $issues[0]['title'] ) ) {
			echo '<small class="subin-health-primary">' . esc_html( $issues[0]['title'] ) . '</small>';
		}
	}

	/** Render status badge. */
	private function render_status_badge( $status ) {
		$labels = array( 'active' => __( 'Active', 'submission-inbox' ), 'inactive' => __( 'Inactive', 'submission-inbox' ), 'trash' => __( 'Trashed', 'submission-inbox' ) );
		echo '<span class="subin-form-status subin-form-status--' . esc_attr( sanitize_html_class( $status ) ) . '">' . esc_html( $labels[ $status ] ?? ucfirst( $status ) ) . '</span>';
	}

	/** Render row overflow menu. */
	private function render_more_menu( $form_id, $status ) {
		$is_trash   = \SUBIN\Forms\FormRepository::STATUS_TRASHED === $status;
		$can_delete = \SUBIN\Security\Capabilities::can_current_user( \SUBIN\Security\Capabilities::DELETE_FORMS );
		?>
		<details class="subin-row-menu"><summary class="button subin-icon-button" title="<?php esc_attr_e( 'More actions', 'submission-inbox' ); ?>"><span class="dashicons dashicons-ellipsis" aria-hidden="true"></span></summary><div class="subin-row-menu__popover">
			<?php if ( ! $is_trash ) : ?><a href="<?php echo esc_url( $this->preview_url( $form_id ) ); ?>"><span class="dashicons dashicons-visibility"></span><?php esc_html_e( 'Preview', 'submission-inbox' ); ?></a><a href="<?php echo esc_url( $this->edit_url( $form_id, 'settings' ) ); ?>"><span class="dashicons dashicons-admin-generic"></span><?php esc_html_e( 'Settings', 'submission-inbox' ); ?></a><?php $this->render_action_form( 'duplicate', $form_id, __( 'Duplicate', 'submission-inbox' ), 'dashicons-admin-page' ); ?><?php $this->render_action_form( 'active' === $status ? 'deactivate' : 'activate', $form_id, 'active' === $status ? __( 'Deactivate', 'submission-inbox' ) : __( 'Activate', 'submission-inbox' ), 'dashicons-controls-pause' ); ?><?php $this->render_action_form( 'trash', $form_id, __( 'Move to Trash', 'submission-inbox' ), 'dashicons-trash', true ); ?>
			<?php else : ?><?php $this->render_action_form( 'restore', $form_id, __( 'Restore as inactive', 'submission-inbox' ), 'dashicons-undo' ); ?><?php if ( $can_delete ) : ?><?php $this->render_action_form( 'delete_permanently', $form_id, __( 'Delete permanently', 'submission-inbox' ), 'dashicons-dismiss', true, true ); ?><?php endif; ?><?php endif; ?>
		</div></details>
		<?php
	}

	/** Render the row's primary edit or restore action. */
	private function render_primary_row_action( $form_id, $is_trash ) {
		if ( ! $is_trash ) {
			echo '<a class="button subin-btn subin-btn-primary" href="' . esc_url( $this->edit_url( $form_id ) ) . '">' . esc_html__( 'Edit', 'submission-inbox' ) . '</a>';
			return;
		}
		?>
		<form class="subin-row-primary-action" method="post" action=""><input type="hidden" name="subin_forms_action" value="restore" /><input type="hidden" name="form_ids[]" value="<?php echo esc_attr( (string) $form_id ); ?>" /><?php wp_nonce_field( self::NONCE_ACTION, self::NONCE_NAME ); ?><button type="submit" class="button subin-btn"><?php esc_html_e( 'Restore', 'submission-inbox' ); ?></button></form>
		<?php
	}

	/** Render a compact row command form. */
	private function render_action_form( $action, $form_id, $label, $icon, $danger = false, $permanent = false ) {
		?>
		<form method="post" action=""<?php echo $danger ? ' class="is-danger"' : ''; ?><?php echo $permanent ? ' onsubmit="return confirm(\'' . esc_js( __( 'Delete this form permanently? Saved leads and email history will remain, and already scheduled emails may still be sent.', 'submission-inbox' ) ) . '\');"' : ''; ?>><input type="hidden" name="subin_forms_action" value="<?php echo esc_attr( $action ); ?>" /><input type="hidden" name="form_ids[]" value="<?php echo esc_attr( (string) $form_id ); ?>" /><?php wp_nonce_field( self::NONCE_ACTION, self::NONCE_NAME ); ?><button type="submit"><span class="dashicons <?php echo esc_attr( $icon ); ?>"></span><?php echo esc_html( $label ); ?></button></form>
		<?php
	}

	/** Render the expanded operational and performance details. */
	private function render_form_details( array $form, array $funnel, array $filters ) {
		$form_id   = absint( $form['id'] ?? 0 );
		$issues    = (array) ( $form['health']['issues'] ?? array() );
		$locations = (array) ( $form['locations']['locations'] ?? array() );
		$shortcode = '[submission_inbox_form id="' . $form_id . '"]';
		?>
		<div class="subin-form-details-grid">
			<?php /* translators: %d: number of days in the conversion reporting period. */ ?>
			<section class="subin-form-detail-panel subin-form-detail-panel--funnel"><div class="subin-form-detail-panel__heading"><h3><?php echo esc_html( sprintf( __( 'Conversion funnel · %dd', 'submission-inbox' ), $filters['period'] ) ); ?></h3><span><?php esc_html_e( 'Anonymous, cookie-free events', 'submission-inbox' ); ?></span></div><div class="subin-funnel"><div><strong><?php echo esc_html( number_format_i18n( absint( $funnel['views'] ?? 0 ) ) ); ?></strong><span><?php esc_html_e( 'Views', 'submission-inbox' ); ?></span></div><i>→</i><div><strong><?php echo esc_html( number_format_i18n( absint( $funnel['starts'] ?? 0 ) ) ); ?></strong><span><?php esc_html_e( 'Starts', 'submission-inbox' ); ?></span></div><i>→</i><div><strong><?php echo esc_html( number_format_i18n( absint( $funnel['interactions'] ?? 0 ) ) ); ?></strong><span><?php esc_html_e( 'Interactions', 'submission-inbox' ); ?></span></div><i>→</i><div><strong><?php echo esc_html( number_format_i18n( absint( $funnel['submissions'] ?? 0 ) ) ); ?></strong><span><?php esc_html_e( 'Submits', 'submission-inbox' ); ?></span></div></div><div class="subin-funnel-rates"><span><strong><?php echo esc_html( number_format_i18n( (float) ( $funnel['start_rate'] ?? 0 ), 1 ) ); ?>%</strong><?php esc_html_e( 'start rate', 'submission-inbox' ); ?></span><span><strong><?php echo esc_html( number_format_i18n( (float) ( $funnel['completion_rate'] ?? 0 ), 1 ) ); ?>%</strong><?php esc_html_e( 'completion', 'submission-inbox' ); ?></span><span><strong><?php echo esc_html( number_format_i18n( (float) ( $funnel['conversion_rate'] ?? 0 ), 1 ) ); ?>%</strong><?php esc_html_e( 'conversion', 'submission-inbox' ); ?></span></div></section>
			<section class="subin-form-detail-panel"><div class="subin-form-detail-panel__heading"><h3><?php esc_html_e( 'Inbox operations', 'submission-inbox' ); ?></h3><a href="<?php echo esc_url( $this->inbox_url( $form_id ) ); ?>"><?php esc_html_e( 'Open Inbox', 'submission-inbox' ); ?></a></div><dl class="subin-operation-stats"><div><dt><?php esc_html_e( 'Open pipeline', 'submission-inbox' ); ?></dt><dd><?php echo esc_html( number_format_i18n( absint( $form['leads']['open_pipeline'] ?? 0 ) ) ); ?></dd></div><div><dt><?php esc_html_e( 'Unassigned', 'submission-inbox' ); ?></dt><dd><?php echo esc_html( number_format_i18n( absint( $form['leads']['unassigned_count'] ?? 0 ) ) ); ?></dd></div><div><dt><?php esc_html_e( 'Overdue follow-up', 'submission-inbox' ); ?></dt><dd><?php echo esc_html( number_format_i18n( absint( $form['leads']['overdue_follow_up'] ?? 0 ) ) ); ?></dd></div><div><dt><?php esc_html_e( 'Won', 'submission-inbox' ); ?></dt><dd><?php echo esc_html( number_format_i18n( absint( $form['leads']['workflow_won'] ?? 0 ) ) ); ?></dd></div></dl></section>
			<?php /* translators: %d: number of form-readiness issues. */ ?>
			<section class="subin-form-detail-panel"><div class="subin-form-detail-panel__heading"><h3><?php esc_html_e( 'Readiness', 'submission-inbox' ); ?></h3><span><?php echo esc_html( sprintf( _n( '%d issue', '%d issues', count( $issues ), 'submission-inbox' ), count( $issues ) ) ); ?></span></div><?php if ( empty( $issues ) ) : ?><div class="subin-all-clear"><span class="dashicons dashicons-yes-alt"></span><div><strong><?php esc_html_e( 'Ready to collect leads', 'submission-inbox' ); ?></strong><span><?php esc_html_e( 'No form-level issues were detected.', 'submission-inbox' ); ?></span></div></div><?php else : ?><ul class="subin-issue-list"><?php foreach ( $issues as $issue ) : ?><li class="subin-issue-list__item subin-issue-list__item--<?php echo esc_attr( sanitize_html_class( $issue['severity'] ?? 'warning' ) ); ?>"><span class="dashicons dashicons-warning"></span><div><strong><?php echo esc_html( $issue['title'] ?? '' ); ?></strong><span><?php echo esc_html( $issue['message'] ?? '' ); ?></span><a href="<?php echo esc_url( $this->issue_url( $issue['action']['key'] ?? '', $form_id, $filters['period'], absint( $form['auto_reply']['rule_id'] ?? 0 ) ) ); ?>"><?php echo esc_html( $issue['action']['label'] ?? __( 'Fix issue', 'submission-inbox' ) ); ?></a></div></li><?php endforeach; ?></ul><?php endif; ?></section>
			<?php /* translators: %d: number of pages or posts where the form is embedded. */ ?>
			<section class="subin-form-detail-panel"><div class="subin-form-detail-panel__heading"><h3><?php esc_html_e( 'Placement & embed', 'submission-inbox' ); ?></h3><span><?php echo esc_html( sprintf( _n( '%d location', '%d locations', count( $locations ), 'submission-inbox' ), count( $locations ) ) ); ?></span></div><div class="subin-shortcode-compact"><code><?php echo esc_html( $shortcode ); ?></code><button type="button" class="button subin-copy-shortcode" data-subin-copy="<?php echo esc_attr( $shortcode ); ?>"><?php esc_html_e( 'Copy', 'submission-inbox' ); ?></button><span class="subin-copy-feedback" aria-live="polite"></span></div><?php if ( empty( $locations ) ) : ?><p class="subin-orphaned-message"><span class="dashicons dashicons-location-alt"></span><?php esc_html_e( 'Not found on a published page yet.', 'submission-inbox' ); ?></p><?php else : ?><ul class="subin-location-list"><?php foreach ( array_slice( $locations, 0, 4 ) as $location ) : ?><li><span class="dashicons dashicons-admin-page"></span><div><a href="<?php echo esc_url( $location['url'] ?? '' ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html( $location['title'] ?? '' ); ?></a><small><?php echo esc_html( ucfirst( $location['type'] ?? 'page' ) ); ?></small></div><?php if ( ! empty( $location['edit_url'] ) ) : ?><a href="<?php echo esc_url( $location['edit_url'] ); ?>"><?php esc_html_e( 'Edit page', 'submission-inbox' ); ?></a><?php endif; ?></li><?php endforeach; ?></ul><?php endif; ?></section>
		</div>
		<?php
	}

	/** Render empty state for either a new install or filters. */
	private function render_empty_state( $all_total, array $filters ) {
		if ( $all_total <= 0 ) {
			SUBIN_View::empty_state( __( 'Create your first form', 'submission-inbox' ), __( 'Start from a template, publish it, and this workspace will track readiness, leads, and conversion.', 'submission-inbox' ) );
			echo '<p class="subin-empty-state-action"><a class="button button-primary subin-btn subin-btn-primary" href="' . esc_url( $this->templates_url() ) . '">' . esc_html__( 'Browse templates', 'submission-inbox' ) . '</a></p>';
			return;
		}
		SUBIN_View::empty_state( __( 'No forms match these filters', 'submission-inbox' ), __( 'Clear one or more filters to return to the full form portfolio.', 'submission-inbox' ) );
		echo '<p class="subin-empty-state-action"><a class="button subin-btn" href="' . esc_url( admin_url( 'admin.php?page=submission-inbox-forms' ) ) . '">' . esc_html__( 'Clear filters', 'submission-inbox' ) . '</a></p>';
	}

	/** Render pagination. */
	private function render_pagination( $total, array $filters ) {
		$total_pages = max( 1, (int) ceil( absint( $total ) / self::PER_PAGE ) );
		if ( $total_pages <= 1 ) {
			return;
		}
		/* translators: %1$d: current page number, %2$d: total number of pages. */
		echo '<nav class="subin-pagination" aria-label="' . esc_attr__( 'Forms pagination', 'submission-inbox' ) . '"><span class="subin-pagination__info">' . esc_html( sprintf( __( 'Page %1$d of %2$d', 'submission-inbox' ), $filters['paged'], $total_pages ) ) . '</span><div class="subin-pagination__links">';
		echo wp_kses_post( paginate_links( array( 'base' => add_query_arg( 'paged', '%#%', $this->list_url( $filters ) ), 'format' => '', 'current' => $filters['paged'], 'total' => $total_pages, 'prev_text' => __( 'Previous', 'submission-inbox' ), 'next_text' => __( 'Next', 'submission-inbox' ) ) ) );
		echo '</div></nav>';
	}

	/** Explain the intentional relationship between portfolio and diagnostics. */
	private function render_diagnostic_guide() {
		?>
		<div class="subin-diagnostic-guide"><div><span class="dashicons dashicons-forms"></span><strong><?php esc_html_e( 'Forms', 'submission-inbox' ); ?></strong><small><?php esc_html_e( 'Spot which form needs action', 'submission-inbox' ); ?></small></div><i>→</i><a href="<?php echo esc_url( admin_url( 'admin.php?page=subin-email-status' ) ); ?>"><span class="dashicons dashicons-heart"></span><strong><?php esc_html_e( 'Email Health', 'submission-inbox' ); ?></strong><small><?php esc_html_e( 'Understand delivery patterns and causes', 'submission-inbox' ); ?></small></a><i>→</i><a href="<?php echo esc_url( admin_url( 'admin.php?page=subin-email-log' ) ); ?>"><span class="dashicons dashicons-list-view"></span><strong><?php esc_html_e( 'Email Log', 'submission-inbox' ); ?></strong><small><?php esc_html_e( 'Inspect an exact email event', 'submission-inbox' ); ?></small></a></div>
		<?php
	}

	/** Render notices. */
	private function render_notice() {
		$key = SUBIN_Request::get_key( 'subin_notice' );
		$messages = array(
			'folder_created' => array( 'success', __( 'Folder created.', 'submission-inbox' ) ), 'tag_created' => array( 'success', __( 'Tag created.', 'submission-inbox' ) ), 'forms_organized' => array( 'success', __( 'Form organization updated.', 'submission-inbox' ) ), 'command_completed' => array( 'success', __( 'Selected forms were updated.', 'submission-inbox' ) ), 'command_partially_completed' => array( 'warning', __( 'Some selected forms could not be updated.', 'submission-inbox' ) ), 'forms_not_selected' => array( 'warning', __( 'Select at least one form.', 'submission-inbox' ) ), 'organization_failed' => array( 'error', __( 'Folder or tag changes could not be saved.', 'submission-inbox' ) ), 'command_failed' => array( 'error', __( 'The selected action could not be completed.', 'submission-inbox' ) ), 'security_failed' => array( 'error', __( 'Security check failed. Please try again.', 'submission-inbox' ) ),
		);
		if ( empty( $messages[ $key ] ) ) {
			return;
		}
		echo '<div class="notice notice-' . esc_attr( $messages[ $key ][0] ) . ' is-dismissible"><p>' . esc_html( $messages[ $key ][1] ) . '</p></div>';
	}

	/** Redirect after a command. */
	private function redirect( $notice ) {
		$fallback = admin_url( 'admin.php?page=submission-inbox-forms' );
		$target   = wp_get_referer();
		if ( ! $target || false === strpos( $target, 'page=submission-inbox-forms' ) ) {
			$target = $fallback;
		}
		$target = remove_query_arg( array( 'subin_notice', '_wpnonce', self::NONCE_NAME ), $target );
		wp_safe_redirect( add_query_arg( 'subin_notice', sanitize_key( $notice ), $target ) );
		exit;
	}

	/** Build a list URL preserving filters. */
	private function list_url( array $filters, array $overrides = array() ) {
		$values = array_merge( $filters, $overrides );
		$args   = array_filter( array(
			'page' => 'submission-inbox-forms', 's' => $values['search'] ?? '', 'subin_form_state' => ( $values['state'] ?? 'all' ) !== 'all' ? $values['state'] : '', 'subin_health' => $values['health'] ?? '', 'subin_folder' => $values['folder'] ?? '', 'subin_tag' => absint( $values['tag'] ?? 0 ), 'subin_period' => absint( $values['period'] ?? 30 ) !== 30 ? absint( $values['period'] ) : '', 'subin_sort' => ( $values['sort'] ?? 'updated' ) !== 'updated' ? $values['sort'] : '', 'subin_order' => ( $values['order'] ?? 'desc' ) !== 'desc' ? $values['order'] : '', 'paged' => absint( $values['paged'] ?? 1 ) > 1 ? absint( $values['paged'] ) : '',
		), function ( $value ) { return '' !== (string) $value && 0 !== $value; } );
		$args['page'] = 'submission-inbox-forms';
		return add_query_arg( $args, admin_url( 'admin.php' ) );
	}

	/** Build issue action URL. */
	private function issue_url( $action, $form_id, $period, $rule_id = 0 ) {
		if ( 'view_email_log' === $action ) {
			return $this->email_log_url( $form_id, 'failed', $period );
		}
		if ( 'manage_auto_reply' === $action ) {
			unset( $rule_id );
			return $this->auto_reply_url( $form_id );
		}
		if ( in_array( $action, array( 'edit_settings', 'edit_notification' ), true ) ) {
			return $this->edit_url( $form_id, 'settings' );
		}
		return $this->edit_url( $form_id );
	}

	/** Auto-replies list filtered to one built-in form. */
	private function auto_reply_url( $form_id ) {
		return add_query_arg(
			array(
				'page'                   => 'submission-inbox-auto-replies',
				'subin_auto_replies_tab' => 'rules',
				'provider'               => 'submission_inbox_form',
				'form_id'                => absint( $form_id ),
			),
			admin_url( 'admin.php' )
		);
	}

	/** Built-in form editor URL. */
	private function edit_url( $form_id, $tab = 'design_studio' ) {
		$args = array( 'page' => 'submission-inbox-forms', 'view' => 'edit', 'form_id' => absint( $form_id ) );
		if ( 'design_studio' !== $tab ) {
			$args['tab'] = sanitize_key( $tab );
		}
		return add_query_arg( $args, admin_url( 'admin.php' ) );
	}

	/** Preview URL. */
	private function preview_url( $form_id ) {
		return add_query_arg( array( 'page' => 'submission-inbox-forms', 'view' => 'preview', 'form_id' => absint( $form_id ) ), admin_url( 'admin.php' ) );
	}

	/** Templates URL. */
	private function templates_url() {
		return add_query_arg( array( 'page' => 'submission-inbox-forms', 'view' => 'templates' ), admin_url( 'admin.php' ) );
	}

	/** Filtered Inbox URL. */
	private function inbox_url( $form_id ) {
		return add_query_arg( array( 'page' => 'subin-inbox', 'subin_provider' => 'submission_inbox_form', 'subin_form_id' => 'submission_inbox_form|' . absint( $form_id ) ), admin_url( 'admin.php' ) );
	}

	/** Filtered Email Health URL. */
	private function email_health_url( $form_id, $period = 30 ) {
		return add_query_arg( array( 'page' => 'subin-email-status', 'subin_source' => 'submission_inbox_form', 'subin_form_id' => absint( $form_id ), 'subin_date_range' => in_array( absint( $period ), array( 7, 30 ), true ) ? absint( $period ) : 30 ), admin_url( 'admin.php' ) );
	}

	/** Filtered Email Log URL. */
	private function email_log_url( $form_id, $status = '', $period = 30 ) {
		return add_query_arg( array_filter( array( 'page' => 'subin-email-log', 'subin_source' => 'submission_inbox_form', 'subin_form_id' => absint( $form_id ), 'subin_status' => sanitize_key( $status ), 'subin_date_range' => in_array( absint( $period ), array( 7, 30 ), true ) ? absint( $period ) : 30 ) ), admin_url( 'admin.php' ) );
	}

	/** Human-friendly date. */
	private function relative_date( $date ) {
		$datetime = $this->parse_local_datetime( $date );
		if ( ! $datetime ) {
			return __( 'Never', 'submission-inbox' );
		}
		/* translators: %s: human-readable time elapsed since the form event. */
		return sprintf( __( '%s ago', 'submission-inbox' ), human_time_diff( $datetime->getTimestamp(), current_datetime()->getTimestamp() ) );
	}

	/** Formatted local date. */
	private function format_date( $date ) {
		$datetime = $this->parse_local_datetime( $date );
		if ( ! $datetime ) {
			return '';
		}
		return wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $datetime->getTimestamp(), wp_timezone() );
	}

	/** Parse a local WordPress MySQL datetime without applying the timezone twice. */
	private function parse_local_datetime( $date ) {
		$value = trim( (string) $date );
		if ( '' === $value ) {
			return null;
		}
		try {
			return new \DateTimeImmutable( $value, wp_timezone() );
		} catch ( \Exception $exception ) {
			return null;
		}
	}

	/** Empty analytics funnel. */
	private function empty_funnel() {
		return array( 'views' => 0, 'starts' => 0, 'interactions' => 0, 'submissions' => 0, 'start_rate' => 0.0, 'completion_rate' => 0.0, 'conversion_rate' => 0.0 );
	}
}
