<?php
/**
 * Server-rendered Schema Health editor panel.
 *
 * @package SEOvaultSEO\Admin
 */

namespace SEOvaultSEO\Admin;

use SEOvaultSEO\Schema\Validation\SchemaHealthStatus;
use SEOvaultSEO\Schema\Validation\SchemaHealthStatusPresenter;
use SEOvaultSEO\Schema\Validation\SchemaValidationFeatures;
use SEOvaultSEO\Schema\Validation\Severity;
use SEOvaultSEO\Schema\Validation\ValidationIssuePresenter;

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

/**
 * Renders the compact Schema Health sidebar summary.
 *
 * Detailed issue cards and live comparison belong in the Review schema surface.
 */
class SchemaHealthPanel {

	/**
	 * Render the compact default sidebar panel.
	 *
	 * @param array      $validation Post validation response.
	 * @param array|null $live       Optional published-page validation response (kept for AJAX callers; not shown in the compact sidebar).
	 * @return string
	 */
	public static function render( $validation, $live = null ) {
		$validation    = is_array( $validation ) ? $validation : array();
		$presenter     = new SchemaHealthStatusPresenter();
		$published     = $presenter->present_published( $validation );
		$setup         = $presenter->present_setup( $validation );
		$editable      = $presenter->present_editable_entities( $validation );
		$local_enabled = SchemaValidationFeatures::is_enabled( SchemaValidationFeatures::LOCAL );
		$live_enabled  = SchemaValidationFeatures::is_enabled( SchemaValidationFeatures::LIVE );
		$status        = $published['status'];
		$top_actions   = array_slice( is_array( $published['actions'] ) ? $published['actions'] : array(), 0, 3 );
		$setup_count   = isset( $setup['count'] ) ? (int) $setup['count'] : 0;
		$post_id       = isset( $validation['post_id'] ) ? absint( $validation['post_id'] ) : 0;

		/*
		 * $live remains in the signature for MetaBox/AJAX callers. Compact sidebar
		 * intentionally omits the live subsection (Review schema surface owns it).
		 */
		if ( null !== $live && ! is_array( $live ) ) {
			$live = null;
		}

		$buffer_level = ob_get_level();
		ob_start();
		try {
			?>
		<section
			class="seovaultseo-schema-health seovaultseo-schema-health-compact seovaultseo-schema-health-<?php echo esc_attr( $status ); ?>"
			id="seovaultseo-schema-health"
			data-schema-health-state="<?php echo esc_attr( $status ); ?>"
			data-schema-health-internal-state="<?php echo esc_attr( isset( $validation['state'] ) ? (string) $validation['state'] : '' ); ?>"
			aria-labelledby="seovaultseo-schema-health-title"
		>
			<div class="seovaultseo-schema-health-status" role="status" aria-live="polite">
				<h3 id="seovaultseo-schema-health-title"><?php esc_html_e( 'Schema Health', 'seovault-ai' ); ?></h3>
				<p class="seovaultseo-schema-health-state">
					<span class="seovaultseo-schema-health-icon" aria-hidden="true"><?php echo esc_html( $published['icon'] ); ?></span>
					<strong class="seovaultseo-schema-health-label"><?php echo esc_html( $published['label'] ); ?></strong>
				</p>
				<?php if ( '' !== $published['entities_summary'] ) : ?>
					<p class="seovaultseo-schema-health-entities">
						<span class="screen-reader-text"><?php esc_html_e( 'Emitted schema:', 'seovault-ai' ); ?></span>
						<?php echo esc_html( $published['entities_summary'] ); ?>
					</p>
				<?php endif; ?>
				<?php echo self::render_editable_entities( $editable['items'], $post_id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Helper escapes. ?>
				<?php if ( empty( $top_actions ) ) : ?>
					<p class="seovaultseo-schema-health-summary"><?php echo esc_html( $published['summary'] ); ?></p>
				<?php else : ?>
					<ol class="seovaultseo-schema-health-top-actions">
						<?php foreach ( $top_actions as $action ) : ?>
							<li><?php echo esc_html( (string) $action ); ?></li>
						<?php endforeach; ?>
					</ol>
				<?php endif; ?>
				<p class="seovaultseo-schema-health-scope"><?php echo esc_html( $published['scope'] ); ?></p>
			</div>

			<?php echo self::render_setup_list( $setup['items'], $setup_count, $post_id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Helper escapes. ?>
			<?php
			$suggestions = isset( $validation['content_suggestions']['suggestions'] ) && is_array( $validation['content_suggestions']['suggestions'] )
				? $validation['content_suggestions']['suggestions']
				: array();
			$suggestion_hash = isset( $validation['content_suggestions']['content_hash'] )
				? (string) $validation['content_suggestions']['content_hash']
				: '';
			echo self::render_content_suggestions( $suggestions, $suggestion_hash, $post_id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Helper escapes.
			?>

			<div class="seovaultseo-schema-health-actions">
				<?php if ( $local_enabled ) : ?>
					<button type="button" class="button button-secondary seovaultseo-schema-health-check">
						<?php esc_html_e( 'Check schema', 'seovault-ai' ); ?>
					</button>
				<?php endif; ?>
				<?php if ( $live_enabled ) : ?>
					<button type="button" class="button button-secondary seovaultseo-schema-health-live-check">
						<?php esc_html_e( 'Check published page', 'seovault-ai' ); ?>
					</button>
				<?php endif; ?>
				<button type="button" class="button button-secondary seovaultseo-schema-health-add" aria-haspopup="dialog" aria-controls="seovaultseo-schema-add-picker" aria-expanded="false">
					<?php esc_html_e( 'Add schema', 'seovault-ai' ); ?>
				</button>
				<button type="button" class="button button-primary seovaultseo-schema-health-review" aria-haspopup="dialog" aria-controls="seovaultseo-schema-review">
					<?php esc_html_e( 'Review schema', 'seovault-ai' ); ?>
				</button>
			</div>

			<div class="seovaultseo-schema-health-request-error" role="alert" hidden></div>

			<p class="seovaultseo-schema-health-limitation">
				<?php esc_html_e( 'Uses SEOvault’s bundled local rules. This does not guarantee a Google rich result.', 'seovault-ai' ); ?>
			</p>
		</section>
			<?php

			return (string) ob_get_clean();
		} finally {
			while ( ob_get_level() > $buffer_level ) {
				ob_end_clean();
			}
		}
	}

	/**
	 * Render content-to-block suggestions. Suggestions never emit schema.
	 *
	 * @param array  $suggestions Suggestion rows.
	 * @param string $content_hash Content hash for dismiss/confirm.
	 * @param int    $post_id      Post ID.
	 * @return string
	 */
	public static function render_content_suggestions( array $suggestions, $content_hash = '', $post_id = 0 ) {
		if ( empty( $suggestions ) ) {
			return '';
		}
		unset( $post_id );

		$buffer_level = ob_get_level();
		ob_start();
		try {
			?>
		<div
			class="seovaultseo-schema-content-suggestions"
			data-content-hash="<?php echo esc_attr( (string) $content_hash ); ?>"
			data-suggestion-count="<?php echo (int) count( $suggestions ); ?>"
		>
			<h4 class="seovaultseo-schema-content-suggestions-heading"><?php esc_html_e( 'Suggested blocks', 'seovault-ai' ); ?></h4>
			<p class="seovaultseo-schema-content-suggestions-intro description">
				<?php esc_html_e( 'Optional conversions. Schema does not change until you review and confirm a block.', 'seovault-ai' ); ?>
			</p>
			<ul class="seovaultseo-schema-content-suggestions-list">
				<?php foreach ( $suggestions as $item ) : ?>
					<?php if ( ! is_array( $item ) ) { continue; } ?>
					<li
						class="seovaultseo-schema-content-suggestion"
						data-suggestion-id="<?php echo esc_attr( (string) ( $item['id'] ?? '' ) ); ?>"
						data-suggestion-kind="<?php echo esc_attr( (string) ( $item['kind'] ?? '' ) ); ?>"
						data-suggestion-block="<?php echo esc_attr( (string) ( $item['block_name'] ?? '' ) ); ?>"
						data-suggestion-type="<?php echo esc_attr( (string) ( $item['type_label'] ?? '' ) ); ?>"
						data-suggestion-confidence="<?php echo esc_attr( (string) ( $item['confidence'] ?? '' ) ); ?>"
					>
						<script type="application/json" class="seovaultseo-schema-content-suggestion-payload"><?php echo wp_json_encode( $item, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Encoded JSON payload. ?></script>
						<p class="seovaultseo-schema-content-suggestion-title">
							<strong><?php echo esc_html( (string) ( $item['summary'] ?? '' ) ); ?></strong>
							<span class="seovaultseo-schema-health-setup-badge"><?php echo esc_html( (string) ( $item['confidence'] ?? '' ) ); ?></span>
						</p>
						<p class="seovaultseo-schema-content-suggestion-reason"><?php echo esc_html( (string) ( $item['reason'] ?? '' ) ); ?></p>
						<?php if ( ! empty( $item['preview'] ) && is_array( $item['preview'] ) ) : ?>
							<ul class="seovaultseo-schema-content-suggestion-preview">
								<?php foreach ( array_slice( $item['preview'], 0, 3 ) as $row ) : ?>
									<?php if ( ! is_array( $row ) ) { continue; } ?>
									<li>
										<strong><?php echo esc_html( (string) ( $row['label'] ?? '' ) ); ?></strong>
										<span><?php echo esc_html( wp_html_excerpt( (string) ( $row['detail'] ?? '' ), 80, '…' ) ); ?></span>
									</li>
								<?php endforeach; ?>
							</ul>
						<?php endif; ?>
						<p class="seovaultseo-schema-content-suggestion-actions">
							<button type="button" class="button button-small button-primary seovaultseo-schema-content-suggestion-review">
								<?php esc_html_e( 'Review & confirm', 'seovault-ai' ); ?>
							</button>
							<button type="button" class="button-link seovaultseo-schema-content-suggestion-dismiss">
								<?php esc_html_e( 'Dismiss', 'seovault-ai' ); ?>
							</button>
						</p>
					</li>
				<?php endforeach; ?>
			</ul>
		</div>
			<?php

			return (string) ob_get_clean();
		} finally {
			while ( ob_get_level() > $buffer_level ) {
				ob_end_clean();
			}
		}
	}

	/**
	 * Persistent suggestion review dialog (outside replaceable health panel HTML).
	 *
	 * @return string
	 */
	public static function render_suggestion_dialog_shell() {
		$buffer_level = ob_get_level();
		ob_start();
		try {
			?>
		<dialog
			id="seovaultseo-schema-content-suggestion-dialog"
			class="seovaultseo-schema-content-suggestion-dialog"
			aria-modal="true"
			aria-labelledby="seovaultseo-schema-content-suggestion-dialog-title"
		>
			<div class="seovaultseo-schema-content-suggestion-dialog-chrome">
				<header>
					<h2 id="seovaultseo-schema-content-suggestion-dialog-title"><?php esc_html_e( 'Review suggested block', 'seovault-ai' ); ?></h2>
					<button type="button" class="button-link seovaultseo-schema-content-suggestion-dialog-close" aria-label="<?php esc_attr_e( 'Close', 'seovault-ai' ); ?>">&times;</button>
				</header>
				<div class="seovaultseo-schema-content-suggestion-dialog-body" data-suggestion-dialog-body tabindex="-1"></div>
				<footer>
					<button type="button" class="button button-secondary seovaultseo-schema-content-suggestion-dialog-close"><?php esc_html_e( 'Cancel', 'seovault-ai' ); ?></button>
					<button type="button" class="button button-primary seovaultseo-schema-content-suggestion-confirm"><?php esc_html_e( 'Create block', 'seovault-ai' ); ?></button>
				</footer>
			</div>
		</dialog>
			<?php

			return (string) ob_get_clean();
		} finally {
			while ( ob_get_level() > $buffer_level ) {
				ob_end_clean();
			}
		}
	}

	/**
	 * Persistent polite live region for Schema Health status announcements.
	 *
	 * @return string
	 */
	public static function render_announcer() {
		return '<div id="seovaultseo-schema-health-announcer" class="screen-reader-text" role="status" aria-live="polite" aria-atomic="true"></div>';
	}

	/**
	 * Render unfinished setup rows with Complete / Remove actions.
	 *
	 * @param array $items      Presented setup items.
	 * @param int   $setup_count Count.
	 * @param int   $post_id     Post ID for no-JS links.
	 * @return string
	 */
	public static function render_setup_list( array $items, $setup_count, $post_id = 0 ) {
		if ( $setup_count <= 0 || empty( $items ) ) {
			return '';
		}

		$buffer_level = ob_get_level();
		ob_start();
		try {
			?>
		<div class="seovaultseo-schema-health-setup" data-setup-count="<?php echo (int) $setup_count; ?>">
			<h4 class="seovaultseo-schema-health-setup-heading"><?php esc_html_e( 'Unfinished setup', 'seovault-ai' ); ?></h4>
			<p class="seovaultseo-schema-health-setup-count">
				<?php
				echo esc_html(
					sprintf(
						/* translators: %d: unfinished schema setup item count. */
						_n( '%d unfinished setup item', '%d unfinished setup items', $setup_count, 'seovault-ai' ),
						$setup_count
					)
				);
				?>
			</p>
			<ul class="seovaultseo-schema-health-setup-list">
				<?php foreach ( $items as $item ) : ?>
					<?php if ( ! is_array( $item ) ) { continue; } ?>
					<li
						class="seovaultseo-schema-health-setup-item"
						data-schema-type="<?php echo esc_attr( (string) ( $item['type'] ?? '' ) ); ?>"
						data-instance-id="<?php echo esc_attr( (string) ( $item['instance_id'] ?? '' ) ); ?>"
						data-focus-field="<?php echo esc_attr( (string) ( $item['first_field_key'] ?? '' ) ); ?>"
						data-setup-status="<?php echo esc_attr( (string) ( $item['status'] ?? '' ) ); ?>"
						data-source="<?php echo esc_attr( (string) ( $item['source'] ?? '' ) ); ?>"
					>
						<p class="seovaultseo-schema-health-setup-item-title">
							<strong><?php echo esc_html( (string) ( $item['type'] ?? '' ) ); ?></strong>
							<span class="seovaultseo-schema-health-setup-badge"><?php echo esc_html( (string) ( $item['status_label'] ?? '' ) ); ?></span>
							<?php if ( ! empty( $item['source_label'] ) ) : ?>
								<span class="seovaultseo-schema-source-label"><?php echo esc_html( (string) $item['source_label'] ); ?></span>
							<?php endif; ?>
						</p>
						<p class="seovaultseo-schema-health-setup-item-summary"><?php echo esc_html( (string) ( $item['summary'] ?? '' ) ); ?></p>
						<?php if ( ! empty( $item['editable'] ) || ! empty( $item['removable'] ) || ! empty( $item['action'] ) ) : ?>
							<p class="seovaultseo-schema-health-setup-item-actions">
								<?php if ( ! empty( $item['editable'] ) ) : ?>
									<?php echo self::render_setup_action_control( 'complete', $item, $post_id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
								<?php elseif ( ! empty( $item['action'] ) && 'focus_custom_json' === $item['action'] ) : ?>
									<button type="button" class="button-link seovaultseo-schema-setup-complete" data-schema-setup-action="focus_custom_json">
										<?php esc_html_e( 'Complete', 'seovault-ai' ); ?>
									</button>
								<?php endif; ?>
								<?php if ( ! empty( $item['removable'] ) ) : ?>
									<?php echo self::render_setup_action_control( 'remove', $item, $post_id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
								<?php endif; ?>
							</p>
						<?php endif; ?>
					</li>
				<?php endforeach; ?>
			</ul>
		</div>
			<?php

			return (string) ob_get_clean();
		} finally {
			while ( ob_get_level() > $buffer_level ) {
				ob_end_clean();
			}
		}
	}

	/**
	 * Render ready guided entities with Edit actions.
	 *
	 * @param array $items   Editable entity rows.
	 * @param int   $post_id Post ID.
	 * @return string
	 */
	public static function render_editable_entities( array $items, $post_id = 0 ) {
		if ( empty( $items ) ) {
			return '';
		}

		$buffer_level = ob_get_level();
		ob_start();
		try {
			?>
		<ul class="seovaultseo-schema-health-entity-list" aria-label="<?php esc_attr_e( 'Editable schema entities', 'seovault-ai' ); ?>">
			<?php foreach ( $items as $item ) : ?>
				<?php if ( ! is_array( $item ) ) { continue; } ?>
				<li
					class="seovaultseo-schema-health-entity-item"
					data-schema-type="<?php echo esc_attr( (string) ( $item['type'] ?? '' ) ); ?>"
					data-instance-id="<?php echo esc_attr( (string) ( $item['instance_id'] ?? '' ) ); ?>"
					data-source="<?php echo esc_attr( (string) ( $item['source'] ?? '' ) ); ?>"
				>
					<span class="seovaultseo-schema-health-entity-type"><?php echo esc_html( (string) ( $item['type'] ?? '' ) ); ?></span>
					<?php if ( ! empty( $item['source_label'] ) ) : ?>
						<span class="seovaultseo-schema-source-label"><?php echo esc_html( (string) $item['source_label'] ); ?></span>
					<?php endif; ?>
					<?php echo self::render_setup_action_control( 'edit', $item, $post_id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
				</li>
			<?php endforeach; ?>
		</ul>
			<?php

			return (string) ob_get_clean();
		} finally {
			while ( ob_get_level() > $buffer_level ) {
				ob_end_clean();
			}
		}
	}

	/**
	 * Button + no-JS fallback link for setup/entity actions.
	 *
	 * @param string $action complete|remove|edit.
	 * @param array  $item   Presented row.
	 * @param int    $post_id Post ID.
	 * @return string
	 */
	private static function render_setup_action_control( $action, array $item, $post_id ) {
		$instance_id = (string) ( $item['instance_id'] ?? '' );
		$type        = (string) ( $item['type'] ?? '' );
		$focus       = (string) ( $item['first_field_key'] ?? '' );
		$labels      = array(
			'complete' => __( 'Complete', 'seovault-ai' ),
			'remove'   => __( 'Remove', 'seovault-ai' ),
			'edit'     => __( 'Edit', 'seovault-ai' ),
		);
		$label = isset( $labels[ $action ] ) ? $labels[ $action ] : $labels['complete'];
		$class = 'edit' === $action
			? 'button-link seovaultseo-schema-entity-edit'
			: ( 'remove' === $action ? 'button-link seovaultseo-schema-setup-remove' : 'button-link seovaultseo-schema-setup-complete' );

		$fallback = '';
		if ( $post_id > 0 && '' !== $instance_id ) {
			$args = array(
				'seovault_schema_instance' => $instance_id,
				'seovault_schema_action'   => $action,
				'seovault_schema_nonce'    => wp_create_nonce( MetaBox::schema_setup_nonce_action( $post_id ) ),
			);
			if ( '' !== $focus && 'complete' === $action ) {
				$args['seovault_schema_focus'] = $focus;
			}
			$url = add_query_arg( $args, get_edit_post_link( $post_id, 'raw' ) );
			if ( is_string( $url ) && '' !== $url ) {
				$fallback = sprintf(
					'<a class="seovaultseo-schema-setup-fallback" href="%1$s#seovaultseo-schema-guided-form">%2$s</a>',
					esc_url( $url ),
					esc_html( $label )
				);
			}
		}

		$buffer_level = ob_get_level();
		ob_start();
		try {
			?>
		<button
			type="button"
			class="<?php echo esc_attr( $class ); ?>"
			data-schema-setup-action="<?php echo esc_attr( $action ); ?>"
			data-instance-id="<?php echo esc_attr( $instance_id ); ?>"
			data-schema-type="<?php echo esc_attr( $type ); ?>"
			data-focus-field="<?php echo esc_attr( $focus ); ?>"
		>
			<?php echo esc_html( $label ); ?>
		</button>
			<?php
			if ( '' !== $fallback ) {
				echo '<noscript>' . $fallback . '</noscript>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Built with esc_url/esc_html.
			}

			return (string) ob_get_clean();
		} finally {
			while ( ob_get_level() > $buffer_level ) {
				ob_end_clean();
			}
		}
	}

	/**
	 * Render the published-page comparison subsection (Review schema surface).
	 *
	 * @param array|null $live Live validation response.
	 * @return string
	 */
	public static function render_live_section( $live ) {
		$copy = ( new SchemaHealthStatusPresenter() )->present_live( $live );

		$buffer_level = ob_get_level();
		ob_start();
		try {
			?>
		<section
			class="seovaultseo-schema-health-live seovaultseo-schema-health-live-<?php echo esc_attr( $copy['status'] ); ?>"
			id="seovaultseo-schema-health-live"
			data-schema-live-state="<?php echo esc_attr( $copy['state'] ); ?>"
			aria-labelledby="seovaultseo-schema-health-live-title"
		>
			<h4 id="seovaultseo-schema-health-live-title"><?php esc_html_e( 'Published-page schema', 'seovault-ai' ); ?></h4>
			<p class="seovaultseo-schema-health-live-state" role="status" aria-live="polite">
				<span class="seovaultseo-schema-health-icon" aria-hidden="true"><?php echo esc_html( $copy['icon'] ); ?></span>
				<strong><?php echo esc_html( $copy['label'] ); ?></strong>
			</p>
			<p class="seovaultseo-schema-health-live-summary"><?php echo esc_html( $copy['summary'] ); ?></p>
			<?php if ( ! empty( $copy['details'] ) ) : ?>
				<ul class="seovaultseo-schema-health-live-details">
					<?php foreach ( $copy['details'] as $detail ) : ?>
						<li><?php echo esc_html( $detail ); ?></li>
					<?php endforeach; ?>
				</ul>
			<?php endif; ?>
		</section>
			<?php

			return (string) ob_get_clean();
		} finally {
			while ( ob_get_level() > $buffer_level ) {
				ob_end_clean();
			}
		}
	}

	/**
	 * Render issues grouped by severity for the Review schema surface.
	 *
	 * Paths and codes stay behind a technical-details disclosure.
	 *
	 * @param array $issues Exported validation issues.
	 * @return string
	 */
	public static function render_details( $issues ) {
		$presenter = new ValidationIssuePresenter();
		$groups    = array(
			Severity::ERROR          => array(),
			Severity::WARNING        => array(),
			Severity::RECOMMENDATION => array(),
			Severity::INFO           => array(),
		);

		foreach ( $issues as $issue ) {
			if ( ! is_array( $issue ) ) {
				continue;
			}
			$presented = $presenter->present( $issue );
			$severity  = $presented['severity'];
			if ( ! isset( $groups[ $severity ] ) ) {
				$severity = Severity::INFO;
			}
			$groups[ $severity ][] = $presented;
		}

		$buffer_level = ob_get_level();
		ob_start();
		try {
			?>
		<div class="seovaultseo-schema-health-details-panel">
			<?php
			foreach ( $groups as $severity => $group ) :
				if ( empty( $group ) ) {
					continue;
				}
				$group_class = Severity::RECOMMENDATION === $severity
					? 'seovaultseo-schema-health-group-recommendation'
					: 'seovaultseo-schema-health-group-' . $severity;
				?>
				<section class="seovaultseo-schema-health-group <?php echo esc_attr( $group_class ); ?>">
					<h4>
						<?php echo esc_html( $group[0]['severity_label'] ); ?>
						<span class="seovaultseo-schema-health-group-count">(<?php echo (int) count( $group ); ?>)</span>
					</h4>
					<ul>
						<?php foreach ( $group as $issue ) : ?>
							<li class="seovaultseo-schema-health-issue-row">
								<article class="seovaultseo-schema-health-issue">
									<header class="seovaultseo-schema-health-issue-summary">
										<span class="seovaultseo-schema-health-issue-icon" aria-hidden="true"><?php echo esc_html( self::get_severity_icon( $severity ) ); ?></span>
										<span class="seovaultseo-schema-health-issue-title-text"><?php echo esc_html( $issue['title'] ); ?></span>
										<span class="seovaultseo-schema-health-issue-hint">
											<?php echo esc_html( $issue['entity_type'] ); ?>
										</span>
									</header>
									<div class="seovaultseo-schema-health-issue-body">
										<p><?php echo esc_html( $issue['message'] ); ?></p>
										<p class="seovaultseo-schema-health-action">
											<strong><?php esc_html_e( 'Suggested action:', 'seovault-ai' ); ?></strong>
											<?php echo esc_html( $issue['action'] ); ?>
										</p>
										<?php if ( ! empty( $issue['is_plugin_fault'] ) && ! empty( $issue['repair_actions'] ) ) : ?>
											<ul class="seovaultseo-schema-health-repair-actions">
												<?php foreach ( $issue['repair_actions'] as $repair ) : ?>
													<li><?php echo esc_html( $repair ); ?></li>
												<?php endforeach; ?>
											</ul>
										<?php endif; ?>
										<?php if ( ! empty( $issue['learn_more_url'] ) ) : ?>
											<p class="seovaultseo-schema-health-learn-more">
												<a href="<?php echo esc_url( $issue['learn_more_url'] ); ?>" target="_blank" rel="noopener noreferrer">
													<?php esc_html_e( 'Learn more', 'seovault-ai' ); ?>
												</a>
											</p>
										<?php endif; ?>
										<details class="seovaultseo-schema-health-technical">
											<summary><?php esc_html_e( 'Technical details', 'seovault-ai' ); ?></summary>
											<dl>
												<div>
													<dt><?php esc_html_e( 'Entity', 'seovault-ai' ); ?></dt>
													<dd><?php echo esc_html( $issue['entity_type'] ); ?></dd>
												</div>
												<?php if ( '' !== $issue['code'] ) : ?>
													<div>
														<dt><?php esc_html_e( 'Code', 'seovault-ai' ); ?></dt>
														<dd><code><?php echo esc_html( $issue['code'] ); ?></code></dd>
													</div>
												<?php endif; ?>
												<?php if ( '' !== $issue['path'] ) : ?>
													<div>
														<dt><?php esc_html_e( 'Path', 'seovault-ai' ); ?></dt>
														<dd><code><?php echo esc_html( $issue['path'] ); ?></code></dd>
													</div>
												<?php endif; ?>
											</dl>
										</details>
									</div>
								</article>
							</li>
						<?php endforeach; ?>
					</ul>
				</section>
				<?php
			endforeach;
			?>
		</div>
			<?php

			return (string) ob_get_clean();
		} finally {
			while ( ob_get_level() > $buffer_level ) {
				ob_end_clean();
			}
		}
	}

	/**
	 * Get a visible, non-color severity indicator.
	 *
	 * @param string $severity Severity.
	 * @return string
	 */
	private static function get_severity_icon( $severity ) {
		if ( Severity::ERROR === $severity ) {
			return '×';
		}
		if ( Severity::WARNING === $severity ) {
			return '!';
		}
		if ( Severity::RECOMMENDATION === $severity ) {
			return '●';
		}

		return 'i';
	}
}
