<?php
namespace Bookaro\Controller\Admin;

defined( 'ABSPATH' ) || exit;

// phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.DB.SlowDBQuery.slow_db_query_meta_key, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Read-only diagnostics page: request reads are sanitized status params with no state change; integrity-scan SELECTs target custom plugin tables ($wpdb->prefix, joined to core tables) and bind values via prepare(); meta_key lookups are bounded one-off checks.

use Bookaro\Repository\BookingRepository;
use Bookaro\Repository\OptionRepository;
use Bookaro\Utils\AdminLaneSummary;
use Bookaro\Utils\TemplateLoader;
use Bookaro\Utils\GenericPresetProfiles;

/**
 * System status page for Bookaro.
 */
class SystemStatusController
{
    private BookingRepository $db;
    private OptionRepository $options;

    public function __construct( BookingRepository $db, OptionRepository $options )
    {
        $this->db = $db;
        $this->options = $options;
    }

    public static function get_support_touchpoint_urls(): array
    {
        $system_status_url = admin_url( 'admin.php?page=bookaro-system-status' );

        return [
            'system_status_url' => $system_status_url,
            'support_snapshot_url' => $system_status_url . '#bookaro-support-snapshot',
            'support_bundle_url' => $system_status_url . '#bookaro-support-bundle',
            'generic_validation_url' => $system_status_url . '#bookaro-support-check-generic_validation_provider_resolution_sample',
        ];
    }

    private function admin_menu_capability(): string
    {
        return function_exists( 'bookaro_get_admin_menu_capability' )
            ? bookaro_get_admin_menu_capability()
            : 'manage_options';
    }

    private function can_manage_admin(): bool
    {
        if ( function_exists( 'bookaro_current_user_can_manage_admin' ) ) {
            return bookaro_current_user_can_manage_admin();
        }
        return current_user_can( 'manage_options' );
    }

    public function register_hooks(): void
    {
        add_action( 'admin_menu', [ $this, 'add_submenu_page' ], 27 );
        add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
        // Bug 56: on bookaro admin screens, warn site owners when
        // DISABLE_WP_CRON=true is set. The plugin schedules five recurring
        // / single-event jobs (auto_complete, send_reminder,
        // send_review_invite, notification_log_cleanup, logfile_cleanup) and
        // without WP-Cron firing them, reminders silently never go out and
        // approved bookings stay "approved" forever. The existing
        // system-status pill is too quiet — sites discover this only when a
        // customer complains.
        add_action( 'admin_notices', [ $this, 'maybe_show_wp_cron_notice' ] );
    }

    /**
     * Bug 56: render a dismissable notice when DISABLE_WP_CRON is set.
     * Restricted to bookaro admin screens to avoid noise on the rest of
     * wp-admin.
     */
    public function maybe_show_wp_cron_notice(): void
    {
        if ( ! defined( 'DISABLE_WP_CRON' ) || ! DISABLE_WP_CRON ) {
            return;
        }
        if ( ! current_user_can( $this->admin_menu_capability() ) ) {
            return;
        }
        $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
        if ( $screen && ! empty( $screen->id ) && strpos( (string) $screen->id, 'bookaro' ) === false ) {
            return;
        }
        $status_url = admin_url( 'admin.php?page=bookaro-system-status' );
        $msg = sprintf(
            /* translators: %s: link to bookaro system status */
            esc_html__( 'MyBookaro: %1$sWP-Cron is disabled%2$s on this site. Booking reminders, auto-complete, and review invites will never fire until system cron is configured, or until you run %3$swp bookaro cron-run%4$s manually.', 'mybookaro' ),
            '<strong>',
            '</strong>',
            '<code>',
            '</code>'
        );
        echo '<div class="notice notice-warning"><p>' . wp_kses(
            $msg,
            [ 'strong' => [], 'code' => [] ]
        ) . ' <a href="' . esc_url( $status_url ) . '">' . esc_html__( 'Open System Status', 'mybookaro' ) . '</a></p></div>';
    }

    public function add_submenu_page(): void
    {
        add_submenu_page(
            'bookaro-bookings',
            __( 'System Status', 'mybookaro' ),
            __( 'System Status', 'mybookaro' ),
            $this->admin_menu_capability(),
            'bookaro-system-status',
            [ $this, 'render_page' ]
        );
    }

    public function enqueue_assets( string $hook ): void
    {
        $is_page = ( 'bookaro-bookings_page_bookaro-system-status' === $hook );
        if ( ! $is_page && function_exists( 'get_current_screen' ) ) {
            $screen = get_current_screen();
            if ( $screen && ! empty( $screen->id ) ) {
                $is_page = ( 'bookaro-bookings_page_bookaro-system-status' === $screen->id );
            }
        }
        if ( ! $is_page ) {
            $page = sanitize_key( wp_unslash( $_GET['page'] ?? '' ) );
            $is_page = ( 'bookaro-system-status' === $page );
        }
        if ( ! $is_page ) {
            return;
        }

        $rel = 'assets/css/admin-settings.css';
        $path = plugin_dir_path( BOOKARO_PLUGIN_FILE ) . $rel;
        $ver = file_exists( $path ) ? (string) filemtime( $path ) : BOOKARO_VERSION;
        $url = plugins_url( $rel, BOOKARO_PLUGIN_FILE );
        wp_enqueue_style( 'bookaro-admin-settings', $url, [], $ver );

        // Copy / select / download behavior for the support report, JSON, and
        // bundle controls. Previously printed as an inline script element in the
        // template; now attached as inline JS on a dedicated, src-less admin
        // script handle scoped to this page, with translated labels passed via
        // wp_localize_script().
        $handle = 'bookaro-system-status';
        if ( ! wp_script_is( $handle, 'registered' ) ) {
            wp_register_script( $handle, false, [], BOOKARO_VERSION, true );
        }
        wp_enqueue_script( $handle );
        wp_localize_script(
            $handle,
            'bookaroSystemStatusL10n',
            [
                'copied'                => __( 'Copied.', 'mybookaro' ),
                'ticketStarterCopied'   => __( 'Ticket starter copied.', 'mybookaro' ),
                'supportSnapshotCopied' => __( 'Support snapshot copied.', 'mybookaro' ),
                'subjectCopied'         => __( 'Subject copied.', 'mybookaro' ),
                'bundleCopied'          => __( 'Support bundle copied.', 'mybookaro' ),
                'launchSummaryAndReportCopied' => __( 'Launch summary + report copied.', 'mybookaro' ),
                'selectedForCopy'       => __( 'Selected. Press Ctrl+C (or Cmd+C) to copy.', 'mybookaro' ),
                'failed'                => __( 'Copy failed.', 'mybookaro' ),
            ]
        );
        wp_add_inline_script( $handle, $this->build_system_status_inline_script() );
    }

    /**
     * Build the system-status page JavaScript (copy / select / download wiring).
     * Translated labels are read from the localized bookaroSystemStatusL10n
     * object provided via wp_localize_script() in enqueue_assets().
     */
    private function build_system_status_inline_script(): string
    {
        return <<<'JS'
document.addEventListener('DOMContentLoaded', function() {
    var L10n = window.bookaroSystemStatusL10n || {};
    var supportShareButton = document.getElementById('bookaro-copy-support-share-summary');
    var supportShareSelectButton = document.getElementById('bookaro-select-support-share-summary');
    var supportShareTextarea = document.getElementById('bookaro-support-share-summary');
    var supportShareStatus = document.getElementById('bookaro-copy-support-share-summary-status');
    var reportButton = document.getElementById('bookaro-copy-report');
    var reportTextarea = document.getElementById('bookaro-system-report');
    var reportStatus = document.getElementById('bookaro-copy-status');
    var launchHandoffMessageButton = document.getElementById('bookaro-copy-launch-handoff-message');
    var launchHandoffMessageSelectButton = document.getElementById('bookaro-select-launch-handoff-message');
    var launchHandoffSubjectButton = document.getElementById('bookaro-copy-launch-handoff-subject');
    var launchHandoffSubjectField = document.getElementById('bookaro-launch-handoff-subject');
    var launchHandoffMessageTextarea = document.getElementById('bookaro-launch-handoff-message');
    var launchHandoffMessageStatus = document.getElementById('bookaro-copy-launch-handoff-message-status');
    var launchQuickSummaryButton = document.getElementById('bookaro-copy-launch-quick-summary');
    var launchQuickSummarySelectButton = document.getElementById('bookaro-select-launch-quick-summary');
    var launchQuickSummaryTextarea = document.getElementById('bookaro-launch-blocker-quick-summary');
    var launchQuickSummaryStatus = document.getElementById('bookaro-copy-launch-quick-summary-status');
    var launchSummaryButton = document.getElementById('bookaro-copy-launch-summary');
    var launchSummarySelectButton = document.getElementById('bookaro-select-launch-summary');
    var launchSummaryAndReportButton = document.getElementById('bookaro-copy-launch-summary-report');
    var launchSummaryTextarea = document.getElementById('bookaro-launch-blocker-summary');
    var launchSummaryStatus = document.getElementById('bookaro-copy-launch-summary-status');
    var jsonButton = document.getElementById('bookaro-copy-json');
    var jsonTextarea = document.getElementById('bookaro-system-report-json');
    var jsonStatus = document.getElementById('bookaro-copy-json-status');
    var jsonDownload = document.getElementById('bookaro-download-json');
    var bundleDownload = document.getElementById('bookaro-download-bundle');
    var bundleTextarea = document.getElementById('bookaro-system-report-bundle');
    var bundleCopyButtons = document.querySelectorAll('.bookaro-copy-bundle-button');
    var copiedText = L10n.copied || 'Copied.';
    var ticketStarterCopiedText = L10n.ticketStarterCopied || copiedText;
    var supportSnapshotCopiedText = L10n.supportSnapshotCopied || copiedText;
    var subjectCopiedText = L10n.subjectCopied || copiedText;
    var bundleCopiedText = L10n.bundleCopied || copiedText;
    var launchSummaryAndReportCopiedText = L10n.launchSummaryAndReportCopied || copiedText;
    var selectedForCopyText = L10n.selectedForCopy || '';
    var failedText = L10n.failed || 'Copy failed.';

    function setStatusText(statusEl, text) {
        if (!statusEl) {
            return;
        }
        statusEl.textContent = text;
    }

    function copyText(text, statusEl, successText) {
        var okText = successText || copiedText;
        if (navigator.clipboard && navigator.clipboard.writeText) {
            return navigator.clipboard.writeText(text).then(function() {
                setStatusText(statusEl, okText);
            }).catch(function() {
                setStatusText(statusEl, failedText);
            });
        }
        var textareaEl = document.createElement('textarea');
        textareaEl.value = text;
        textareaEl.style.position = 'fixed';
        textareaEl.style.opacity = '0';
        document.body.appendChild(textareaEl);
        textareaEl.select();
        var ok = false;
        try {
            ok = document.execCommand('copy');
        } catch (e) {
            ok = false;
        }
        document.body.removeChild(textareaEl);
        setStatusText(statusEl, ok ? okText : failedText);
        return Promise.resolve();
    }

    function selectTextArea(textareaEl, statusEl) {
        if (!textareaEl) {
            return;
        }
        textareaEl.focus();
        textareaEl.select();
        if (typeof textareaEl.setSelectionRange === 'function') {
            textareaEl.setSelectionRange(0, textareaEl.value.length);
        }
        setStatusText(statusEl, selectedForCopyText);
    }

    if (supportShareButton && supportShareTextarea && supportShareStatus) {
        supportShareButton.addEventListener('click', function() {
            copyText(supportShareTextarea.value, supportShareStatus, supportSnapshotCopiedText);
        });
    }

    if (supportShareSelectButton && supportShareTextarea && supportShareStatus) {
        supportShareSelectButton.addEventListener('click', function() {
            selectTextArea(supportShareTextarea, supportShareStatus);
        });
    }

    if (reportButton && reportTextarea && reportStatus) {
        reportButton.addEventListener('click', function() {
            copyText(reportTextarea.value, reportStatus);
        });
    }

    if (launchHandoffMessageButton && launchHandoffMessageTextarea && launchHandoffMessageStatus) {
        launchHandoffMessageButton.addEventListener('click', function() {
            copyText(launchHandoffMessageTextarea.value, launchHandoffMessageStatus, ticketStarterCopiedText);
        });
    }

    if (launchHandoffMessageSelectButton && launchHandoffMessageTextarea && launchHandoffMessageStatus) {
        launchHandoffMessageSelectButton.addEventListener('click', function() {
            selectTextArea(launchHandoffMessageTextarea, launchHandoffMessageStatus);
        });
    }

    if (launchHandoffSubjectButton && launchHandoffSubjectField && launchHandoffMessageStatus) {
        launchHandoffSubjectButton.addEventListener('click', function() {
            copyText(launchHandoffSubjectField.value || '', launchHandoffMessageStatus, subjectCopiedText);
        });
    }

    if (launchQuickSummaryButton && launchQuickSummaryTextarea && launchQuickSummaryStatus) {
        launchQuickSummaryButton.addEventListener('click', function() {
            copyText(launchQuickSummaryTextarea.value, launchQuickSummaryStatus);
        });
    }

    if (launchQuickSummarySelectButton && launchQuickSummaryTextarea && launchQuickSummaryStatus) {
        launchQuickSummarySelectButton.addEventListener('click', function() {
            selectTextArea(launchQuickSummaryTextarea, launchQuickSummaryStatus);
        });
    }

    if (launchSummaryButton && launchSummaryTextarea && launchSummaryStatus) {
        launchSummaryButton.addEventListener('click', function() {
            copyText(launchSummaryTextarea.value, launchSummaryStatus);
        });
    }

    if (launchSummarySelectButton && launchSummaryTextarea && launchSummaryStatus) {
        launchSummarySelectButton.addEventListener('click', function() {
            selectTextArea(launchSummaryTextarea, launchSummaryStatus);
        });
    }

    if (launchSummaryAndReportButton && launchSummaryTextarea && reportTextarea && launchSummaryStatus) {
        launchSummaryAndReportButton.addEventListener('click', function() {
            var combined = (launchSummaryTextarea.value || '') + '\n\n---\n\n' + (reportTextarea.value || '');
            copyText(combined, launchSummaryStatus, launchSummaryAndReportCopiedText);
        });
    }

    if (jsonButton && jsonTextarea && jsonStatus) {
        jsonButton.addEventListener('click', function() {
            copyText(jsonTextarea.value, jsonStatus);
        });
    }

    if (jsonDownload && jsonTextarea) {
        jsonDownload.addEventListener('click', function() {
            var blob = new Blob([jsonTextarea.value || ''], { type: 'application/json' });
            var url = window.URL.createObjectURL(blob);
            var link = document.createElement('a');
            link.href = url;
            link.download = 'mybookaro-system-status.json';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            window.URL.revokeObjectURL(url);
        });
    }

    if (bundleDownload && bundleTextarea) {
        bundleDownload.addEventListener('click', function() {
            var blob = new Blob([bundleTextarea.value || ''], { type: 'application/json' });
            var url = window.URL.createObjectURL(blob);
            var link = document.createElement('a');
            link.href = url;
            link.download = 'mybookaro-support-bundle.json';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            window.URL.revokeObjectURL(url);
        });
    }

    if (bundleTextarea && bundleCopyButtons.length) {
        bundleCopyButtons.forEach(function(buttonEl) {
            buttonEl.addEventListener('click', function() {
                var statusEl = buttonEl.parentElement
                    ? buttonEl.parentElement.querySelector('.bookaro-copy-bundle-status')
                    : null;
                copyText(bundleTextarea.value || '', statusEl, bundleCopiedText);
            });
        });
    }
});
JS;
    }

    public function render_page(): void
    {
        if ( ! $this->can_manage_admin() ) {
            wp_die( esc_html__( 'You do not have permission to access this page.', 'mybookaro' ) );
        }

        $db_status = $this->get_db_status();
        $cron_status = $this->get_cron_status();
        $api_status = $this->get_api_status();
        $integration_status = $this->get_integration_status();
        $environment_status = $this->get_environment_status();
        $license_status = $this->get_license_status();
        $settings_status = $this->get_settings_status();
        $dashboard_status = $this->get_dashboard_status();
        $generic_status = $this->get_generic_status();
        $services_cache_status = $this->get_services_cache_status();
        $orphan_status = $this->get_orphan_status();
        $opts = $this->options->get_all();
        $generic_validation_prompt = $this->get_generic_validation_prompt( $opts, $generic_status );
        $support_checks = $this->build_support_checks( $api_status, $integration_status, $dashboard_status, $generic_status, $orphan_status, $settings_status, $generic_validation_prompt );
        $launch_readiness = $this->build_launch_readiness_summary( $support_checks, $generic_status );
        $generic_readiness_summary = $this->build_generic_readiness_summary( $generic_status, $generic_validation_prompt, $launch_readiness );
        $support_share_summary = $this->build_support_share_summary( $launch_readiness );
        $launch_blocker_quick_summary = $this->build_launch_blocker_quick_summary( $launch_readiness );
        $launch_blocker_summary = $this->build_launch_blocker_summary( $launch_readiness );
        $launch_handoff_subject = $this->build_launch_handoff_subject( $launch_readiness );
        $launch_handoff_message = $this->build_launch_handoff_message( $launch_handoff_subject, $launch_blocker_quick_summary );
        $lane_summary = $this->build_lane_summary_banner( $generic_status, $launch_readiness, $generic_readiness_summary );
        $report = $this->build_report( $db_status, $cron_status, $api_status, $integration_status, $environment_status, $license_status, $settings_status, $dashboard_status, $generic_status, $services_cache_status, $support_checks, $launch_readiness );
        $export = $this->build_export_payload( $db_status, $cron_status, $api_status, $integration_status, $environment_status, $license_status, $settings_status, $dashboard_status, $generic_status, $services_cache_status, $support_checks, $orphan_status, $launch_readiness );
        $export_json = wp_json_encode( $export, JSON_PRETTY_PRINT );
        if ( ! is_string( $export_json ) ) {
            $export_json = '';
        }
        $support_bundle = [
            'generated_at' => date_i18n( 'c' ),
            'support_share_summary' => $support_share_summary,
            'launch_blocker_quick_summary' => $launch_blocker_quick_summary,
            'launch_blocker_summary' => $launch_blocker_summary,
            'launch_handoff_subject' => $launch_handoff_subject,
            'launch_handoff_message' => $launch_handoff_message,
            'report' => $report,
            'export' => $export,
        ];
        $support_bundle_json = wp_json_encode( $support_bundle, JSON_PRETTY_PRINT );
        if ( ! is_string( $support_bundle_json ) ) {
            $support_bundle_json = '';
        }

        TemplateLoader::render( 'admin/system-status.php', [
            'db_status' => $db_status,
            'cron_status' => $cron_status,
            'api_status' => $api_status,
            'integration_status' => $integration_status,
            'environment_status' => $environment_status,
            'license_status' => $license_status,
            'settings_status' => $settings_status,
            'dashboard_status' => $dashboard_status,
            'generic_status' => $generic_status,
            'services_cache_status' => $services_cache_status,
            'support_checks' => $support_checks,
            'launch_readiness' => $launch_readiness,
            'support_share_summary' => $support_share_summary,
            'launch_blocker_quick_summary' => $launch_blocker_quick_summary,
            'launch_blocker_summary' => $launch_blocker_summary,
            'launch_handoff_subject' => $launch_handoff_subject,
            'launch_handoff_message' => $launch_handoff_message,
            'report' => $report,
            'export_json' => $export_json,
            'support_bundle_json' => $support_bundle_json,
            'generic_validation_prompt' => $generic_validation_prompt,
            'generic_readiness_summary' => $generic_readiness_summary,
            'lane_summary' => $lane_summary,
        ] );

        $this->mark_generic_validation_reviewed( $opts, $generic_validation_prompt );
    }

    private function get_db_status(): array
    {
        $wpdb = $this->db->get_wpdb();
        $tables = [
            'bookings' => $this->db->get_table_name(),
            'availability' => $this->db->get_availability_table(),
            'timeslots' => $this->db->get_timeslot_table(),
            'exceptions' => $this->db->get_exceptions_table(),
            'notifications' => $this->db->get_notification_log_table(),
        ];
        $table_status = [];
        foreach ( $tables as $key => $table ) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $exists = $wpdb->get_var(
                $wpdb->prepare( 'SHOW TABLES LIKE %s', $table )
            );
            $table_status[ $key ] = (bool) $exists;
        }

        $installed = (int) get_option( 'bookaro_db_version', 0 );
        $expected = (int) BOOKARO_DB_VERSION;
        $schema_ok = ( $installed >= $expected );

        return [
            'tables' => $table_status,
            'schema_installed' => $installed,
            'schema_expected' => $expected,
            'schema_ok' => $schema_ok,
        ];
    }

    private function get_cron_status(): array
    {
        $wp_cron_disabled = defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON;
        $next_auto_complete = wp_next_scheduled( 'bookaro_auto_complete' );
        $status = [
            'wp_cron_disabled' => $wp_cron_disabled,
            'auto_complete_scheduled' => (bool) $next_auto_complete,
            'auto_complete_next' => $next_auto_complete ? (int) $next_auto_complete : 0,
        ];

        return $status;
    }

    private function get_api_status(): array
    {
        // Prefixed override filter for the REST probe; defaults to whether the
        // REST API is present. Actual reachability is verified by the loopback
        // probe below.
        $rest_enabled = (bool) apply_filters( 'bookaro_rest_enabled', function_exists( 'rest_url' ) );
        $rest_url = function_exists( 'rest_url' ) ? rest_url() : '';
        $rest_probe = $this->probe_http_access( $rest_url, 'GET', [
            'headers' => [ 'Accept' => 'application/json' ],
        ] );
        $rest_http_code = (int) ( $rest_probe['http_code'] ?? 0 );
        $rest_accessible = false;
        if ( $rest_enabled && $rest_url !== '' && empty( $rest_probe['error'] ) ) {
            if ( in_array( $rest_http_code, [ 401, 403 ], true ) ) {
                $rest_accessible = true;
            } elseif ( 200 === $rest_http_code ) {
                $payload = json_decode( (string) ( $rest_probe['body'] ?? '' ), true );
                $rest_accessible = is_array( $payload ) && (
                    array_key_exists( 'routes', $payload ) || array_key_exists( 'namespaces', $payload )
                );
            } elseif ( $rest_http_code > 0 && $rest_http_code < 400 ) {
                $rest_accessible = true;
            }
        }
        $rest_ok = ( $rest_enabled && $rest_url !== '' && $rest_accessible );

        $ajax_url = admin_url( 'admin-ajax.php' );
        $ajax_probe = $this->probe_http_access( $ajax_url, 'POST', [
            'body' => [
                'action' => 'bookaro_system_status_probe',
            ],
        ] );
        $ajax_http_code = (int) ( $ajax_probe['http_code'] ?? 0 );
        $ajax_accessible = $ajax_url !== ''
            && empty( $ajax_probe['error'] )
            && $ajax_http_code > 0
            && $ajax_http_code < 500;
        $ajax_ok = $ajax_accessible;

        return [
            'rest_enabled' => $rest_enabled,
            'rest_url' => $rest_url,
            'rest_url_masked' => $this->mask_url( $rest_url ),
            'rest_ok' => $rest_ok,
            'rest_http_code' => $rest_http_code,
            'rest_accessible' => $rest_accessible,
            'rest_access_error' => $this->mask_report_text( (string) ( $rest_probe['error'] ?? '' ) ),
            'ajax_url' => $ajax_url,
            'ajax_url_masked' => $this->mask_url( $ajax_url ),
            'ajax_ok' => $ajax_ok,
            'ajax_http_code' => $ajax_http_code,
            'ajax_accessible' => $ajax_accessible,
            'ajax_access_error' => $this->mask_report_text( (string) ( $ajax_probe['error'] ?? '' ) ),
        ];
    }

    private function get_integration_status(): array
    {
        $mylisting_detected = $this->is_mylisting_detected();
        $hook_registered = function_exists( 'has_action' )
            ? (bool) has_action( 'mylisting/single/sidebar/actions', 'bookaro_render_mylisting_booking_button' )
            : false;
        $hook_ok = $mylisting_detected && $hook_registered;

        $mylisting_class_raw = sanitize_key( (string) $this->options->get( 'mylisting_services_repeater_class', '' ) );
        $mylisting_class = $mylisting_class_raw;
        if ( $mylisting_class === '' ) {
            $mylisting_class = 'mybookaro_services';
        }
        $payments_enabled = function_exists( 'bookaro_get_option' )
            ? (bool) bookaro_get_option( 'payments_enabled', 0 )
            : false;
        $woocommerce_present = class_exists( 'WooCommerce' ) || defined( 'WC_VERSION' ) || function_exists( 'WC' );
        $woocommerce_required = $payments_enabled;
        $woocommerce_ok = $woocommerce_required ? $woocommerce_present : true;
        $mylisting_sample_listing_id = $this->get_mylisting_sample_listing_id();
        $mylisting_services_diagnostics = $this->get_mylisting_service_resolution_diagnostics( $mylisting_sample_listing_id );

        return [
            'mylisting_detected' => $mylisting_detected,
            'mylisting_hook_ok' => $hook_ok,
            'mylisting_repeater_class' => $mylisting_class,
            'mylisting_repeater_class_raw' => $mylisting_class_raw,
            'mylisting_repeater_class_configured' => $mylisting_class_raw !== '',
            'mylisting_sample_listing_id' => $mylisting_sample_listing_id,
            'mylisting_services_diagnostics' => $mylisting_services_diagnostics,
            'payments_enabled' => $payments_enabled,
            'woocommerce_present' => $woocommerce_present,
            'woocommerce_ok' => $woocommerce_ok,
        ];
    }

    private function get_mylisting_selected_listing_types(): array
    {
        $opts = $this->options->get_all();
        $selected = [];
        if ( ! empty( $opts['allowed_listing_post_types'] ) && is_array( $opts['allowed_listing_post_types'] ) ) {
            $selected = $opts['allowed_listing_post_types'];
        } elseif ( ! empty( $opts['listing_post_type'] ) ) {
            $selected = [ $opts['listing_post_type'] ];
        }

        $selected = array_values( array_unique( array_filter( array_map( 'sanitize_key', (array) $selected ) ) ) );
        if ( empty( $selected ) ) {
            $selected = [ 'job_listing' ];
        }

        return $selected;
    }

    private function get_mylisting_sample_listing_id(): int
    {
        if ( ! function_exists( 'get_posts' ) ) {
            return 0;
        }

        $listing_types = $this->get_mylisting_selected_listing_types();
        if ( empty( $listing_types ) ) {
            $listing_types = [ 'job_listing' ];
        }

        $posts = get_posts( [
            'post_type' => $listing_types,
            'post_status' => 'publish',
            'posts_per_page' => 1,
            'orderby' => 'date',
            'order' => 'DESC',
            'fields' => 'ids',
        ] );

        if ( ! is_array( $posts ) || empty( $posts ) ) {
            return 0;
        }

        return absint( $posts[0] );
    }

    private function get_mylisting_service_resolution_diagnostics( int $listing_id ): array
    {
        $listing_id = absint( $listing_id );
        $repeater_class = sanitize_key( (string) $this->options->get( 'mylisting_services_repeater_class', '' ) );
        if ( '' === $repeater_class ) {
            $repeater_class = 'mybookaro_services';
        }

        $defaults = [
            'listing_id' => $listing_id,
            'target_repeater_class' => $repeater_class,
            'reason_code' => $listing_id > 0 ? 'no_repeater_rows' : 'listing_not_selected',
            'resolution_path' => 'none',
            'status' => $listing_id > 0 ? 'warn' : 'info',
            'summary' => '',
            'detail' => '',
            'fix' => '',
            'resolved_services_count' => 0,
            'row_count_total' => 0,
            'row_count_service_like' => 0,
            'row_count_class_match' => 0,
            'row_count_prefix_fallback' => 0,
            'row_count_class_mismatch' => 0,
            'row_count_missing_label' => 0,
            'detected_prefixes' => [],
            'detected_classes' => [],
            'primary_detected_prefix' => '',
            'primary_detected_class' => '',
            'prefix_mismatch' => false,
        ];

        if ( function_exists( 'bookaro_get_mylisting_service_resolution_diagnostics' ) ) {
            $resolved = bookaro_get_mylisting_service_resolution_diagnostics( $listing_id );
            if ( is_array( $resolved ) ) {
                return array_merge( $defaults, $resolved );
            }
        }

        return $defaults;
    }

    private function get_mylisting_resolution_path_label( string $resolution_path ): string
    {
        $resolution_path = sanitize_key( $resolution_path );
        if ( 'class_match' === $resolution_path ) {
            return __( 'Class match', 'mybookaro' );
        }
        if ( 'prefix_fallback' === $resolution_path ) {
            return __( 'Prefix fallback', 'mybookaro' );
        }
        if ( 'class_and_prefix' === $resolution_path ) {
            return __( 'Mixed class + prefix fallback', 'mybookaro' );
        }
        return __( 'No resolved path', 'mybookaro' );
    }

    private function build_mylisting_services_check_state( array $diagnostics, int $listing_id, string $repeater_class ): array
    {
        $listing_id = absint( $listing_id );
        $repeater_class = sanitize_key( $repeater_class );
        if ( '' === $repeater_class ) {
            $repeater_class = 'mybookaro_services';
        }

        $reason = sanitize_key( (string) ( $diagnostics['reason_code'] ?? '' ) );
        $resolved_count = absint( $diagnostics['resolved_services_count'] ?? 0 );
        $detected_prefixes = array_values( array_filter( array_map( 'sanitize_key', (array) ( $diagnostics['detected_prefixes'] ?? [] ) ) ) );
        $detected_classes = array_values( array_filter( array_map( 'sanitize_key', (array) ( $diagnostics['detected_classes'] ?? [] ) ) ) );
        $path_label = $this->get_mylisting_resolution_path_label( (string) ( $diagnostics['resolution_path'] ?? '' ) );

        $view = [
            'state' => 'warn',
            'value' => __( 'Needs review', 'mybookaro' ),
            'detail' => __( 'MyListing service diagnostics are not available yet.', 'mybookaro' ),
            'fix' => __( 'Open Setup Wizard > Services, confirm repeater class and sample listing rows, then refresh this page.', 'mybookaro' ),
            'next_step' => __( 'Next step: Open Setup Wizard > Services, review diagnostics, save, then refresh System Status.', 'mybookaro' ),
            'reason_code' => $reason,
        ];

        if ( $listing_id < 1 ) {
            $view['state'] = 'warn';
            $view['value'] = __( 'No sample listing', 'mybookaro' );
            $view['detail'] = __( 'MyListing is active, but no published listing is available for service diagnostics yet.', 'mybookaro' );
            $view['fix'] = __( 'Create or publish one listing, then return to Setup Wizard > Services to validate repeater rows.', 'mybookaro' );
            $view['next_step'] = __( 'Next step: Publish a listing, then open Setup Wizard > Services to re-run diagnostics.', 'mybookaro' );
            return $view;
        }

        if ( in_array( $reason, [ 'resolved_with_class_match', 'resolved_with_class_and_prefix', 'pre_resolved_services' ], true ) ) {
            $view['state'] = 'ok';
            $view['value'] = __( 'Resolved', 'mybookaro' );
            $view['detail'] = sprintf(
                /* translators: 1: service count, 2: resolution path */
                __( '%1$d service(s) resolved. Resolution path: %2$s.', 'mybookaro' ),
                $resolved_count,
                $path_label
            );
            $view['fix'] = '';
            $view['next_step'] = '';
            return $view;
        }

        if ( 'resolved_with_prefix_fallback' === $reason ) {
            $view['state'] = 'warn';
            $view['value'] = __( 'Fallback', 'mybookaro' );
            $view['detail'] = sprintf(
                /* translators: 1: service count, 2: resolution path */
                __( '%1$d service(s) resolved via %2$s. Rows currently rely on `<prefix>-label` parsing instead of class tokens.', 'mybookaro' ),
                $resolved_count,
                $path_label
            );
            $view['fix'] = sprintf(
                /* translators: %s: repeater class */
                __( 'Add class `%s` to service rows so MyListing resolution is explicit.', 'mybookaro' ),
                $repeater_class
            );
            $view['next_step'] = __( 'Next step: Open Setup Wizard > Services, keep the configured class, then update listing-type rows to include that class.', 'mybookaro' );
            return $view;
        }

        if ( 'class_mismatch' === $reason ) {
            $view['state'] = 'error';
            $view['value'] = __( 'Class mismatch', 'mybookaro' );
            $view['detail'] = sprintf(
                /* translators: 1: configured class, 2: detected classes, 3: detected prefixes */
                __( 'Configured class `%1$s` is missing from service rows. Detected row classes: %2$s. Detected prefixes: %3$s.', 'mybookaro' ),
                $repeater_class,
                ! empty( $detected_classes ) ? implode( ', ', $detected_classes ) : __( 'none', 'mybookaro' ),
                ! empty( $detected_prefixes ) ? implode( ', ', $detected_prefixes ) : __( 'none', 'mybookaro' )
            );
            $view['fix'] = __( 'Set Services Repeater Class to the class used in your listing type, or update row classes to include the configured class.', 'mybookaro' );
            $view['next_step'] = __( 'Next step: Open Setup Wizard > Services, align repeater class and row classes, save, then refresh this page.', 'mybookaro' );
            return $view;
        }

        if ( 'no_service_like_rows' === $reason ) {
            $view['state'] = 'error';
            $view['value'] = __( 'Missing service fields', 'mybookaro' );
            $view['detail'] = __( 'Repeater rows were found, but none include expected service fields like `<prefix>-label`.', 'mybookaro' );
            $view['fix'] = __( 'Add service label fields (and optional duration/price fields) to each repeater row in your MyListing listing type.', 'mybookaro' );
            $view['next_step'] = __( 'Next step: Update listing-type repeater fields, save the listing, then refresh diagnostics.', 'mybookaro' );
            return $view;
        }

        if ( 'missing_service_labels' === $reason ) {
            $view['state'] = 'error';
            $view['value'] = __( 'Missing labels', 'mybookaro' );
            $view['detail'] = __( 'Service rows matched, but one or more rows have empty labels so Bookaro skipped them.', 'mybookaro' );
            $view['fix'] = __( 'Fill the service label field for each row and save the listing.', 'mybookaro' );
            $view['next_step'] = __( 'Next step: Update row labels, save, then refresh this check.', 'mybookaro' );
            return $view;
        }

        if ( 'no_repeater_rows' === $reason ) {
            $view['state'] = 'error';
            $view['value'] = __( 'No rows', 'mybookaro' );
            $view['detail'] = __( 'No MyListing repeater rows were found on the sample listing.', 'mybookaro' );
            $view['fix'] = __( 'Add and save service rows in the listing type, then refresh diagnostics.', 'mybookaro' );
            $view['next_step'] = __( 'Next step: Add at least one service row, save, and refresh this page.', 'mybookaro' );
            return $view;
        }

        if ( 'listing_not_allowed' === $reason ) {
            $view['state'] = 'warn';
            $view['value'] = __( 'Listing blocked', 'mybookaro' );
            $view['detail'] = __( 'The sample listing is outside the currently allowed listing post types.', 'mybookaro' );
            $view['fix'] = __( 'Align allowed listing post types in Setup Wizard > Listings with your MyListing listing type.', 'mybookaro' );
            $view['next_step'] = __( 'Next step: Open Setup Wizard > Listings, update listing post types, save, then refresh this page.', 'mybookaro' );
            return $view;
        }

        return $view;
    }

    private function get_environment_status(): array
    {
        $wp_version = get_bloginfo( 'version' );
        $php_version = PHP_VERSION;
        $theme_name = '';
        $theme_version = '';
        $theme_parent = '';
        if ( function_exists( 'wp_get_theme' ) ) {
            $theme = wp_get_theme();
            if ( $theme ) {
                $theme_name = (string) $theme->get( 'Name' );
                $theme_version = (string) $theme->get( 'Version' );
                if ( $theme->parent() ) {
                    $theme_parent = (string) $theme->parent()->get( 'Name' );
                }
            }
        }

        $active_plugins = [];
        $active_count = 0;
        if ( function_exists( 'get_plugins' ) || file_exists( ABSPATH . 'wp-admin/includes/plugin.php' ) ) {
            if ( ! function_exists( 'get_plugins' ) ) {
                require_once ABSPATH . 'wp-admin/includes/plugin.php';
            }
            $all_plugins = function_exists( 'get_plugins' ) ? get_plugins() : [];
            $active_files = (array) get_option( 'active_plugins', [] );
            foreach ( $active_files as $file ) {
                if ( isset( $all_plugins[ $file ] ) ) {
                    $data = $all_plugins[ $file ];
                    $name = $data['Name'] ?? $file;
                    $version = $data['Version'] ?? '';
                    $active_plugins[] = trim( $name . ( $version !== '' ? ' ' . $version : '' ) );
                } else {
                    $active_plugins[] = $file;
                }
            }
            $active_count = count( $active_plugins );
        }

        $active_excerpt = $active_plugins;
        if ( $active_count > 6 ) {
            $active_excerpt = array_slice( $active_plugins, 0, 6 );
        }

        return [
            'wp_version' => $wp_version,
            'php_version' => $php_version,
            'bookaro_version' => defined( 'BOOKARO_VERSION' ) ? BOOKARO_VERSION : '',
            'bookaro_pro_version' => defined( 'BOOKARO_PRO_VERSION' ) ? BOOKARO_PRO_VERSION : '',
            'theme_name' => $theme_name,
            'theme_version' => $theme_version,
            'theme_parent' => $theme_parent,
            'active_plugins' => $active_plugins,
            'active_plugins_excerpt' => $active_excerpt,
            'active_plugins_count' => $active_count,
        ];
    }

    private function get_license_status(): array
    {
        $pro_active = defined( 'BOOKARO_PRO_VERSION' );
        $license_key = (string) get_option( 'bookaro_pro_license_key', '' );
        $fingerprint = $license_key !== '' ? substr( hash( 'sha256', $license_key ), 0, 12 ) : '';
        $api_url = function_exists( 'bookaro_pro_get_license_api_url' ) ? (string) bookaro_pro_get_license_api_url() : '';

        return [
            'pro_active' => $pro_active,
            'license_key_present' => $license_key !== '',
            'license_key_fingerprint' => $fingerprint,
            'license_status' => (string) get_option( 'bookaro_pro_license_status', '' ),
            'license_expires' => (string) get_option( 'bookaro_pro_license_expires', '' ),
            'license_last_check' => (int) get_option( 'bookaro_pro_license_last_check', 0 ),
            'license_last_success' => (int) get_option( 'bookaro_pro_license_last_success', 0 ),
            'license_error' => (string) get_option( 'bookaro_pro_license_error', '' ),
            'updates_enabled' => (string) get_option( 'bookaro_pro_enable_updates', '1' ) !== '0',
            'update_failures' => (int) get_option( 'bookaro_pro_update_failures', 0 ),
            'update_last_attempt' => (int) get_option( 'bookaro_pro_update_last_attempt', 0 ),
            'update_last_success' => (int) get_option( 'bookaro_pro_update_last_success', 0 ),
            'update_last_error_code' => (string) get_option( 'bookaro_pro_update_last_error_code', '' ),
            'update_last_error_message' => (string) get_option( 'bookaro_pro_update_last_error_message', '' ),
            'update_backoff_until' => (int) get_option( 'bookaro_pro_update_backoff_until', 0 ),
            'api_url' => $api_url,
        ];
    }

    private function get_settings_status(): array
    {
        $timezone = function_exists( 'wp_timezone_string' ) ? wp_timezone_string() : '';
        $timezone_ok = $timezone !== '';
        $frontend_enabled = function_exists( 'bookaro_is_frontend_enabled' )
            ? (bool) bookaro_is_frontend_enabled()
            : true;
        $spam_honeypot_enabled = (bool) $this->options->get( 'booking_spam_honeypot_enabled', 1 );
        $spam_min_fill_seconds = absint( $this->options->get( 'booking_spam_min_fill_seconds', 4 ) );
        $spam_burst_window_seconds = absint( $this->options->get( 'booking_spam_burst_window_seconds', 300 ) );
        if ( $spam_burst_window_seconds < 30 ) {
            $spam_burst_window_seconds = 30;
        }
        $spam_burst_ip_limit = absint( $this->options->get( 'booking_spam_burst_ip_limit', 8 ) );
        $spam_burst_email_limit = absint( $this->options->get( 'booking_spam_burst_email_limit', 5 ) );
        $spam_duplicate_pending_hours = absint( $this->options->get( 'booking_spam_duplicate_pending_hours', 24 ) );
        $spam_blacklist_words = (string) $this->options->get( 'booking_spam_blacklist_words', '' );
        $spam_blacklist_count = $this->count_spam_blacklist_words( $spam_blacklist_words );

        $spam_stats = get_option( 'bookaro_spam_stats', [] );
        if ( ! is_array( $spam_stats ) ) {
            $spam_stats = [];
        }
        $spam_reasons = $spam_stats['reasons'] ?? [];
        if ( ! is_array( $spam_reasons ) ) {
            $spam_reasons = [];
        }
        $clean_spam_reasons = [];
        foreach ( $spam_reasons as $reason => $count ) {
            $key = sanitize_key( (string) $reason );
            $value = absint( $count );
            if ( $key === '' || $value < 1 ) {
                continue;
            }
            $clean_spam_reasons[ $key ] = $value;
        }
        $spam_total_blocks = absint( $spam_stats['total_blocks'] ?? array_sum( $clean_spam_reasons ) );
        $spam_last_blocked_at = absint( $spam_stats['last_blocked_at'] ?? 0 );
        $spam_last_reason = sanitize_key( (string) ( $spam_stats['last_reason'] ?? '' ) );
        $spam_protection_enabled = $spam_honeypot_enabled
            || $spam_min_fill_seconds > 0
            || $spam_burst_ip_limit > 0
            || $spam_burst_email_limit > 0
            || $spam_duplicate_pending_hours > 0
            || $spam_blacklist_count > 0;

        return [
            'timezone' => $timezone !== '' ? $timezone : 'UTC',
            'timezone_ok' => $timezone_ok,
            'frontend_enabled' => $frontend_enabled,
            'spam_protection_enabled' => $spam_protection_enabled,
            'spam_honeypot_enabled' => $spam_honeypot_enabled,
            'spam_min_fill_seconds' => $spam_min_fill_seconds,
            'spam_burst_window_seconds' => $spam_burst_window_seconds,
            'spam_burst_ip_limit' => $spam_burst_ip_limit,
            'spam_burst_email_limit' => $spam_burst_email_limit,
            'spam_duplicate_pending_hours' => $spam_duplicate_pending_hours,
            'spam_blacklist_words_count' => $spam_blacklist_count,
            'spam_total_blocks' => $spam_total_blocks,
            'spam_block_reasons' => $clean_spam_reasons,
            'spam_last_blocked_at' => $spam_last_blocked_at,
            'spam_last_reason' => $spam_last_reason,
        ];
    }

    private function get_dashboard_status(): array
    {
        $ui_mode = $this->resolve_dashboard_ui_mode();
        $frontend_enabled = function_exists( 'bookaro_is_frontend_enabled' )
            ? (bool) bookaro_is_frontend_enabled()
            : true;
        // Resolve dashboard pages the same way the rest of the controller
        // (see the launch-assistant logic) and the runtime page resolver do:
        // prefer the Setup Wizard's canonical `generic_setup_*` mirror keys,
        // then fall back to the global page IDs. Without this fallback a
        // Generic site configured entirely through the guided wizard (which
        // persists only the `generic_setup_*` mirrors + per-type overrides)
        // would always report its dashboard pages as "missing" here, so the
        // lane could never reach launch-ready through the guided flow.
        $provider_page_id = absint( $this->options->get( 'generic_setup_provider_dashboard_page_id', 0 ) );
        if ( $provider_page_id < 1 ) {
            $provider_page_id = absint( $this->options->get( 'provider_dashboard_page_id', 0 ) );
        }
        $customer_page_id = absint( $this->options->get( 'generic_setup_customer_dashboard_page_id', 0 ) );
        if ( $customer_page_id < 1 ) {
            $customer_page_id = absint( $this->options->get( 'customer_dashboard_page_id', 0 ) );
        }
        $provider_post = $provider_page_id > 0 ? get_post( $provider_page_id ) : null;
        $customer_post = $customer_page_id > 0 ? get_post( $customer_page_id ) : null;
        $provider_embed = $this->evaluate_dashboard_embed( $provider_post, 'provider' );
        $customer_embed = $this->evaluate_dashboard_embed( $customer_post, 'customer' );

        $provider_role = sanitize_key( (string) $this->options->get( 'provider_role', '' ) );
        $customer_role = sanitize_key( (string) $this->options->get( 'owner_role', '' ) );
        $role_names = function_exists( 'wp_roles' ) && wp_roles() ? wp_roles()->get_names() : [];

        $provider_role_key = $provider_role !== '' ? $provider_role : 'bookaro_provider';
        $customer_role_key = $customer_role !== '' ? $customer_role : 'bookaro_customer';
        $provider_role_label = isset( $role_names[ $provider_role_key ] )
            ? $role_names[ $provider_role_key ]
            : __( 'MyBookaro Provider', 'mybookaro' );
        $customer_role_label = isset( $role_names[ $customer_role_key ] )
            ? $role_names[ $customer_role_key ]
            : __( 'MyBookaro Customer', 'mybookaro' );
        $provider_role_exists = isset( $role_names[ $provider_role_key ] );
        $customer_role_exists = isset( $role_names[ $customer_role_key ] );

        $cap_provider = defined( 'BOOKARO_CAP_PROVIDER' ) ? BOOKARO_CAP_PROVIDER : 'bookaro_provider';
        $cap_customer = defined( 'BOOKARO_CAP_CUSTOMER' ) ? BOOKARO_CAP_CUSTOMER : 'bookaro_customer';
        $provider_role_has_cap = false;
        $customer_role_has_cap = false;
        if ( function_exists( 'wp_roles' ) && wp_roles() ) {
            $roles = wp_roles();
            $provider_role_obj = $roles ? $roles->get_role( $provider_role_key ) : null;
            $customer_role_obj = $roles ? $roles->get_role( $customer_role_key ) : null;
            if ( $provider_role_obj ) {
                $provider_role_has_cap = $provider_role_obj->has_cap( $cap_provider );
            }
            if ( $customer_role_obj ) {
                $customer_role_has_cap = $customer_role_obj->has_cap( $cap_customer );
            }
        }

        return [
            'ui_mode' => $ui_mode,
            'frontend_enabled' => $frontend_enabled,
            'provider_page_id' => $provider_page_id,
            'provider_page_exists' => (bool) $provider_post,
            'provider_page_title' => $provider_post ? (string) $provider_post->post_title : '',
            'provider_page_edit' => $provider_post ? (string) get_edit_post_link( $provider_page_id, 'url' ) : '',
            'provider_page_view' => $provider_post ? (string) get_permalink( $provider_page_id ) : '',
            'provider_page_embed_ok' => ! empty( $provider_embed['ok'] ),
            'provider_page_embed_label' => (string) ( $provider_embed['label'] ?? '' ),
            'customer_page_id' => $customer_page_id,
            'customer_page_exists' => (bool) $customer_post,
            'customer_page_title' => $customer_post ? (string) $customer_post->post_title : '',
            'customer_page_edit' => $customer_post ? (string) get_edit_post_link( $customer_page_id, 'url' ) : '',
            'customer_page_view' => $customer_post ? (string) get_permalink( $customer_page_id ) : '',
            'customer_page_embed_ok' => ! empty( $customer_embed['ok'] ),
            'customer_page_embed_label' => (string) ( $customer_embed['label'] ?? '' ),
            'provider_role_key' => $provider_role_key,
            'provider_role_label' => $provider_role_label,
            'provider_role_exists' => $provider_role_exists,
            'provider_role_has_cap' => $provider_role_has_cap,
            'customer_role_key' => $customer_role_key,
            'customer_role_label' => $customer_role_label,
            'customer_role_exists' => $customer_role_exists,
            'customer_role_has_cap' => $customer_role_has_cap,
        ];
    }

    private function resolve_dashboard_ui_mode(): string
    {
        if ( function_exists( 'bookaro_get_ui_mode' ) ) {
            $ui_mode = sanitize_key( (string) bookaro_get_ui_mode() );
            if ( in_array( $ui_mode, [ 'woocommerce', 'shortcodes' ], true ) ) {
                return $ui_mode;
            }
        }

        $default_ui_mode = $this->get_default_ui_mode_for_integration_mode();
        $ui_mode = sanitize_key( (string) $this->options->get( 'ui_mode', $default_ui_mode ) );
        if ( ! in_array( $ui_mode, [ 'woocommerce', 'shortcodes' ], true ) ) {
            $ui_mode = $default_ui_mode;
        }
        if ( 'woocommerce' === $ui_mode && ! $this->is_woocommerce_active() ) {
            $ui_mode = 'shortcodes';
        }
        return $ui_mode;
    }

    private function get_default_ui_mode_for_integration_mode(): string
    {
        $mode = function_exists( 'bookaro_get_integration_mode' )
            ? sanitize_key( (string) bookaro_get_integration_mode() )
            : sanitize_key( (string) $this->options->get( 'integration_mode', 'auto' ) );
        if ( ! in_array( $mode, [ 'auto', 'mylisting', 'generic' ], true ) ) {
            $mode = 'auto';
        }
        if ( 'auto' === $mode ) {
            $mode = $this->is_mylisting_detected() ? 'mylisting' : 'generic';
        }
        return ( 'generic' === $mode ) ? 'shortcodes' : 'woocommerce';
    }

    private function is_woocommerce_active(): bool
    {
        return class_exists( 'WooCommerce' ) || defined( 'WC_VERSION' ) || function_exists( 'WC' );
    }

    private function get_generic_status(): array
    {
        $opts = $this->options->get_all();
        $site_type = function_exists( 'bookaro_get_site_type' )
            ? sanitize_key( (string) bookaro_get_site_type() )
            : sanitize_key( (string) ( $opts['site_type'] ?? 'directory' ) );
        $site_type = $this->normalize_site_type( $site_type );
        $integration_setting = sanitize_key( (string) $this->options->get( 'integration_mode', 'auto' ) );
        if ( ! in_array( $integration_setting, [ 'auto', 'mylisting', 'generic' ], true ) ) {
            $integration_setting = 'auto';
        }
        $mylisting_detected = $this->is_mylisting_detected();
        $integration_resolved = function_exists( 'bookaro_get_integration_mode' )
            ? bookaro_get_integration_mode()
            : $integration_setting;
        $integration_resolved = sanitize_key( (string) $integration_resolved );
        if ( ! in_array( $integration_resolved, [ 'mylisting', 'generic' ], true ) ) {
            $integration_resolved = $mylisting_detected ? 'mylisting' : 'generic';
        }
        $lane_id = $this->resolve_product_lane_id( $site_type, $integration_resolved );
        $lane_label = $this->get_product_lane_label( $lane_id );
        $lane_blueprint = $this->get_product_lane_blueprint( $lane_id, 'advanced_mapping' === $site_type );

        $generic_setup_confirmed = function_exists( 'bookaro_is_generic_setup_confirmed' )
            ? (bool) bookaro_is_generic_setup_confirmed( $opts )
            : ( 'generic' === $integration_setting || ! empty( $opts['generic_setup_completed'] ) );
        $generic_setup_explicitly_confirmed = function_exists( 'bookaro_is_generic_setup_explicitly_confirmed' )
            ? (bool) bookaro_is_generic_setup_explicitly_confirmed( $opts )
            : ( ! empty( $opts['generic_setup_confirmed'] ) || 'generic' === $integration_setting );
        $generic_confirmation_required = function_exists( 'bookaro_generic_requires_confirmation' )
            ? (bool) bookaro_generic_requires_confirmation()
            : ( 'auto' === $integration_setting && ! $mylisting_detected && ! $generic_setup_confirmed );
        $generic_legacy_fallback_active = function_exists( 'bookaro_is_generic_legacy_fallback_active' )
            ? (bool) bookaro_is_generic_legacy_fallback_active()
            : ( 'auto' === $integration_setting && ! $mylisting_detected && $generic_setup_confirmed && ! $generic_setup_explicitly_confirmed );
        $generic_setup_completed = ! empty( $opts['generic_setup_completed'] );
        $generic_setup_confirmed_at = absint( $opts['generic_setup_confirmed_at'] ?? 0 );
        $generic_setup_confirmation_source = sanitize_key( (string) ( $opts['generic_setup_confirmation_source'] ?? '' ) );

        $integration_reason = '';
        if ( 'single_business' === $site_type ) {
            $integration_reason = __( 'Single Business lane is active. Directory lane choice is not used.', 'mybookaro' );
        } elseif ( 'auto' === $integration_setting ) {
            if ( $mylisting_detected ) {
                $integration_reason = __( 'Directory lane auto-select: MyListing detected.', 'mybookaro' );
            } elseif ( $generic_confirmation_required ) {
                $integration_reason = __( 'Directory lane auto-select: MyListing not detected. Generic Directory is available but not confirmed yet.', 'mybookaro' );
            } elseif ( $generic_legacy_fallback_active ) {
                $integration_reason = __( 'Directory lane auto-select: MyListing not detected. Generic Directory is running from legacy saved settings. Save Lane once to confirm it explicitly.', 'mybookaro' );
            } else {
                $integration_reason = __( 'Directory lane auto-select: MyListing not detected. Generic Directory is explicitly confirmed.', 'mybookaro' );
            }
        } elseif ( 'mylisting' === $integration_setting ) {
            $integration_reason = __( 'Directory lane choice set manually: MyListing Directory.', 'mybookaro' );
        } elseif ( 'generic' === $integration_setting ) {
            $integration_reason = __( 'Directory lane choice set manually: Generic Directory.', 'mybookaro' );
        }

        $allowed_types = function_exists( 'bookaro_get_allowed_listing_post_types' )
            ? bookaro_get_allowed_listing_post_types()
            : [];
        if ( ! is_array( $allowed_types ) ) {
            $allowed_types = [ (string) $allowed_types ];
        }
        $allowed_types = array_values( array_filter( array_map( 'sanitize_key', $allowed_types ) ) );
        $allowed_type_labels = [];
        foreach ( $allowed_types as $slug ) {
            $label = $slug;
            $obj = get_post_type_object( $slug );
            if ( $obj && ! empty( $obj->labels->singular_name ) ) {
                $label = $obj->labels->singular_name;
            }
            $allowed_type_labels[] = $label . ' (' . $slug . ')';
        }

        $allowed_pages = $this->options->get( 'allowed_listing_pages', [] );
        if ( ! is_array( $allowed_pages ) ) {
            $allowed_pages = [ $allowed_pages ];
        }
        $allowed_page_labels = [];
        foreach ( $allowed_pages as $page_id ) {
            $page_id = absint( $page_id );
            if ( $page_id < 1 ) {
                continue;
            }
            $title = get_the_title( $page_id );
            if ( $title === '' ) {
                /* translators: %d: numeric value */
                $title = sprintf( __( 'Page #%d', 'mybookaro' ), $page_id );
            }
            $allowed_page_labels[] = $title . ' (#' . $page_id . ')';
        }

        $provider_resolution_mode_raw = sanitize_key( (string) $this->options->get( 'provider_resolution_mode', '' ) );
        $provider_resolution_mode_valid = in_array( $provider_resolution_mode_raw, [ 'author', 'meta_key' ], true );
        $provider_resolution_mode = $provider_resolution_mode_raw;
        if ( ! $provider_resolution_mode_valid ) {
            $provider_resolution_mode = 'author';
        }
        $provider_meta_key = sanitize_key( (string) $this->options->get( 'provider_meta_key', '' ) );

        $services_mode = sanitize_key( (string) $this->options->get( 'generic_services_mode', 'hybrid' ) );
        if ( ! in_array( $services_mode, [ 'provider_only', 'admin_catalog', 'hybrid' ], true ) ) {
            $services_mode = 'hybrid';
        }
        $generic_setup_preset = sanitize_key( (string) ( $opts['generic_setup_preset'] ?? '' ) );
        $provider_label = GenericPresetProfiles::get_provider_mode_label( $provider_resolution_mode, $provider_meta_key );
        $services_mode_label = GenericPresetProfiles::get_services_model_label( $services_mode );
        $preset_placement_strategy = function_exists( 'bookaro_get_booking_placement_strategy' )
            ? sanitize_key( (string) bookaro_get_booking_placement_strategy() )
            : sanitize_key( (string) ( $opts['booking_placement_strategy'] ?? '' ) );
        if ( ! in_array( $preset_placement_strategy, [ 'directory_template', 'normal_page', 'shortcode_only', 'css_selector' ], true ) ) {
            $preset_placement_strategy = ( 'single_business' === $site_type ) ? 'normal_page' : 'directory_template';
        }
        $preset_placement_label = GenericPresetProfiles::get_placement_strategy_label( $preset_placement_strategy );
        $setup_pattern_label = GenericPresetProfiles::get_label( $generic_setup_preset );
        if ( '' === $setup_pattern_label ) {
            $setup_pattern_label = GenericPresetProfiles::build_custom_setup_label(
                $provider_label,
                $services_mode_label,
                $preset_placement_label
            );
        }

        $global_pages = [
            'booking' => absint( $this->options->get( 'booking_page_id', 0 ) ),
            'provider_dashboard' => absint( $this->options->get( 'provider_dashboard_page_id', 0 ) ),
            'customer_dashboard' => absint( $this->options->get( 'customer_dashboard_page_id', 0 ) ),
        ];

        $listing_type_pages = $this->options->get( 'listing_post_type_pages', [] );
        if ( ! is_array( $listing_type_pages ) ) {
            $listing_type_pages = [];
        }

        $default_provider_id = absint( $this->options->get( 'default_provider_id', 0 ) );
        $default_provider = null;
        if ( $default_provider_id > 0 ) {
            $user = get_user_by( 'ID', $default_provider_id );
            if ( $user ) {
                $label = $user->display_name ?: $user->user_login;
                if ( ! empty( $user->user_email ) ) {
                    $label .= ' (' . $user->user_email . ')';
                }
                $default_provider = [
                    'id' => $default_provider_id,
                    'label' => $label,
                ];
            }
        }

        $booking_placement_strategy = function_exists( 'bookaro_get_booking_placement_strategy' )
            ? sanitize_key( (string) bookaro_get_booking_placement_strategy() )
            : sanitize_key( (string) ( $opts['booking_placement_strategy'] ?? '' ) );
        if ( ! in_array( $booking_placement_strategy, [ 'directory_template', 'normal_page', 'shortcode_only', 'css_selector' ], true ) ) {
            $booking_placement_strategy = ( 'single_business' === $site_type ) ? 'normal_page' : 'directory_template';
        }

        $services_model_effective = function_exists( 'bookaro_get_services_model' )
            ? sanitize_key( (string) bookaro_get_services_model() )
            : sanitize_key( (string) ( $opts['services_model'] ?? $opts['generic_services_mode'] ?? 'hybrid' ) );
        if ( 'admin_catalog' === $services_model_effective ) {
            $services_model_effective = 'admin_only';
        }
        if ( ! in_array( $services_model_effective, [ 'provider_only', 'admin_only', 'hybrid' ], true ) ) {
            $services_model_effective = 'hybrid';
        }

        return [
            'site_type' => $site_type,
            'lane_id' => $lane_id,
            'lane_label' => $lane_label,
            'lane_blueprint' => $lane_blueprint,
            'integration_setting' => $integration_setting,
            'integration_resolved' => $integration_resolved,
            'integration_reason' => $integration_reason,
            'generic_setup_confirmed' => $generic_setup_confirmed,
            'generic_setup_explicitly_confirmed' => $generic_setup_explicitly_confirmed,
            'generic_confirmation_required' => $generic_confirmation_required,
            'generic_legacy_fallback_active' => $generic_legacy_fallback_active,
            'generic_setup_completed' => $generic_setup_completed,
            'generic_setup_confirmed_at' => $generic_setup_confirmed_at,
            'generic_setup_confirmation_source' => $generic_setup_confirmation_source,
            'allowed_listing_types' => $allowed_types,
            'allowed_listing_type_labels' => $allowed_type_labels,
            'allowed_listing_pages' => $allowed_pages,
            'allowed_listing_page_labels' => $allowed_page_labels,
            'provider_resolution_mode' => $provider_resolution_mode,
            'provider_resolution_mode_raw' => $provider_resolution_mode_raw,
            'provider_resolution_mode_valid' => $provider_resolution_mode_valid,
            'provider_meta_key' => $provider_meta_key,
            'services_mode' => $services_mode,
            'generic_setup_preset' => $generic_setup_preset,
            'setup_pattern_label' => $setup_pattern_label,
            'provider_mode_label' => $provider_label,
            'services_mode_label' => $services_mode_label,
            'placement_strategy_label' => $preset_placement_label,
            'global_pages' => $global_pages,
            'listing_type_pages' => $listing_type_pages,
            'default_provider' => $default_provider,
            'booking_placement_strategy' => $booking_placement_strategy,
            'services_model_effective' => $services_model_effective,
        ];
    }

    private function normalize_site_type( string $site_type ): string
    {
        $site_type = sanitize_key( $site_type );
        if ( ! in_array( $site_type, [ 'directory', 'single_business', 'advanced_mapping' ], true ) ) {
            return 'directory';
        }
        return $site_type;
    }

    private function resolve_product_lane_id( string $site_type, string $integration_resolved ): string
    {
        $site_type = $this->normalize_site_type( $site_type );
        $integration_resolved = sanitize_key( $integration_resolved );
        if ( 'single_business' === $site_type ) {
            return 'single_business';
        }
        if ( 'directory' === $site_type && 'mylisting' === $integration_resolved ) {
            return 'mylisting_directory';
        }
        return 'generic_directory';
    }

    private function get_product_lane_label( string $lane_id ): string
    {
        $lane_id = sanitize_key( $lane_id );
        $labels = [
            'mylisting_directory' => __( 'MyListing Directory', 'mybookaro' ),
            'generic_directory' => __( 'Generic Directory', 'mybookaro' ),
            'single_business' => __( 'Single Business', 'mybookaro' ),
        ];
        return $labels[ $lane_id ] ?? __( 'Generic Directory', 'mybookaro' );
    }

    private function get_product_lane_blueprint( string $lane_id, bool $advanced_mapping = false ): array
    {
        $lane_id = sanitize_key( $lane_id );
        switch ( $lane_id ) {
            case 'mylisting_directory':
                return [
                    'provider_mapping' => __( 'Listing owner/provider from MyListing listing context', 'mybookaro' ),
                    'services_model' => __( 'MyListing repeater services', 'mybookaro' ),
                    'placement_model' => __( 'Directory listing template (sidebar booking entry)', 'mybookaro' ),
                    'pages_required' => __( 'Provider and customer dashboards (or WooCommerce My Account mode)', 'mybookaro' ),
                ];
            case 'single_business':
                return [
                    'provider_mapping' => __( 'Default Provider (provider-first, no listing required)', 'mybookaro' ),
                    'services_model' => __( 'Provider Only by default (Admin Only/Hybrid optional)', 'mybookaro' ),
                    'placement_model' => __( 'Normal pages or shortcode/block placement', 'mybookaro' ),
                    'pages_required' => __( 'Booking page, provider dashboard page, customer dashboard page (services page recommended)', 'mybookaro' ),
                ];
            case 'generic_directory':
            default:
                return [
                    'provider_mapping' => $advanced_mapping
                        ? __( 'Listing Author or Listing Meta Key (legacy compatibility state active)', 'mybookaro' )
                        : __( 'Listing Author or Listing Meta Key (depends on the selected Generic preset)', 'mybookaro' ),
                    'services_model' => __( 'Provider Only, Admin Catalog Only, or Hybrid (depends on the selected Generic preset)', 'mybookaro' ),
                    'placement_model' => __( 'Assign a Booking page and place blocks/shortcodes explicitly; Auto-Insert or CSS selector can be used as fallback', 'mybookaro' ),
                    'pages_required' => __( 'Booking page, plus Provider/Customer dashboard pages when UI Mode = Shortcodes', 'mybookaro' ),
                ];
        }
    }

    private function get_services_cache_status(): array
    {
        $mode = function_exists( 'bookaro_get_integration_mode' )
            ? sanitize_key( (string) bookaro_get_integration_mode() )
            : 'generic';
        if ( '' === $mode ) {
            $mode = 'generic';
        }

        $context = 'system_status';
        $cache_enabled = function_exists( 'bookaro_should_cache_listing_services' )
            ? (bool) bookaro_should_cache_listing_services( 0, $mode, $context )
            : true;
        $cache_ttl = function_exists( 'bookaro_get_listing_services_cache_ttl' )
            ? max( 0, (int) bookaro_get_listing_services_cache_ttl( 0, $mode, $context ) )
            : 900;
        $global_version = function_exists( 'bookaro_get_services_cache_version' )
            ? (int) bookaro_get_services_cache_version()
            : 0;

        $global_version_timestamp = 0;
        if ( $global_version > 0 ) {
            $candidate_timestamp = (int) floor( $global_version / 1000 );
            if ( $candidate_timestamp > 946684800 && $candidate_timestamp < 4102444800 ) {
                $global_version_timestamp = $candidate_timestamp;
            }
        }

        $invalidation_hooks = [
            'save_post:listings' => (bool) has_action( 'save_post', 'bookaro_bust_listing_services_cache_on_save' ),
            'save_post:services' => (bool) has_action( 'save_post', 'bookaro_bust_services_cache_on_save' ),
            'before_delete_post:services' => (bool) has_action( 'before_delete_post', 'bookaro_bust_services_cache_on_delete' ),
            'trashed_post:services' => (bool) has_action( 'trashed_post', 'bookaro_bust_services_cache_on_delete' ),
            'untrashed_post:services' => (bool) has_action( 'untrashed_post', 'bookaro_bust_services_cache_on_delete' ),
            'added_post_meta' => (bool) has_action( 'added_post_meta', 'bookaro_bust_services_cache_on_meta_change' ),
            'updated_post_meta' => (bool) has_action( 'updated_post_meta', 'bookaro_bust_services_cache_on_meta_change' ),
            'deleted_post_meta' => (bool) has_action( 'deleted_post_meta', 'bookaro_bust_services_cache_on_meta_change' ),
        ];

        $missing_invalidation_hooks = [];
        foreach ( $invalidation_hooks as $hook_name => $registered ) {
            if ( ! $registered ) {
                $missing_invalidation_hooks[] = $hook_name;
            }
        }

        return [
            'mode' => $mode,
            'cache_enabled' => $cache_enabled,
            'cache_ttl' => $cache_ttl,
            'global_version' => $global_version,
            'global_version_timestamp' => $global_version_timestamp,
            'invalidation_hooks' => $invalidation_hooks,
            'invalidation_hooks_ok' => empty( $missing_invalidation_hooks ),
            'missing_invalidation_hooks' => $missing_invalidation_hooks,
            'listing_buster_meta_key' => defined( 'BOOKARO_SERVICES_CACHE_META' ) ? (string) BOOKARO_SERVICES_CACHE_META : 'bookaro_services_cache_buster',
        ];
    }

    private function get_generic_validation_prompt( array $opts = [], array $generic_status = [] ): array
    {
        if ( empty( $opts ) ) {
            $opts = $this->options->get_all();
        }

        $resolved_mode = sanitize_key( (string) ( $generic_status['integration_resolved'] ?? '' ) );
        if ( '' === $resolved_mode ) {
            $resolved_mode = function_exists( 'bookaro_get_integration_mode' )
                ? sanitize_key( (string) bookaro_get_integration_mode() )
                : sanitize_key( (string) ( $opts['integration_mode'] ?? 'auto' ) );
        }
        $confirmation_required = ! empty( $generic_status['generic_confirmation_required'] );
        $active = ( 'generic' === $resolved_mode ) && ! $confirmation_required;

        $current_hash = $this->build_generic_validation_config_hash( $opts );
        $snapshot = function_exists( 'bookaro_get_generic_validation_snapshot' )
            ? bookaro_get_generic_validation_snapshot()
            : [ 'hash' => (string) ( $opts['generic_validation_review_hash'] ?? '' ), 'at' => absint( $opts['generic_validation_reviewed_at'] ?? 0 ) ];
        $reviewed_hash_raw = strtolower( (string) ( $snapshot['hash'] ?? '' ) );
        $reviewed_hash = preg_replace( '/[^a-f0-9]/', '', $reviewed_hash_raw );
        if ( ! is_string( $reviewed_hash ) ) {
            $reviewed_hash = '';
        }

        return [
            'active' => $active,
            'needs_validation' => $active && '' !== $current_hash && $reviewed_hash !== $current_hash,
            'current_hash' => $current_hash,
            'reviewed_hash' => $reviewed_hash,
            'reviewed_at' => absint( $snapshot['at'] ?? 0 ),
            'confirmation_required' => $confirmation_required,
        ];
    }

    private function mark_generic_validation_reviewed( array $opts, array $generic_validation_prompt ): void
    {
        if ( empty( $generic_validation_prompt['active'] ) ) {
            return;
        }

        $current_hash = strtolower( (string) ( $generic_validation_prompt['current_hash'] ?? '' ) );
        $current_hash = preg_replace( '/[^a-f0-9]/', '', $current_hash );
        if ( ! is_string( $current_hash ) || '' === $current_hash ) {
            return;
        }

        $snapshot = function_exists( 'bookaro_get_generic_validation_snapshot' )
            ? bookaro_get_generic_validation_snapshot()
            : [ 'hash' => (string) ( $opts['generic_validation_review_hash'] ?? '' ), 'at' => absint( $opts['generic_validation_reviewed_at'] ?? 0 ) ];
        $stored_hash = preg_replace( '/[^a-f0-9]/', '', strtolower( (string) ( $snapshot['hash'] ?? '' ) ) );
        if ( ! is_string( $stored_hash ) ) {
            $stored_hash = '';
        }

        $stored_at = absint( $snapshot['at'] ?? 0 );
        if ( $stored_hash === $current_hash && $stored_at > 0 ) {
            return;
        }

        $needs_validation = ! empty( $generic_validation_prompt['needs_validation'] );
        $runtime_validation = function_exists( 'bookaro_run_generic_admin_validation' )
            ? bookaro_run_generic_admin_validation()
            : [];
        $runtime_failed_count = is_array( $runtime_validation )
            ? absint( $runtime_validation['failed_count'] ?? 0 )
            : 0;

        // Keep the revalidation reminder active after config changes until the
        // Generic runtime validation checks no longer report Warn/Fail.
        if ( $needs_validation && $runtime_failed_count > 0 ) {
            return;
        }

        // Persist to a dedicated option. The main settings blob is large and could
        // not be re-written reliably from this admin render path on some MySQL
        // configs, which left this reminder permanently stuck.
        if ( function_exists( 'bookaro_set_generic_validation_snapshot' ) ) {
            bookaro_set_generic_validation_snapshot( $current_hash );
        }
    }

    private function build_generic_validation_config_hash( array $opts ): string
    {
        if ( function_exists( 'bookaro_build_generic_validation_config_hash' ) ) {
            return bookaro_build_generic_validation_config_hash( $opts );
        }
        $allowed_types = $opts['allowed_listing_post_types'] ?? [];
        if ( ! is_array( $allowed_types ) ) {
            $allowed_types = [ $allowed_types ];
        }
        $allowed_types = array_values( array_unique( array_filter( array_map( 'sanitize_key', $allowed_types ) ) ) );
        sort( $allowed_types );

        $allowed_pages = $opts['allowed_listing_pages'] ?? [];
        if ( ! is_array( $allowed_pages ) ) {
            $allowed_pages = [ $allowed_pages ];
        }
        $allowed_pages = array_values( array_unique( array_filter( array_map( 'absint', $allowed_pages ) ) ) );
        sort( $allowed_pages );

        $listing_page_overrides = [];
        $raw_overrides = $opts['listing_post_type_pages'] ?? [];
        if ( is_array( $raw_overrides ) ) {
            foreach ( $raw_overrides as $post_type => $contexts ) {
                $post_type = sanitize_key( (string) $post_type );
                if ( '' === $post_type || ! is_array( $contexts ) ) {
                    continue;
                }
                $row = [];
                foreach ( [ 'booking', 'provider_dashboard', 'customer_dashboard', 'services' ] as $context ) {
                    $page_id = absint( $contexts[ $context ] ?? 0 );
                    if ( $page_id > 0 ) {
                        $row[ $context ] = $page_id;
                    }
                }
                if ( ! empty( $row ) ) {
                    $listing_page_overrides[ $post_type ] = $row;
                }
            }
        }
        ksort( $listing_page_overrides );

        $payload = [
            'site_type' => $this->normalize_site_type( (string) ( $opts['site_type'] ?? 'directory' ) ),
            'integration_mode_setting' => sanitize_key( (string) ( $opts['integration_mode'] ?? 'auto' ) ),
            'integration_mode_resolved' => function_exists( 'bookaro_get_integration_mode' )
                ? sanitize_key( (string) bookaro_get_integration_mode() )
                : sanitize_key( (string) ( $opts['integration_mode'] ?? 'auto' ) ),
            'booking_placement_strategy' => function_exists( 'bookaro_get_booking_placement_strategy' )
                ? sanitize_key( (string) bookaro_get_booking_placement_strategy() )
                : sanitize_key( (string) ( $opts['booking_placement_strategy'] ?? '' ) ),
            'ui_mode' => sanitize_key( (string) ( $opts['ui_mode'] ?? '' ) ),
            'generic_advanced_setup_enabled' => ! empty( $opts['generic_advanced_setup_enabled'] ) ? 1 : 0,
            'generic_setup_preset' => sanitize_key( (string) ( $opts['generic_setup_preset'] ?? '' ) ),
            'allowed_listing_post_types' => $allowed_types,
            'allowed_listing_pages' => $allowed_pages,
            'listing_post_type' => sanitize_key( (string) ( $opts['listing_post_type'] ?? '' ) ),
            'provider_resolution_mode' => sanitize_key( (string) ( $opts['provider_resolution_mode'] ?? '' ) ),
            'provider_meta_key' => sanitize_key( (string) ( $opts['provider_meta_key'] ?? $opts['listing_provider_meta_key'] ?? '' ) ),
            'services_model' => sanitize_key( (string) ( $opts['services_model'] ?? '' ) ),
            'generic_services_mode' => sanitize_key( (string) ( $opts['generic_services_mode'] ?? '' ) ),
            'provider_services_enabled' => ! empty( $opts['provider_services_enabled'] ) ? 1 : 0,
            'allow_provider_custom_services' => ! empty( $opts['allow_provider_custom_services'] ) ? 1 : 0,
            'allow_provider_override_catalog' => ! empty( $opts['allow_provider_override_catalog'] ) ? 1 : 0,
            'auto_insert_booking_button_enabled' => ! empty( $opts['auto_insert_booking_button_enabled'] ) ? 1 : 0,
            'auto_insert_booking_button' => sanitize_key( (string) ( $opts['auto_insert_booking_button'] ?? '' ) ),
            'auto_insert_booking_button_selector' => sanitize_text_field( (string) ( $opts['auto_insert_booking_button_selector'] ?? '' ) ),
            'generic_setup_pages' => [
                'booking' => absint( $opts['generic_setup_booking_page_id'] ?? 0 ),
                'provider_dashboard' => absint( $opts['generic_setup_provider_dashboard_page_id'] ?? 0 ),
                'customer_dashboard' => absint( $opts['generic_setup_customer_dashboard_page_id'] ?? 0 ),
                'services' => absint( $opts['generic_setup_services_page_id'] ?? 0 ),
            ],
            'global_pages' => [
                'booking' => absint( $opts['booking_page_id'] ?? 0 ),
                'provider_dashboard' => absint( $opts['provider_dashboard_page_id'] ?? 0 ),
                'customer_dashboard' => absint( $opts['customer_dashboard_page_id'] ?? 0 ),
            ],
            'generic_setup_context' => [
                'listing_id' => absint( $opts['generic_setup_listing_id'] ?? 0 ),
                'provider_user_id' => absint( $opts['generic_setup_provider_user_id'] ?? 0 ),
                'service_id' => absint( $opts['generic_setup_service_id'] ?? 0 ),
                'default_provider_id' => absint( $opts['default_provider_id'] ?? 0 ),
            ],
            'listing_post_type_pages' => $listing_page_overrides,
        ];

        $json = wp_json_encode( $payload );
        if ( ! is_string( $json ) || '' === $json ) {
            return '';
        }

        return hash( 'sha256', $json );
    }

    private function count_spam_blacklist_words( string $raw ): int
    {
        $raw = trim( $raw );
        if ( $raw === '' ) {
            return 0;
        }
        $parts = preg_split( '/[\r\n,;]+/', $raw );
        if ( ! is_array( $parts ) ) {
            return 0;
        }

        $words = [];
        foreach ( $parts as $part ) {
            $word = strtolower( trim( sanitize_text_field( (string) $part ) ) );
            if ( strlen( $word ) < 2 ) {
                continue;
            }
            $words[ $word ] = true;
        }

        return count( $words );
    }

    private function build_launch_readiness_summary( array $support_checks, array $generic_status ): array
    {
        $mode = sanitize_key( (string) ( $generic_status['integration_resolved'] ?? 'auto' ) );
        if ( '' === $mode ) {
            $mode = 'auto';
        }
        $mode_label_map = [
            'generic' => __( 'Generic Directory lane', 'mybookaro' ),
            'mylisting' => __( 'MyListing Directory lane', 'mybookaro' ),
            'auto' => __( 'Directory lane auto-select', 'mybookaro' ),
        ];
        $mode_label = (string) ( $generic_status['lane_label'] ?? '' );
        if ( '' === $mode_label ) {
            $mode_label = $mode_label_map[ $mode ] ?? ucfirst( $mode ) . ' ' . __( 'lane', 'mybookaro' );
        }

        $blockers = [];
        foreach ( $support_checks as $index => $check ) {
            if ( ! is_array( $check ) ) {
                continue;
            }
            $state = sanitize_key( (string) ( $check['state'] ?? 'info' ) );
            if ( ! in_array( $state, [ 'warn', 'error' ], true ) ) {
                continue;
            }
            if ( empty( $check['needs_fix'] ) ) {
                continue;
            }

            $summary = trim( (string) ( $check['next_step'] ?? '' ) );
            if ( '' === $summary ) {
                $summary = trim( (string) ( $check['fix'] ?? '' ) );
            }
            if ( '' === $summary ) {
                $summary = trim( (string) ( $check['detail'] ?? '' ) );
            }

            $blockers[] = [
                'id' => sanitize_key( (string) ( $check['id'] ?? '' ) ),
                'label' => (string) ( $check['label'] ?? '' ),
                'state' => $state,
                'value' => (string) ( $check['value'] ?? '' ),
                'detail' => (string) ( $check['detail'] ?? '' ),
                'fix' => (string) ( $check['fix'] ?? '' ),
                'next_step' => (string) ( $check['next_step'] ?? '' ),
                'summary' => $summary,
                'action_url' => (string) ( $check['action_url'] ?? '' ),
                'action_label' => (string) ( $check['action_label'] ?? '' ),
                '_priority' => ( 'error' === $state ) ? 0 : 1,
                '_order' => (int) $index,
            ];
        }

        usort(
            $blockers,
            static function ( array $a, array $b ): int {
                $priority_compare = ( (int) ( $a['_priority'] ?? 1 ) <=> (int) ( $b['_priority'] ?? 1 ) );
                if ( 0 !== $priority_compare ) {
                    return $priority_compare;
                }
                return ( (int) ( $a['_order'] ?? 0 ) <=> (int) ( $b['_order'] ?? 0 ) );
            }
        );

        $error_count = 0;
        $warn_count = 0;
        foreach ( $blockers as $check ) {
            if ( 'error' === ( $check['state'] ?? '' ) ) {
                $error_count++;
            } elseif ( 'warn' === ( $check['state'] ?? '' ) ) {
                $warn_count++;
            }
        }

        $status = 'ok';
        $status_label = __( 'Launch-ready', 'mybookaro' );
        $summary = __( 'No blocking checks were found. This setup is ready to go live.', 'mybookaro' );
        $detail = __( 'Keep monitoring System Status after launch for environment or integration changes.', 'mybookaro' );

        if ( $error_count > 0 ) {
            $status = 'error';
            $status_label = __( 'Not launch-ready', 'mybookaro' );
            $summary = sprintf(
                /* translators: %d: number of blocking diagnostics */
                _n( '%d blocking issue must be fixed before launch.', '%d blocking issues must be fixed before launch.', $error_count, 'mybookaro' ),
                $error_count
            );
            if ( $warn_count > 0 ) {
                $detail = sprintf(
                    /* translators: %d: number of warning diagnostics */
                    _n( '%d additional warning should also be reviewed.', '%d additional warnings should also be reviewed.', $warn_count, 'mybookaro' ),
                    $warn_count
                );
            } else {
                $detail = __( 'Use the top blockers list below and apply each suggested fix before launch.', 'mybookaro' );
            }
        } elseif ( $warn_count > 0 ) {
            $status = 'warn';
            $status_label = __( 'Needs attention', 'mybookaro' );
            $summary = sprintf(
                /* translators: %d: number of warning diagnostics */
                _n( '%d warning should be reviewed before launch.', '%d warnings should be reviewed before launch.', $warn_count, 'mybookaro' ),
                $warn_count
            );
            $detail = __( 'Resolve the warnings below, then re-run System Status before going live.', 'mybookaro' );
        }

        $blocker_count = count( $blockers );
        $all_blockers = $blockers;
        foreach ( $all_blockers as &$all_blocker ) {
            unset( $all_blocker['_priority'], $all_blocker['_order'] );
        }
        unset( $all_blocker );
        $top_blockers = array_slice( $all_blockers, 0, 5 );

        $primary_action_url = '';
        $primary_action_label = '';
        if ( ! empty( $top_blockers[0] ) && is_array( $top_blockers[0] ) ) {
            $primary_action_url = (string) ( $top_blockers[0]['action_url'] ?? '' );
            $primary_action_label = (string) ( $top_blockers[0]['action_label'] ?? '' );
        }
        if ( '' === $primary_action_url ) {
            $primary_action_url = admin_url( 'admin.php?page=bookaro-system-status' );
            $primary_action_label = __( 'Review support checks', 'mybookaro' );
        }

        return [
            'mode' => $mode,
            'mode_label' => $mode_label,
            'status' => $status,
            'status_label' => $status_label,
            'launch_ready' => ( 0 === $blocker_count ),
            'summary' => $summary,
            'detail' => $detail,
            'blocker_count' => $blocker_count,
            'error_count' => $error_count,
            'warn_count' => $warn_count,
            'blockers' => $all_blockers,
            'top_blockers' => $top_blockers,
            'action_url' => $primary_action_url,
            'action_label' => $primary_action_label,
        ];
    }

    private function build_generic_readiness_summary(
        array $generic_status,
        array $generic_validation_prompt,
        array $launch_readiness
    ): array {
        $mode = sanitize_key( (string) ( $generic_status['integration_resolved'] ?? '' ) );
        $summary = [
            'active' => false,
            'state' => 'info',
            'state_label' => __( 'Info', 'mybookaro' ),
            'summary' => '',
            'current_pattern' => '',
            'current_model' => '',
            'model_items' => [],
            'main_blocker' => '',
            'validation_state' => __( 'Not required', 'mybookaro' ),
            'validation_state_level' => 'info',
            'validation_detail' => '',
            'last_validation_timestamp' => 0,
            'last_validation_run' => __( 'Never', 'mybookaro' ),
            'top_next_action' => [
                'label' => '',
                'url' => '',
                'detail' => '',
            ],
        ];

        if ( 'generic' !== $mode ) {
            return $summary;
        }

        $summary['active'] = true;
        $summary['current_pattern'] = (string) ( $generic_status['setup_pattern_label'] ?? '' );
        $generic_setup_preset = sanitize_key( (string) ( $generic_status['generic_setup_preset'] ?? '' ) );
        $preset_launch_detail = GenericPresetProfiles::build_launch_readiness_detail( $generic_setup_preset );
        $provider_mode_label = trim( (string) ( $generic_status['provider_mode_label'] ?? '' ) );
        $services_mode_label = trim( (string) ( $generic_status['services_mode_label'] ?? '' ) );
        $placement_strategy_label = trim( (string) ( $generic_status['placement_strategy_label'] ?? '' ) );
        $current_pattern_label = trim( (string) $summary['current_pattern'] );
        if ( '' === $current_pattern_label ) {
            $current_pattern_label = __( 'Custom Generic setup', 'mybookaro' );
        }
        $model_snapshot = AdminLaneSummary::build_generic_model_snapshot(
            $current_pattern_label,
            $provider_mode_label,
            $services_mode_label,
            $placement_strategy_label
        );
        $summary['current_model'] = (string) ( $model_snapshot['summary'] ?? '' );
        $summary['model_items'] = is_array( $model_snapshot['items'] ?? null ) ? $model_snapshot['items'] : [];

        $confirmation_required = ! empty( $generic_status['generic_confirmation_required'] );
        $legacy_fallback_active = ! empty( $generic_status['generic_legacy_fallback_active'] );
        $needs_validation = ! empty( $generic_validation_prompt['needs_validation'] );
        $reviewed_at = absint( $generic_validation_prompt['reviewed_at'] ?? 0 );
        $validation_url = admin_url( 'admin.php?page=bookaro-system-status#bookaro-support-check-generic_validation_provider_resolution_sample' );
        $wizard_modes_url = admin_url( 'admin.php?page=bookaro-setup-wizard&step=modes' );

        $runtime_validation = function_exists( 'bookaro_run_generic_admin_validation' )
            ? bookaro_run_generic_admin_validation()
            : [];
        $runtime_checks = [];
        if ( is_array( $runtime_validation ) && ! empty( $runtime_validation['checks'] ) && is_array( $runtime_validation['checks'] ) ) {
            $runtime_checks = $runtime_validation['checks'];
        }
        $runtime_total = count( $runtime_checks );
        $runtime_failed = is_array( $runtime_validation )
            ? absint( $runtime_validation['failed_count'] ?? 0 )
            : 0;

        $summary['last_validation_timestamp'] = $reviewed_at;
        if ( $reviewed_at > 0 ) {
            $summary['last_validation_run'] = sprintf(
                /* translators: 1: formatted date, 2: relative time */
                __( '%1$s (%2$s ago)', 'mybookaro' ),
                date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $reviewed_at ),
                human_time_diff( $reviewed_at, time() )
            );
        }

        $validation_level = 'ok';
        $validation_state = __( 'Passing', 'mybookaro' );
        $validation_detail = __( 'Generic validation is current. Bookaro can confirm directory lane choice, services source, booking entry placement, and required pages for this setup.', 'mybookaro' );
        if ( $confirmation_required ) {
            $validation_level = 'error';
            $validation_state = __( 'Confirmation required', 'mybookaro' );
            $validation_detail = __( 'Generic Directory is not confirmed yet. Until you save the Lane step, Bookaro cannot treat this as the intended Generic path. Next action: confirm Generic in Setup Wizard, then run validation again.', 'mybookaro' );
        } elseif ( $legacy_fallback_active ) {
            $validation_level = 'warn';
            $validation_state = __( 'Review confirmation', 'mybookaro' );
            $validation_detail = __( 'Generic Directory is running from older automatic settings. Save the Lane step once so Bookaro records the intended Generic path, then review the validation checks.', 'mybookaro' );
        } elseif ( $needs_validation ) {
            $validation_level = 'warn';
            $validation_state = __( 'Re-run required', 'mybookaro' );
            $validation_detail = __( 'Settings changed after the last validation run. Until you re-run validation, Bookaro cannot confirm that directory lane choice, services source, placement, and pages still match. Next action: re-run the Generic validation checks before launch.', 'mybookaro' );
        } elseif ( $runtime_total < 1 ) {
            $validation_level = 'warn';
            $validation_state = __( 'Not run yet', 'mybookaro' );
            $validation_detail = __( 'Generic validation has not run yet. Bookaro still needs to confirm directory lane choice, services source, booking entry placement, and required pages before launch. Next action: run the Generic validation checks.', 'mybookaro' );
        } elseif ( $runtime_failed > 0 ) {
            $validation_level = 'error';
            $validation_state = __( 'Blocked', 'mybookaro' );
            $validation_detail = sprintf(
                /* translators: 1: failed checks, 2: total checks */
                __( '%1$d of %2$d Generic checks still need attention. That means at least one directory lane choice, services source, booking entry, or page requirement can still block bookings.', 'mybookaro' ),
                $runtime_failed,
                $runtime_total
            );
        } else {
            $validation_detail = sprintf(
                /* translators: %d: total generic validation checks */
                __( 'All %d Generic validation checks are passing. Bookaro can resolve providers, services, booking entry placement, and required pages for the current setup.', 'mybookaro' ),
                $runtime_total
            );
        }

        $summary['validation_state'] = $validation_state;
        $summary['validation_state_level'] = $validation_level;
        if ( '' !== trim( $preset_launch_detail ) ) {
            $validation_detail .= ' ' . $preset_launch_detail;
        }
        $summary['validation_detail'] = $validation_detail;

        $launch_status = sanitize_key( (string) ( $launch_readiness['status'] ?? 'info' ) );
        $state = 'ok';
        $state_label = __( 'Ready', 'mybookaro' );
        $state_summary = __( 'Ready: Generic validation is passing and no launch blockers are currently detected.', 'mybookaro' );
        if ( $confirmation_required || $runtime_failed > 0 || 'error' === $launch_status ) {
            $state = 'error';
            $state_label = __( 'Blocked', 'mybookaro' );
            if ( $confirmation_required ) {
                $state_summary = __( 'Blocked: Generic confirmation is still required in Setup Wizard > Lane before launch checks can pass.', 'mybookaro' );
            } elseif ( $runtime_failed > 0 ) {
                $state_summary = sprintf(
                    /* translators: 1: failed checks, 2: total checks */
                    __( 'Blocked: %1$d of %2$d Generic validation checks still need attention.', 'mybookaro' ),
                    $runtime_failed,
                    max( 1, $runtime_total )
                );
            } else {
                $state_summary = __( 'Blocked: Launch readiness still reports blocking checks that must be fixed before go-live.', 'mybookaro' );
            }
        } elseif ( $legacy_fallback_active || $needs_validation || $runtime_total < 1 || in_array( $launch_status, [ 'warn', 'info' ], true ) ) {
            $state = 'warn';
            $state_label = __( 'Review needed', 'mybookaro' );
            if ( $legacy_fallback_active ) {
                $state_summary = __( 'Review needed: Save Setup Wizard > Lane once to capture explicit Generic confirmation metadata.', 'mybookaro' );
            } elseif ( $needs_validation ) {
                $state_summary = __( 'Review needed: Settings changed after the last Generic validation run, so you should re-run validation.', 'mybookaro' );
            } elseif ( $runtime_total < 1 ) {
                $state_summary = __( 'Review needed: Generic validation has not run yet for the current setup.', 'mybookaro' );
            } else {
                $state_summary = __( 'Review needed: Resolve warning-level launch checks before going live.', 'mybookaro' );
            }
        }
        $summary['state'] = $state;
        $summary['state_label'] = $state_label;
        $summary['summary'] = $state_summary;

        $main_blocker = __( 'No Generic blocker is currently detected for this model.', 'mybookaro' );
        if ( $confirmation_required ) {
            $main_blocker = __( 'Generic lane is not confirmed yet in Setup Wizard > Lane.', 'mybookaro' );
        } elseif ( $legacy_fallback_active ) {
            $main_blocker = __( 'Generic lane still uses legacy fallback metadata and needs a one-time Lane save.', 'mybookaro' );
        } elseif ( $runtime_failed > 0 ) {
            $main_blocker = sprintf(
                /* translators: %d: number of failed Generic runtime validation checks */
                _n(
                    '%d Generic validation check still blocks launch.',
                    '%d Generic validation checks still block launch.',
                    $runtime_failed,
                    'mybookaro'
                ),
                $runtime_failed
            );
        } elseif ( $needs_validation ) {
            $main_blocker = __( 'Validation snapshot is stale after recent Generic settings changes.', 'mybookaro' );
        } elseif ( $runtime_total < 1 ) {
            $main_blocker = __( 'Generic validation has not run yet for this setup.', 'mybookaro' );
        } elseif ( ! empty( $launch_readiness['top_blockers'][0] ) && is_array( $launch_readiness['top_blockers'][0] ) ) {
            $main_blocker = AdminLaneSummary::resolve_blocker_summary( $launch_readiness['top_blockers'][0] );
        }
        $summary['main_blocker'] = trim( $main_blocker );

        $top_action = [
            'label' => __( 'Open Generic validation checks', 'mybookaro' ),
            'url' => $validation_url,
            'detail' => __( 'Use this after mapping, services, or page changes so Bookaro can confirm the current Generic setup.', 'mybookaro' ),
        ];
        if ( $confirmation_required ) {
            $top_action = [
                'label' => __( 'Confirm Generic in Setup Wizard', 'mybookaro' ),
                'url' => $wizard_modes_url,
                'detail' => __( 'Confirm Generic first, then re-run validation checks.', 'mybookaro' ),
            ];
        } elseif ( $legacy_fallback_active ) {
            $top_action = [
                'label' => __( 'Review and save Generic confirmation', 'mybookaro' ),
                'url' => $wizard_modes_url,
                'detail' => __( 'Save the Lane step once to capture explicit confirmation metadata.', 'mybookaro' ),
            ];
        } elseif ( $needs_validation || $runtime_total < 1 || $runtime_failed > 0 ) {
            $top_action = [
                'label' => __( 'Run Generic validation now', 'mybookaro' ),
                'url' => $validation_url,
                'detail' => __( 'Resolve every warning or error before launch.', 'mybookaro' ),
            ];
        } elseif ( ! empty( $launch_readiness['blocker_count'] ) ) {
            $top_action = [
                'label' => (string) ( $launch_readiness['action_label'] ?? __( 'Review support checks', 'mybookaro' ) ),
                'url' => (string) ( $launch_readiness['action_url'] ?? admin_url( 'admin.php?page=bookaro-system-status' ) ),
                'detail' => __( 'Address the highest-priority blocker shown in Launch readiness.', 'mybookaro' ),
            ];
        } elseif ( 'ok' === $state ) {
            $top_action = [
                'label' => __( 'Re-run validation after config changes', 'mybookaro' ),
                'url' => $validation_url,
                'detail' => __( 'No blockers detected. Re-run validation whenever mapping or pages change.', 'mybookaro' ),
            ];
        }

        $top_action['label'] = trim( (string) ( $top_action['label'] ?? '' ) );
        $top_action['url'] = trim( (string) ( $top_action['url'] ?? '' ) );
        $top_action['detail'] = trim( (string) ( $top_action['detail'] ?? '' ) );
        $summary['top_next_action'] = $top_action;

        return $summary;
    }

    private function build_lane_summary_banner(
        array $generic_status,
        array $launch_readiness,
        array $generic_readiness_summary
    ): array {
        $lane_id = sanitize_key( (string) ( $generic_status['lane_id'] ?? '' ) );
        $resolved_mode = sanitize_key( (string) ( $generic_status['integration_resolved'] ?? '' ) );
        $site_type = sanitize_key( (string) ( $generic_status['site_type'] ?? '' ) );

        $lane_label = trim( (string) ( $generic_status['lane_label'] ?? '' ) );
        if ( '' === $lane_label ) {
            $lane_label = AdminLaneSummary::resolve_lane_label( $lane_id, $resolved_mode, $site_type );
        }

        $summary = AdminLaneSummary::create_payload( $lane_label );

        if ( 'single_business' === $lane_id || 'single_business' === $site_type ) {
            $single_business_context = $this->build_single_business_lane_focus_context( $generic_status );
            $single_business_snapshot = AdminLaneSummary::build_single_business_readiness_snapshot( [
                'provider_ready' => ! empty( $single_business_context['provider_ready'] ),
                'booking_page_ready' => ! empty( $single_business_context['booking_page_ready'] ),
                'services_ready' => ! empty( $single_business_context['services_ready'] ),
                'services_count' => max( 0, absint( $single_business_context['services_count'] ?? 0 ) ),
                'dashboard_mode' => sanitize_key( (string) ( $single_business_context['dashboard_mode'] ?? 'shortcodes' ) ),
                'dashboard_pages_ready' => ! empty( $single_business_context['dashboard_pages_ready'] ),
                'preview_ready' => ! empty( $single_business_context['preview_ready'] ),
                'fast_path_ready' => ! empty( $single_business_context['fast_path_ready'] ),
            ] );
            $summary['summary'] = __( 'Single Business first-booking order: Default Provider -> Booking/dashboard pages -> First service -> Preview booking.', 'mybookaro' );
            $summary['top_blocker_label'] = __( 'Main blocker', 'mybookaro' );
            $summary['next_action_label'] = __( 'Required next step', 'mybookaro' );
            $summary['model_label'] = __( 'Single Business launch assistant', 'mybookaro' );
            $summary['model_summary'] = trim( (string) ( $single_business_snapshot['summary'] ?? '' ) );
            $summary['model_items'] = is_array( $single_business_snapshot['items'] ?? null ) ? $single_business_snapshot['items'] : [];

            return AdminLaneSummary::normalize(
                array_merge(
                    $summary,
                    AdminLaneSummary::resolve_single_business_focus( $single_business_context )
                )
            );
        }

        $top_blockers = is_array( $launch_readiness['top_blockers'] ?? null ) ? $launch_readiness['top_blockers'] : [];
        $top_blocker = '';
        $next_action = $summary['next_action'];

        if ( ! empty( $top_blockers[0] ) && is_array( $top_blockers[0] ) ) {
            $top_blocker = AdminLaneSummary::resolve_blocker_summary( $top_blockers[0] );
            $next_action = [
                'label' => trim( (string) ( $top_blockers[0]['action_label'] ?? '' ) ),
                'url' => trim( (string) ( $top_blockers[0]['action_url'] ?? '' ) ),
                'detail' => trim( (string) ( $top_blockers[0]['next_step'] ?? '' ) ),
            ];
        }

        if ( '' === trim( (string) ( $next_action['url'] ?? '' ) ) || '' === trim( (string) ( $next_action['label'] ?? '' ) ) ) {
            $next_action = [
                'label' => trim( (string) ( $launch_readiness['action_label'] ?? __( 'Review support checks', 'mybookaro' ) ) ),
                'url' => trim( (string) ( $launch_readiness['action_url'] ?? admin_url( 'admin.php?page=bookaro-system-status' ) ) ),
                'detail' => trim( (string) ( $launch_readiness['detail'] ?? '' ) ),
            ];
        }

        if ( 'generic_directory' === $lane_id && 'generic' === $resolved_mode && is_array( $generic_readiness_summary['top_next_action'] ?? null ) ) {
            $summary['top_blocker_label'] = __( 'Main blocker', 'mybookaro' );
            $summary['next_action_label'] = __( 'Required next step', 'mybookaro' );
            $summary['model_label'] = __( 'Current lane profile', 'mybookaro' );
            $summary['summary'] = __( 'Compact Generic lane snapshot: pattern, ownership model, placement strategy, top blocker, and required next step.', 'mybookaro' );
            $current_model = trim( (string) ( $generic_readiness_summary['current_model'] ?? '' ) );
            if ( '' !== $current_model ) {
                $summary['model_summary'] = $current_model;
            }
            $model_items = is_array( $generic_readiness_summary['model_items'] ?? null ) ? $generic_readiness_summary['model_items'] : [];
            if ( ! empty( $model_items ) ) {
                $summary['model_items'] = $model_items;
            }
            $generic_action = $generic_readiness_summary['top_next_action'];
            if ( '' !== trim( (string) ( $generic_action['url'] ?? '' ) ) && '' !== trim( (string) ( $generic_action['label'] ?? '' ) ) ) {
                $next_action = $generic_action;
            }
            $top_blocker = trim( (string) ( $generic_readiness_summary['main_blocker'] ?? '' ) );
            if ( '' === $top_blocker ) {
                $top_blocker = trim( (string) ( $generic_readiness_summary['validation_detail'] ?? '' ) );
            }
            if ( '' === $top_blocker ) {
                $top_blocker = trim( (string) ( $generic_readiness_summary['summary'] ?? '' ) );
            }
        }

        if ( '' === $top_blocker ) {
            $top_blocker = trim( (string) ( $launch_readiness['summary'] ?? '' ) );
        }
        if ( '' === $top_blocker ) {
            $top_blocker = __( 'No blockers detected for the current lane snapshot.', 'mybookaro' );
        }

        $state = sanitize_key( (string) ( $launch_readiness['status'] ?? 'info' ) );
        if ( ! in_array( $state, [ 'ok', 'warn', 'error', 'info' ], true ) ) {
            $state = 'info';
        }
        $state_label = (string) ( $launch_readiness['status_label'] ?? '' );

        if ( 'generic_directory' === $lane_id && 'generic' === $resolved_mode ) {
            $generic_state = sanitize_key( (string) ( $generic_readiness_summary['state'] ?? '' ) );
            if ( in_array( $generic_state, [ 'ok', 'warn', 'error', 'info' ], true ) ) {
                $state = $generic_state;
                $state_label = (string) ( $generic_readiness_summary['state_label'] ?? $state_label );
            }
        }

        return AdminLaneSummary::normalize( array_merge( $summary, [
            'state' => $state,
            'state_label' => $state_label,
            'top_blocker' => $top_blocker,
            'next_action' => $next_action,
        ] ) );
    }

    private function build_single_business_lane_focus_context( array $generic_status = [] ): array
    {
        $default_provider = is_array( $generic_status['default_provider'] ?? null ) ? $generic_status['default_provider'] : [];
        $provider_id = absint( $default_provider['id'] ?? 0 );
        if ( $provider_id < 1 ) {
            $provider_id = absint( $this->options->get( 'default_provider_id', 0 ) );
        }
        if ( $provider_id > 0 && ! get_user_by( 'ID', $provider_id ) ) {
            $provider_id = 0;
        }

        $ui_mode = $this->resolve_dashboard_ui_mode();
        $dashboard_mode = $ui_mode;
        $booking_page_id = absint( $this->options->get( 'generic_setup_booking_page_id', 0 ) );
        if ( $booking_page_id < 1 ) {
            $booking_page_id = absint( $this->options->get( 'booking_page_id', 0 ) );
        }
        $provider_page_id = absint( $this->options->get( 'generic_setup_provider_dashboard_page_id', 0 ) );
        if ( $provider_page_id < 1 ) {
            $provider_page_id = absint( $this->options->get( 'provider_dashboard_page_id', 0 ) );
        }
        $customer_page_id = absint( $this->options->get( 'generic_setup_customer_dashboard_page_id', 0 ) );
        if ( $customer_page_id < 1 ) {
            $customer_page_id = absint( $this->options->get( 'customer_dashboard_page_id', 0 ) );
        }

        $missing_pages = [];
        $missing_page_keys = [];
        if ( $booking_page_id < 1 ) {
            $missing_pages[] = __( 'Booking page', 'mybookaro' );
            $missing_page_keys[] = 'booking';
        }
        if ( 'shortcodes' === $ui_mode ) {
            if ( $provider_page_id < 1 ) {
                $missing_pages[] = __( 'Provider dashboard page', 'mybookaro' );
                $missing_page_keys[] = 'provider_dashboard';
            }
            if ( $customer_page_id < 1 ) {
                $missing_pages[] = __( 'Customer dashboard page', 'mybookaro' );
                $missing_page_keys[] = 'customer_dashboard';
            }
        }
        $booking_page_ready = ( $booking_page_id > 0 );
        $dashboard_pages_ready = ( 'shortcodes' !== $ui_mode ) || ( $provider_page_id > 0 && $customer_page_id > 0 );
        $pages_ready = empty( $missing_pages );
        $pages_detail = $pages_ready
            ? (
                'shortcodes' === $ui_mode
                    ? __( 'Booking page, Provider Dashboard page, and Customer Dashboard page are assigned.', 'mybookaro' )
                    : __( 'Booking page is assigned. Dashboard pages use WooCommerce My Account.', 'mybookaro' )
            )
            : sprintf(
                /* translators: %s: comma separated missing pages */
                __( 'Missing: %s.', 'mybookaro' ),
                implode( ', ', $missing_pages )
            );
        if ( ! $pages_ready ) {
            $pages_detail .= ' ' . __( 'Single Business sequence is strict: assign Booking page first, then dashboard pages (if Shortcodes mode).', 'mybookaro' );
        }
        $pages_action_label = __( 'Assign pages', 'mybookaro' );
        if ( ! $pages_ready ) {
            $missing_booking_page = in_array( 'booking', $missing_page_keys, true );
            $missing_dashboard_pages = in_array( 'provider_dashboard', $missing_page_keys, true ) || in_array( 'customer_dashboard', $missing_page_keys, true );
            if ( $missing_booking_page && $missing_dashboard_pages ) {
                $pages_action_label = __( 'Assign booking + dashboard pages', 'mybookaro' );
            } elseif ( $missing_booking_page ) {
                $pages_action_label = __( 'Assign Booking page', 'mybookaro' );
            } elseif ( $missing_dashboard_pages ) {
                $pages_action_label = __( 'Assign dashboard pages', 'mybookaro' );
            }
        }

        $provider_ready = $provider_id > 0;
        $services = ( $provider_ready && function_exists( 'bookaro_get_generic_provider_context_services' ) )
            ? bookaro_get_generic_provider_context_services( $provider_id )
            : [];
        $services = is_array( $services ) ? $services : [];
        $services_count = count( $services );
        $services_ready = $provider_ready && $services_count > 0;

        $service_type = defined( 'BOOKARO_SERVICE_POST_TYPE' ) ? BOOKARO_SERVICE_POST_TYPE : 'bookaro_service';
        $create_service_url = admin_url( 'post-new.php?post_type=' . $service_type );
        $default_provider_url = admin_url( 'admin.php?page=bookaro-setup-wizard&step=listings' );
        $pages_url = admin_url( 'admin.php?page=bookaro-setup-wizard&step=pages' );

        $preview_url = '';
        $preview_candidates = array_values(
            array_filter(
                array_unique( [
                    $booking_page_id,
                    absint( $this->options->get( 'generic_setup_services_page_id', 0 ) ),
                    absint( $this->options->get( 'booking_page_id', 0 ) ),
                ] )
            )
        );
        foreach ( $preview_candidates as $page_id ) {
            $page_id = absint( $page_id );
            if ( $page_id < 1 ) {
                continue;
            }
            $view_url = get_permalink( $page_id );
            if ( $view_url ) {
                $preview_url = (string) $view_url;
                break;
            }
            $edit_url = get_edit_post_link( $page_id, '' );
            if ( $edit_url ) {
                $preview_url = (string) $edit_url;
                break;
            }
        }
        $preview_ready = $provider_ready && $pages_ready && $services_ready && '' !== trim( $preview_url );
        $fast_path_url = $this->get_single_business_fast_path_url();
        $fast_path_ready = $provider_ready && $pages_ready && $services_ready && '' !== trim( $fast_path_url );
        $ready_detail = ( $provider_ready && $pages_ready && $services_ready )
            ? __( 'Open booking/services preview and run one end-to-end booking test.', 'mybookaro' )
            : __( 'Follow this order: Default Provider -> Pages -> First service -> Preview booking.', 'mybookaro' );
        if ( '' === trim( $preview_url ) ) {
            $preview_url = admin_url( 'admin.php?page=bookaro-getting-started#bookaro-action-open-listing' );
        }

        $provider_detail = $provider_ready
            ? __( 'Default Provider is set. Continue with pages, first service, then preview booking.', 'mybookaro' )
            : __( 'Set Default Provider first. Single Business bookings cannot resolve provider context without it.', 'mybookaro' );
        $services_detail = ! $provider_ready
            ? __( 'Cannot validate service inventory until Default Provider is set.', 'mybookaro' )
            : (
                $services_ready
                    ? sprintf(
                        /* translators: %d: available services count */
                        __( 'Available services for the Default Provider: %d. Continue to preview booking.', 'mybookaro' ),
                        $services_count
                    )
                    : __( 'No services are available for the Default Provider. Create one service before previewing bookings.', 'mybookaro' )
            );

        return [
            'provider_ready' => $provider_ready,
            'pages_ready' => $pages_ready,
            'services_ready' => $services_ready,
            'booking_page_ready' => $booking_page_ready,
            'dashboard_mode' => $dashboard_mode,
            'dashboard_pages_ready' => $dashboard_pages_ready,
            'missing_page_keys' => $missing_page_keys,
            'default_provider_url' => $default_provider_url,
            'pages_url' => $pages_url,
            'pages_action_label' => $pages_action_label,
            'create_service_url' => $create_service_url,
            'ready_url' => $preview_url,
            'preview_ready' => $preview_ready,
            'fast_path_url' => $fast_path_url,
            'fast_path_ready' => $fast_path_ready,
            'services_count' => $services_count,
            'provider_detail' => $provider_detail,
            'pages_detail' => $pages_detail,
            'services_detail' => $services_detail,
            'ready_detail' => $ready_detail,
        ];
    }

    private function get_single_business_fast_path_url(): string
    {
        $url = admin_url( 'admin-post.php?action=bookaro_getting_started_fast_path_booking&listing_id=0' );
        if ( function_exists( 'add_query_arg' ) ) {
            $url = add_query_arg(
                [
                    'action' => 'bookaro_getting_started_fast_path_booking',
                    'listing_id' => 0,
                ],
                admin_url( 'admin-post.php' )
            );
        }
        if ( function_exists( 'wp_nonce_url' ) ) {
            return wp_nonce_url( $url, 'bookaro_getting_started_fast_path_booking' );
        }

        return $url;
    }

    private function build_launch_blocker_summary( array $launch_readiness ): string
    {
        $mode_label = trim( (string) ( $launch_readiness['mode_label'] ?? __( 'Unknown lane', 'mybookaro' ) ) );
        if ( '' === $mode_label ) {
            $mode_label = __( 'Unknown lane', 'mybookaro' );
        }
        $status_label = trim( (string) ( $launch_readiness['status_label'] ?? __( 'Unknown', 'mybookaro' ) ) );
        if ( '' === $status_label ) {
            $status_label = __( 'Unknown', 'mybookaro' );
        }
        $launch_ready = ! empty( $launch_readiness['launch_ready'] );
        $blocker_count = (int) ( $launch_readiness['blocker_count'] ?? 0 );
        $error_count = (int) ( $launch_readiness['error_count'] ?? 0 );
        $warn_count = (int) ( $launch_readiness['warn_count'] ?? 0 );
        $summary = trim( (string) ( $launch_readiness['summary'] ?? '' ) );
        $detail = trim( (string) ( $launch_readiness['detail'] ?? '' ) );

        $blockers = is_array( $launch_readiness['blockers'] ?? null ) ? $launch_readiness['blockers'] : [];
        if ( empty( $blockers ) && is_array( $launch_readiness['top_blockers'] ?? null ) ) {
            $blockers = $launch_readiness['top_blockers'];
        }

        $summary_id_payload = wp_json_encode( [
            'mode' => (string) ( $launch_readiness['mode'] ?? '' ),
            'status' => (string) ( $launch_readiness['status'] ?? '' ),
            'blocker_count' => $blocker_count,
            'error_count' => $error_count,
            'warn_count' => $warn_count,
            'blockers' => array_map(
                static function ( $check ) {
                    if ( ! is_array( $check ) ) {
                        return [];
                    }
                    return [
                        'id' => sanitize_key( (string) ( $check['id'] ?? '' ) ),
                        'state' => sanitize_key( (string) ( $check['state'] ?? '' ) ),
                        'value' => trim( (string) ( $check['value'] ?? '' ) ),
                    ];
                },
                $blockers
            ),
        ] );
        $summary_id = 'n/a';
        if ( is_string( $summary_id_payload ) && '' !== $summary_id_payload ) {
            $summary_id = substr( hash( 'sha256', $summary_id_payload ), 0, 12 );
        }

        $generated_at = date_i18n( 'Y-m-d H:i:s' );
        $status_code = 'READY';
        if ( $error_count > 0 ) {
            $status_code = 'BLOCKED';
        } elseif ( $warn_count > 0 ) {
            $status_code = 'ATTENTION';
        }
        $launch_decision = 'GO';
        if ( $error_count > 0 ) {
            $launch_decision = 'NO-GO';
        } elseif ( $warn_count > 0 ) {
            $launch_decision = 'GO WITH CAUTION';
        }
        $handoff_subject = $this->build_launch_handoff_subject( $launch_readiness );

        $state_labels = [
            'error' => 'FAIL',
            'warn' => 'WARN',
            'ok' => 'PASS',
            'info' => 'INFO',
        ];

        $lines = [];
        $lines[] = '=== BEGIN MYBOOKARO LAUNCH HANDOFF ===';
        $lines[] = 'MyBookaro Launch Readiness Handoff';
        $lines[] = 'Snapshot ID: ' . $summary_id;
        $lines[] = 'Generated (site timezone): ' . $generated_at;
        $lines[] = 'Lane: ' . $mode_label;
        $lines[] = 'Overall status: ' . $status_label . ' (' . $status_code . ')';
        $lines[] = 'Launch-ready: ' . ( $launch_ready ? 'Yes' : 'No' );
        $lines[] = 'Launch decision: ' . $launch_decision;
        $lines[] = sprintf(
            'Counts: blockers=%1$d | fail=%2$d | warn=%3$d',
            $blocker_count,
            $error_count,
            $warn_count
        );
        $lines[] = 'Ticket subject: ' . $handoff_subject;
        $lines[] = '';
        $lines[] = 'Copy instructions';
        $lines[] = '- Copy all lines between BEGIN and END into your support ticket/internal handoff.';
        $lines[] = '- Start with the masked support snapshot, then attach the full Text report and Support Bundle JSON only if deeper diagnostics are requested.';
        $lines[] = '- Review Getting Started > Operational summary to confirm launch guardrails before go-live.';
        $lines[] = '- Single Business: no listings required. Confirm Default Provider + booking/services/dashboard pages.';
        $lines[] = '';
        $lines[] = 'Executive summary';
        if ( '' !== $summary ) {
            $lines[] = '- ' . $summary;
        }
        if ( '' !== $detail ) {
            $lines[] = '- ' . $detail;
        }
        if ( '' === $summary && '' === $detail ) {
            $lines[] = '- No additional summary details were generated.';
        }
        $lines[] = '';
        $lines[] = 'Support handoff checklist';
        $lines[] = '- What changed since last known-good state: settings, plugins, theme, or permalinks.';
        $lines[] = '- Expected behavior vs actual behavior.';
        $lines[] = '- Exact page/listing/provider examples where the issue appears.';
        $lines[] = '';

        $max_items = 10;
        $visible_blockers = array_slice( $blockers, 0, $max_items );
        $hidden_count = max( 0, count( $blockers ) - count( $visible_blockers ) );
        $lines[] = 'Top blockers (ordered by severity)';
        if ( $blocker_count < 1 || empty( $blockers ) ) {
            $lines[] = '- None.';
        } else {
            $index = 1;
            foreach ( $visible_blockers as $blocker ) {
                if ( ! is_array( $blocker ) ) {
                    continue;
                }
                $label = trim( (string) ( $blocker['label'] ?? '' ) );
                if ( '' === $label ) {
                    $label = __( 'Unnamed diagnostic check', 'mybookaro' );
                }
                $check_id = sanitize_key( (string) ( $blocker['id'] ?? '' ) );
                $state = sanitize_key( (string) ( $blocker['state'] ?? 'info' ) );
                if ( ! isset( $state_labels[ $state ] ) ) {
                    $state = 'info';
                }
                $value = trim( (string) ( $blocker['value'] ?? '' ) );
                $title = sprintf( '%1$d) [%2$s] %3$s', $index, $state_labels[ $state ], $label );
                $lines[] = $title;

                if ( '' !== $check_id ) {
                    $lines[] = '   Check ID: ' . $check_id;
                }
                if ( '' !== $value ) {
                    $lines[] = '   Current value: ' . $value;
                }

                $problem = trim( (string) ( $blocker['summary'] ?? '' ) );
                if ( '' === $problem ) {
                    $problem = trim( (string) ( $blocker['detail'] ?? '' ) );
                }
                if ( '' !== $problem ) {
                    $lines[] = '   Problem: ' . $problem;
                }

                $fix = trim( (string) ( $blocker['fix'] ?? '' ) );
                if ( '' !== $fix && strtolower( $fix ) !== strtolower( $problem ) ) {
                    $lines[] = '   Suggested fix: ' . $fix;
                }

                $next_step = trim( (string) ( $blocker['next_step'] ?? '' ) );
                $next_step_lc = strtolower( $next_step );
                if (
                    '' !== $next_step
                    && $next_step_lc !== strtolower( $problem )
                    && $next_step_lc !== strtolower( $fix )
                ) {
                    $lines[] = '   Next step: ' . $next_step;
                }

                $action_label = trim( (string) ( $blocker['action_label'] ?? '' ) );
                $action_url = trim( (string) ( $blocker['action_url'] ?? '' ) );
                $action_path = $this->extract_action_path_for_summary( $action_url );
                if ( '' !== $action_label && '' !== $action_path ) {
                    $lines[] = '   Open in admin: ' . $action_label . ' -> ' . $action_path;
                } elseif ( '' !== $action_label ) {
                    $lines[] = '   Open in admin: ' . $action_label;
                } elseif ( '' !== $action_path ) {
                    $lines[] = '   Admin path: ' . $action_path;
                }

                $lines[] = '';
                $index++;
            }
        }

        if ( $hidden_count > 0 ) {
            $lines[] = sprintf(
                'Additional open items not shown here: %d (see full Text report and Support assistant checks).',
                $hidden_count
            );
            $lines[] = '';
        }

        $lines[] = 'Launch recommendation';
        if ( $error_count > 0 ) {
            $lines[] = '- Block launch until all FAIL items are fixed.';
        } elseif ( $warn_count > 0 ) {
            $lines[] = '- Launch may proceed with caution; resolve WARN items before go-live where possible.';
        } else {
            $lines[] = '- Safe to launch based on current checks.';
        }
        $lines[] = '';
        $lines[] = 'Next actions';
        $lines[] = '- Resolve FAIL items first, then WARN items.';
        $lines[] = '- Re-run System Status after every configuration/theme/plugin change and refresh this summary.';
        $lines[] = '';
        $lines[] = '=== END MYBOOKARO LAUNCH HANDOFF ===';

        $lines = array_map( [ $this, 'mask_report_text' ], $lines );
        return implode( "\n", $lines );
    }

    private function build_launch_blocker_quick_summary( array $launch_readiness ): string
    {
        $mode_label = trim( (string) ( $launch_readiness['mode_label'] ?? __( 'Unknown lane', 'mybookaro' ) ) );
        if ( '' === $mode_label ) {
            $mode_label = __( 'Unknown lane', 'mybookaro' );
        }
        $status_label = trim( (string) ( $launch_readiness['status_label'] ?? __( 'Unknown', 'mybookaro' ) ) );
        if ( '' === $status_label ) {
            $status_label = __( 'Unknown', 'mybookaro' );
        }
        $launch_ready = ! empty( $launch_readiness['launch_ready'] );
        $blocker_count = (int) ( $launch_readiness['blocker_count'] ?? 0 );
        $error_count = (int) ( $launch_readiness['error_count'] ?? 0 );
        $warn_count = (int) ( $launch_readiness['warn_count'] ?? 0 );
        $summary = trim( (string) ( $launch_readiness['summary'] ?? '' ) );
        $detail = trim( (string) ( $launch_readiness['detail'] ?? '' ) );

        $blockers = is_array( $launch_readiness['top_blockers'] ?? null ) ? $launch_readiness['top_blockers'] : [];
        if ( empty( $blockers ) && is_array( $launch_readiness['blockers'] ?? null ) ) {
            $blockers = array_slice( $launch_readiness['blockers'], 0, 5 );
        }

        $status_code = 'READY';
        if ( $error_count > 0 ) {
            $status_code = 'BLOCKED';
        } elseif ( $warn_count > 0 ) {
            $status_code = 'ATTENTION';
        }
        $launch_decision = 'GO';
        if ( $error_count > 0 ) {
            $launch_decision = 'NO-GO';
        } elseif ( $warn_count > 0 ) {
            $launch_decision = 'GO WITH CAUTION';
        }
        $handoff_subject = $this->build_launch_handoff_subject( $launch_readiness );
        $state_labels = [
            'error' => 'FAIL',
            'warn' => 'WARN',
            'ok' => 'PASS',
            'info' => 'INFO',
        ];

        $lines = [];
        $lines[] = '=== BEGIN MYBOOKARO QUICK HANDOFF ===';
        $lines[] = 'MyBookaro Launch Snapshot (Quick Summary)';
        $lines[] = 'Subject: ' . $handoff_subject;
        $lines[] = 'Generated: ' . date_i18n( 'Y-m-d H:i:s' );
        $lines[] = 'Lane: ' . $mode_label;
        $lines[] = 'Status: ' . $status_label . ' (' . $status_code . ')';
        $lines[] = 'Launch-ready: ' . ( $launch_ready ? 'Yes' : 'No' );
        $lines[] = 'Decision: ' . $launch_decision;
        $lines[] = sprintf(
            'Counts: blockers=%1$d | fail=%2$d | warn=%3$d',
            $blocker_count,
            $error_count,
            $warn_count
        );
        $lines[] = '';
        $lines[] = 'Summary';
        if ( '' !== $summary ) {
            $lines[] = '- ' . $summary;
        }
        if ( '' !== $detail ) {
            $lines[] = '- ' . $detail;
        }
        if ( '' === $summary && '' === $detail ) {
            $lines[] = '- No additional summary details were generated.';
        }
        $lines[] = '';
        $lines[] = 'Top items to fix';
        if ( $blocker_count < 1 || empty( $blockers ) ) {
            $lines[] = '- None. No launch blockers are currently open.';
        } else {
            $index = 1;
            foreach ( $blockers as $blocker ) {
                if ( ! is_array( $blocker ) ) {
                    continue;
                }
                $label = trim( (string) ( $blocker['label'] ?? '' ) );
                if ( '' === $label ) {
                    $label = __( 'Unnamed diagnostic check', 'mybookaro' );
                }
                $state = sanitize_key( (string) ( $blocker['state'] ?? 'info' ) );
                if ( ! isset( $state_labels[ $state ] ) ) {
                    $state = 'info';
                }
                $lines[] = sprintf( '%1$d. [%2$s] %3$s', $index, $state_labels[ $state ], $label );

                $problem = trim( (string) ( $blocker['summary'] ?? '' ) );
                if ( '' === $problem ) {
                    $problem = trim( (string) ( $blocker['detail'] ?? '' ) );
                }
                if ( '' !== $problem ) {
                    $lines[] = '   Problem: ' . $problem;
                }

                $fix = trim( (string) ( $blocker['next_step'] ?? '' ) );
                if ( '' === $fix ) {
                    $fix = trim( (string) ( $blocker['fix'] ?? '' ) );
                }
                if ( '' !== $fix && strtolower( $fix ) !== strtolower( $problem ) ) {
                    $lines[] = '   Fix: ' . $fix;
                }

                $action_label = trim( (string) ( $blocker['action_label'] ?? '' ) );
                $action_url = trim( (string) ( $blocker['action_url'] ?? '' ) );
                $action_path = $this->extract_action_path_for_summary( $action_url );
                if ( '' !== $action_label && '' !== $action_path ) {
                    $lines[] = '   Open: ' . $action_label . ' -> ' . $action_path;
                } elseif ( '' !== $action_label ) {
                    $lines[] = '   Open: ' . $action_label;
                }

                $index++;
            }
        }
        $lines[] = '';
        $lines[] = 'Share checklist';
        $lines[] = '- Paste this quick handoff block into support or internal chat first.';
        $lines[] = '- Attach full Text report and Support Bundle JSON.';
        $lines[] = '- Review Getting Started > Operational summary before escalating support.';
        $lines[] = '- Single Business: no listings required. Confirm Default Provider + booking/services/dashboard pages.';
        $lines[] = '- Re-run System Status after fixes and share an updated snapshot.';
        $lines[] = '=== END MYBOOKARO QUICK HANDOFF ===';

        $lines = array_map( [ $this, 'mask_report_text' ], $lines );
        return implode( "\n", $lines );
    }

    private function build_support_share_summary( array $launch_readiness ): string
    {
        $mode_label = trim( (string) ( $launch_readiness['mode_label'] ?? __( 'Unknown lane', 'mybookaro' ) ) );
        if ( '' === $mode_label ) {
            $mode_label = __( 'Unknown lane', 'mybookaro' );
        }
        $status_label = trim( (string) ( $launch_readiness['status_label'] ?? __( 'Unknown', 'mybookaro' ) ) );
        if ( '' === $status_label ) {
            $status_label = __( 'Unknown', 'mybookaro' );
        }

        $blocker_count = (int) ( $launch_readiness['blocker_count'] ?? 0 );
        $error_count = (int) ( $launch_readiness['error_count'] ?? 0 );
        $warn_count = (int) ( $launch_readiness['warn_count'] ?? 0 );
        $summary = trim( (string) ( $launch_readiness['summary'] ?? '' ) );

        $blockers = is_array( $launch_readiness['top_blockers'] ?? null ) ? $launch_readiness['top_blockers'] : [];
        if ( empty( $blockers ) && is_array( $launch_readiness['blockers'] ?? null ) ) {
            $blockers = array_slice( $launch_readiness['blockers'], 0, 3 );
        } else {
            $blockers = array_slice( $blockers, 0, 3 );
        }

        $state_labels = [
            'error' => 'FAIL',
            'warn' => 'WARN',
            'ok' => 'PASS',
            'info' => 'INFO',
        ];

        $lines = [];
        $lines[] = '=== BEGIN MYBOOKARO SUPPORT SNAPSHOT ===';
        $lines[] = 'MyBookaro Support Snapshot (Masked, Compact)';
        $lines[] = 'Generated: ' . date_i18n( 'Y-m-d H:i:s' );
        $lines[] = 'Lane: ' . $mode_label;
        $lines[] = 'Status: ' . $status_label;
        $lines[] = sprintf(
            'Counts: fail=%1$d | warn=%2$d | blockers=%3$d',
            $error_count,
            $warn_count,
            $blocker_count
        );
        if ( '' !== $summary ) {
            $lines[] = 'Summary: ' . $summary;
        }
        $lines[] = '';
        $lines[] = 'Top blockers to fix first';
        if ( $blocker_count < 1 || empty( $blockers ) ) {
            $lines[] = '- None. No active blockers in this snapshot.';
        } else {
            $index = 1;
            foreach ( $blockers as $blocker ) {
                if ( ! is_array( $blocker ) ) {
                    continue;
                }
                $label = trim( (string) ( $blocker['label'] ?? '' ) );
                if ( '' === $label ) {
                    $label = __( 'Unnamed diagnostic check', 'mybookaro' );
                }
                $state = sanitize_key( (string) ( $blocker['state'] ?? 'info' ) );
                if ( ! isset( $state_labels[ $state ] ) ) {
                    $state = 'info';
                }
                $next = trim( (string) ( $blocker['next_step'] ?? '' ) );
                if ( '' === $next ) {
                    $next = trim( (string) ( $blocker['fix'] ?? '' ) );
                }
                if ( '' === $next ) {
                    $next = trim( (string) ( $blocker['summary'] ?? '' ) );
                }

                $lines[] = sprintf( '%1$d) [%2$s] %3$s', $index, $state_labels[ $state ], $label );
                if ( '' !== $next ) {
                    $lines[] = '   Next: ' . $next;
                }

                $index++;
            }
        }
        $lines[] = '';
        $lines[] = 'Before opening support requests';
        $lines[] = '- Re-run System Status after the latest setup/code changes.';
        $lines[] = '- Review Getting Started > Operational summary for active safeguards and defaults.';
        $lines[] = '- Single Business: no listings required. Confirm Default Provider + booking/services/dashboard pages.';
        $lines[] = '- Share this masked snapshot first, then attach Support Bundle JSON if deeper diagnostics are needed.';
        $lines[] = '=== END MYBOOKARO SUPPORT SNAPSHOT ===';

        $lines = array_map( [ $this, 'mask_report_text' ], $lines );
        return implode( "\n", $lines );
    }

    private function build_launch_handoff_subject( array $launch_readiness ): string
    {
        $mode_label = trim( (string) ( $launch_readiness['mode_label'] ?? __( 'Unknown lane', 'mybookaro' ) ) );
        if ( '' === $mode_label ) {
            $mode_label = __( 'Unknown lane', 'mybookaro' );
        }

        $error_count = (int) ( $launch_readiness['error_count'] ?? 0 );
        $warn_count = (int) ( $launch_readiness['warn_count'] ?? 0 );

        $status_code = 'READY';
        if ( $error_count > 0 ) {
            $status_code = 'BLOCKED';
        } elseif ( $warn_count > 0 ) {
            $status_code = 'ATTENTION';
        }

        $summary_id_payload = wp_json_encode( [
            'mode' => (string) ( $launch_readiness['mode'] ?? '' ),
            'status' => (string) ( $launch_readiness['status'] ?? '' ),
            'error_count' => $error_count,
            'warn_count' => $warn_count,
            'blocker_count' => (int) ( $launch_readiness['blocker_count'] ?? 0 ),
        ] );
        $summary_id = 'n/a';
        if ( is_string( $summary_id_payload ) && '' !== $summary_id_payload ) {
            $summary_id = substr( hash( 'sha256', $summary_id_payload ), 0, 8 );
        }

        return sprintf(
            'MyBookaro launch handoff | %1$s | %2$s | fail=%3$d warn=%4$d | %5$s',
            $status_code,
            $mode_label,
            $error_count,
            $warn_count,
            $summary_id
        );
    }

    private function build_launch_handoff_message( string $subject, string $quick_summary ): string
    {
        $subject = trim( $subject );
        $quick_summary = trim( $quick_summary );

        $lines = [];
        if ( '' !== $subject ) {
            $lines[] = 'Subject: ' . $subject;
            $lines[] = '';
        }
        $lines[] = 'Before opening support requests: run System Status, refresh this handoff after your latest changes, and start with the masked support snapshot.';
        $lines[] = '';
        $lines[] = 'Paste the section below in support/internal handoff:';
        $lines[] = '';
        $lines[] = $quick_summary !== '' ? $quick_summary : 'No quick handoff summary is available.';
        $lines[] = '';
        $lines[] = 'Context to add before sending:';
        $lines[] = '- Attach Support Bundle JSON only when the masked snapshot is not enough';
        $lines[] = '- Confirm Operational summary review (Getting Started > Operational summary)';
        $lines[] = '- Single Business: no listings required; confirm Default Provider + booking/services/dashboard pages';
        $lines[] = '- Affected URL(s) and listing/provider IDs';
        $lines[] = '- What changed before the issue appeared';
        $lines[] = '- Expected behavior vs actual behavior';

        $lines = array_map( [ $this, 'mask_report_text' ], $lines );
        return implode( "\n", $lines );
    }

    private function extract_action_path_for_summary( string $url ): string
    {
        $url = trim( $url );
        if ( '' === $url ) {
            return '';
        }

        // Keep local anchors untouched for in-page support checks.
        if ( '#' === substr( $url, 0, 1 ) ) {
            return $url;
        }

        // Already a relative path.
        if ( '/' === substr( $url, 0, 1 ) ) {
            return $url;
        }

        $parts = wp_parse_url( $url );
        if ( ! is_array( $parts ) ) {
            return '';
        }

        $path = isset( $parts['path'] ) ? (string) $parts['path'] : '';
        if ( '' === $path ) {
            return '';
        }
        if ( isset( $parts['query'] ) && (string) $parts['query'] !== '' ) {
            $path .= '?' . (string) $parts['query'];
        }
        if ( isset( $parts['fragment'] ) && (string) $parts['fragment'] !== '' ) {
            $path .= '#' . (string) $parts['fragment'];
        }

        return $path;
    }

    private function build_report(
        array $db_status,
        array $cron_status,
        array $api_status,
        array $integration_status,
        array $environment_status,
        array $license_status,
        array $settings_status,
        array $dashboard_status,
        array $generic_status,
        array $services_cache_status,
        array $support_checks,
        array $launch_readiness = []
    ): string {
        $lines = [];
        $lines[] = 'MyBookaro System Status';
        $lines[] = 'Generated: ' . date_i18n( 'Y-m-d H:i:s' );
        $lines[] = '';
        $lines[] = 'Launch Readiness';
        $lines[] = 'Lane: ' . (string) ( $launch_readiness['mode_label'] ?? 'Unknown lane' );
        $lines[] = 'Status: ' . (string) ( $launch_readiness['status_label'] ?? 'Unknown' );
        $lines[] = 'Launch-ready: ' . ( ! empty( $launch_readiness['launch_ready'] ) ? 'Yes' : 'No' );
        $lines[] = sprintf(
            'Blockers: %1$d error(s), %2$d warning(s)',
            (int) ( $launch_readiness['error_count'] ?? 0 ),
            (int) ( $launch_readiness['warn_count'] ?? 0 )
        );
        if ( ! empty( $launch_readiness['top_blockers'] ) && is_array( $launch_readiness['top_blockers'] ) ) {
            $lines[] = 'Top blockers:';
            foreach ( $launch_readiness['top_blockers'] as $launch_blocker ) {
                if ( ! is_array( $launch_blocker ) ) {
                    continue;
                }
                $state = strtoupper( sanitize_key( (string) ( $launch_blocker['state'] ?? 'info' ) ) );
                $label = trim( (string) ( $launch_blocker['label'] ?? '' ) );
                if ( '' !== $label ) {
                    $lines[] = sprintf( '  - [%1$s] %2$s', $state, $label );
                }
                $blocker_summary = trim( (string) ( $launch_blocker['summary'] ?? '' ) );
                if ( '' !== $blocker_summary ) {
                    $lines[] = '    ' . $blocker_summary;
                }
            }
        }
        $lines[] = '';
        $lines[] = 'Database';
        $lines[] = 'Schema version: installed ' . $db_status['schema_installed'] . ' / expected ' . $db_status['schema_expected'];
        foreach ( $db_status['tables'] as $name => $ok ) {
            $lines[] = sprintf( 'Table %s: %s', $name, $ok ? 'OK' : 'MISSING' );
        }
        $lines[] = '';
        $lines[] = 'Cron';
        $lines[] = 'WP-Cron disabled: ' . ( $cron_status['wp_cron_disabled'] ? 'Yes' : 'No' );
        $lines[] = 'Auto-complete scheduled: ' . ( $cron_status['auto_complete_scheduled'] ? 'Yes' : 'No' );
        if ( $cron_status['auto_complete_next'] ) {
            $lines[] = 'Auto-complete next run: ' . date_i18n( 'Y-m-d H:i:s', $cron_status['auto_complete_next'] );
        }
        $lines[] = '';
        $lines[] = 'API';
        $lines[] = 'REST accessible: ' . ( $api_status['rest_ok'] ? 'Yes' : 'No' );
        $lines[] = 'REST URL: ' . ( $api_status['rest_url_masked'] ?? $api_status['rest_url'] );
        if ( ! empty( $api_status['rest_http_code'] ) ) {
            $lines[] = 'REST HTTP code: ' . (int) $api_status['rest_http_code'];
        }
        if ( ! empty( $api_status['rest_access_error'] ) ) {
            $lines[] = 'REST error: ' . (string) $api_status['rest_access_error'];
        }
        $lines[] = 'AJAX accessible: ' . ( $api_status['ajax_ok'] ? 'Yes' : 'No' );
        $lines[] = 'AJAX URL: ' . ( $api_status['ajax_url_masked'] ?? $api_status['ajax_url'] );
        if ( ! empty( $api_status['ajax_http_code'] ) ) {
            $lines[] = 'AJAX HTTP code: ' . (int) $api_status['ajax_http_code'];
        }
        if ( ! empty( $api_status['ajax_access_error'] ) ) {
            $lines[] = 'AJAX error: ' . (string) $api_status['ajax_access_error'];
        }
        $lines[] = '';
        $lines[] = 'Environment';
        $lines[] = 'WordPress: ' . ( $environment_status['wp_version'] ?? '' );
        $lines[] = 'PHP: ' . ( $environment_status['php_version'] ?? '' );
        $lines[] = 'MyBookaro: ' . ( $environment_status['bookaro_version'] ?? '' );
        $lines[] = 'MyBookaro Pro: ' . ( $environment_status['bookaro_pro_version'] !== '' ? $environment_status['bookaro_pro_version'] : 'Not installed' );
        $theme_label = trim( (string) ( $environment_status['theme_name'] ?? '' ) . ' ' . (string) ( $environment_status['theme_version'] ?? '' ) );
        if ( $theme_label !== '' ) {
            if ( ! empty( $environment_status['theme_parent'] ) ) {
                $theme_label .= ' (Child of ' . (string) $environment_status['theme_parent'] . ')';
            }
            $lines[] = 'Theme: ' . $theme_label;
        }
        if ( ! empty( $environment_status['active_plugins'] ) ) {
            $lines[] = 'Active plugins (' . (int) ( $environment_status['active_plugins_count'] ?? count( $environment_status['active_plugins'] ) ) . '): ' . implode( ', ', (array) $environment_status['active_plugins'] );
        }
        $lines[] = '';
        $lines[] = 'Integrations';
        $lines[] = 'MyListing detected: ' . ( $integration_status['mylisting_detected'] ? 'Yes' : 'No' );
        $lines[] = 'MyListing hook registered: ' . ( $integration_status['mylisting_hook_ok'] ? 'Yes' : 'No' );
        $lines[] = 'MyListing repeater class: ' . ( $integration_status['mylisting_repeater_class'] ?? 'mybookaro_services' );
        $lines[] = 'MyListing repeater class configured: ' . ( ! empty( $integration_status['mylisting_repeater_class_configured'] ) ? 'Yes' : 'No' );
        $mylisting_sample_listing_id = absint( $integration_status['mylisting_sample_listing_id'] ?? 0 );
        $lines[] = 'MyListing sample listing ID: ' . ( $mylisting_sample_listing_id > 0 ? (string) $mylisting_sample_listing_id : 'None' );
        $mylisting_services_diagnostics = is_array( $integration_status['mylisting_services_diagnostics'] ?? null )
            ? $integration_status['mylisting_services_diagnostics']
            : [];
        if ( ! empty( $mylisting_services_diagnostics ) ) {
            $lines[] = 'MyListing services reason: ' . sanitize_key( (string) ( $mylisting_services_diagnostics['reason_code'] ?? '' ) );
            $lines[] = 'MyListing services path: ' . sanitize_key( (string) ( $mylisting_services_diagnostics['resolution_path'] ?? '' ) );
            $lines[] = 'MyListing resolved services: ' . (int) ( $mylisting_services_diagnostics['resolved_services_count'] ?? 0 );
            $lines[] = 'MyListing service-like rows: ' . (int) ( $mylisting_services_diagnostics['row_count_service_like'] ?? 0 );
            $lines[] = 'MyListing class mismatches: ' . (int) ( $mylisting_services_diagnostics['row_count_class_mismatch'] ?? 0 );
            if ( ! empty( $mylisting_services_diagnostics['detected_classes'] ) ) {
                $lines[] = 'MyListing detected row classes: ' . implode( ', ', array_map( 'sanitize_key', (array) $mylisting_services_diagnostics['detected_classes'] ) );
            }
            if ( ! empty( $mylisting_services_diagnostics['detected_prefixes'] ) ) {
                $lines[] = 'MyListing detected service prefixes: ' . implode( ', ', array_map( 'sanitize_key', (array) $mylisting_services_diagnostics['detected_prefixes'] ) );
            }
        }
        $lines[] = 'Payments enabled: ' . ( $integration_status['payments_enabled'] ? 'Yes' : 'No' );
        $lines[] = 'WooCommerce present: ' . ( $integration_status['woocommerce_present'] ? 'Yes' : 'No' );
        $lines[] = '';
        $lines[] = 'Settings';
        $lines[] = 'Timezone: ' . $settings_status['timezone'];
        $lines[] = 'Frontend enabled: ' . ( $settings_status['frontend_enabled'] ? 'Yes' : 'No' );
        $lines[] = 'Spam protection enabled: ' . ( ! empty( $settings_status['spam_protection_enabled'] ) ? 'Yes' : 'No' );
        $lines[] = 'Spam honeypot enabled: ' . ( ! empty( $settings_status['spam_honeypot_enabled'] ) ? 'Yes' : 'No' );
        $lines[] = 'Spam min fill seconds: ' . (int) ( $settings_status['spam_min_fill_seconds'] ?? 0 );
        $lines[] = 'Spam burst window seconds: ' . (int) ( $settings_status['spam_burst_window_seconds'] ?? 0 );
        $lines[] = 'Spam burst IP limit: ' . (int) ( $settings_status['spam_burst_ip_limit'] ?? 0 );
        $lines[] = 'Spam burst email limit: ' . (int) ( $settings_status['spam_burst_email_limit'] ?? 0 );
        $lines[] = 'Duplicate pending window hours: ' . (int) ( $settings_status['spam_duplicate_pending_hours'] ?? 0 );
        $lines[] = 'Spam blacklist words: ' . (int) ( $settings_status['spam_blacklist_words_count'] ?? 0 );
        $lines[] = 'Spam blocks total: ' . (int) ( $settings_status['spam_total_blocks'] ?? 0 );
        if ( ! empty( $settings_status['spam_block_reasons'] ) && is_array( $settings_status['spam_block_reasons'] ) ) {
            $parts = [];
            foreach ( $settings_status['spam_block_reasons'] as $reason => $count ) {
                $parts[] = sanitize_key( (string) $reason ) . ':' . absint( $count );
            }
            if ( ! empty( $parts ) ) {
                $lines[] = 'Spam blocks by reason: ' . implode( ', ', $parts );
            }
        }
        if ( ! empty( $settings_status['spam_last_blocked_at'] ) ) {
            $lines[] = 'Spam last blocked at: ' . date_i18n( 'Y-m-d H:i:s', (int) $settings_status['spam_last_blocked_at'] );
        }
        if ( ! empty( $license_status['pro_active'] ) ) {
            $lines[] = '';
            $lines[] = 'License';
            $lines[] = 'Status: ' . ( $license_status['license_status'] !== '' ? $license_status['license_status'] : 'Unknown' );
            $lines[] = 'Expires: ' . ( $license_status['license_expires'] !== '' ? $license_status['license_expires'] : 'Unknown' );
            $lines[] = 'Last check: ' . ( ! empty( $license_status['license_last_check'] ) ? date_i18n( 'Y-m-d H:i:s', (int) $license_status['license_last_check'] ) : 'Never' );
            $lines[] = 'Updates enabled: ' . ( ! empty( $license_status['updates_enabled'] ) ? 'Yes' : 'No' );
            if ( ! empty( $license_status['update_last_error_code'] ) ) {
                $lines[] = 'Last update error: ' . (string) $license_status['update_last_error_code'];
            }
        }
        $lines[] = '';
        $lines[] = 'Dashboards';
        $lines[] = 'UI mode: ' . ( $dashboard_status['ui_mode'] ?? $this->get_default_ui_mode_for_integration_mode() );
        $lines[] = 'Provider dashboard page: ' . ( ! empty( $dashboard_status['provider_page_id'] ) ? (int) $dashboard_status['provider_page_id'] : 'Not set' );
        $lines[] = 'Customer dashboard page: ' . ( ! empty( $dashboard_status['customer_page_id'] ) ? (int) $dashboard_status['customer_page_id'] : 'Not set' );
        $provider_role_line = 'Provider role: ' . ( $dashboard_status['provider_role_key'] ?? '' );
        $provider_role_line .= ' (cap: ' . ( ! empty( $dashboard_status['provider_role_has_cap'] ) ? 'Yes' : 'No' ) . ')';
        $lines[] = $provider_role_line;
        $customer_role_line = 'Customer role: ' . ( $dashboard_status['customer_role_key'] ?? '' );
        $customer_role_line .= ' (cap: ' . ( ! empty( $dashboard_status['customer_role_has_cap'] ) ? 'Yes' : 'No' ) . ')';
        $lines[] = $customer_role_line;
        $lines[] = '';
        $lines[] = 'Product lane snapshot';
        $site_type = $this->normalize_site_type( (string) ( $generic_status['site_type'] ?? 'directory' ) );
        $site_type_label_map = [
            'directory' => 'Directory lanes (MyListing Directory or Generic Directory)',
            'single_business' => 'Single Business lane',
            'advanced_mapping' => 'Generic Directory (legacy compatibility state active)',
        ];
        $lines[] = 'Lane profile: ' . ( $site_type_label_map[ $site_type ] ?? 'Directory lanes (MyListing Directory or Generic Directory)' );
        $lines[] = 'Lane: ' . (string) ( $generic_status['lane_label'] ?? $this->get_product_lane_label( (string) ( $generic_status['lane_id'] ?? '' ) ) );
        $mode_label = $generic_status['integration_setting'];
        if ( $generic_status['integration_setting'] !== $generic_status['integration_resolved'] ) {
            $mode_label .= ' (resolved: ' . $generic_status['integration_resolved'] . ')';
        }
        $lines[] = 'Directory lane choice setting: ' . $mode_label;
        if ( ! empty( $generic_status['integration_reason'] ) ) {
            $lines[] = 'Directory lane reason: ' . $generic_status['integration_reason'];
        }
        $lines[] = 'Generic confirmation required: ' . ( ! empty( $generic_status['generic_confirmation_required'] ) ? 'Yes' : 'No' );
        $lines[] = 'Generic setup confirmed: ' . ( ! empty( $generic_status['generic_setup_confirmed'] ) ? 'Yes' : 'No' );
        $lines[] = 'Generic setup explicitly confirmed: ' . ( ! empty( $generic_status['generic_setup_explicitly_confirmed'] ) ? 'Yes' : 'No' );
        $lines[] = 'Generic legacy fallback active: ' . ( ! empty( $generic_status['generic_legacy_fallback_active'] ) ? 'Yes' : 'No' );
        if ( ! empty( $generic_status['generic_setup_confirmed_at'] ) ) {
            $lines[] = 'Generic setup confirmed at: ' . date_i18n( 'Y-m-d H:i:s', (int) $generic_status['generic_setup_confirmed_at'] );
        }
        if ( ! empty( $generic_status['generic_setup_confirmation_source'] ) ) {
            $lines[] = 'Generic setup confirmation source: ' . sanitize_key( (string) $generic_status['generic_setup_confirmation_source'] );
        }
        $lines[] = 'Generic setup completed: ' . ( ! empty( $generic_status['generic_setup_completed'] ) ? 'Yes' : 'No' );
        $types = $generic_status['allowed_listing_type_labels'] ?? [];
        $lines[] = 'Allowed listing types: ' . ( ! empty( $types ) ? implode( ', ', $types ) : 'None configured' );
        $pages = $generic_status['allowed_listing_page_labels'] ?? [];
        $lines[] = 'Allowed listing pages: ' . ( ! empty( $pages ) ? implode( ', ', $pages ) : 'All pages' );
        $provider_line = 'Provider mapping: ' . $generic_status['provider_resolution_mode'];
        if ( ! empty( $generic_status['provider_resolution_mode_raw'] ) ) {
            $provider_line .= ' (raw: ' . $generic_status['provider_resolution_mode_raw'] . ')';
        }
        if ( ! empty( $generic_status['provider_meta_key'] ) ) {
            $provider_line .= ' (meta key: ' . $generic_status['provider_meta_key'] . ')';
        }
        // Generic provider mapping is reported via provider_meta_key only.
        $lines[] = $provider_line;
        $lines[] = 'Services mode: ' . $generic_status['services_mode'];
        $lines[] = 'Effective services model: ' . (string) ( $generic_status['services_model_effective'] ?? 'hybrid' );
        $lines[] = 'Placement strategy: ' . (string) ( $generic_status['booking_placement_strategy'] ?? 'directory_template' );
        $lines[] = 'Listing services cache enabled: ' . ( ! empty( $services_cache_status['cache_enabled'] ) ? 'Yes' : 'No' );
        $lines[] = 'Listing services cache TTL (seconds): ' . (int) ( $services_cache_status['cache_ttl'] ?? 0 );
        $lines[] = 'Listing services global cache version: ' . (int) ( $services_cache_status['global_version'] ?? 0 );
        if ( ! empty( $services_cache_status['global_version_timestamp'] ) ) {
            $lines[] = 'Listing services global cache last bump: ' . date_i18n( 'Y-m-d H:i:s', (int) $services_cache_status['global_version_timestamp'] );
        }
        $lines[] = 'Listing services invalidation hooks registered: ' . ( ! empty( $services_cache_status['invalidation_hooks_ok'] ) ? 'Yes' : 'No' );
        if ( ! empty( $services_cache_status['missing_invalidation_hooks'] ) && is_array( $services_cache_status['missing_invalidation_hooks'] ) ) {
            $lines[] = 'Missing invalidation hooks: ' . implode( ', ', array_map( 'sanitize_key', $services_cache_status['missing_invalidation_hooks'] ) );
        }
        $lines[] = 'Listing services cache-buster meta key: ' . (string) ( $services_cache_status['listing_buster_meta_key'] ?? 'bookaro_services_cache_buster' );
        $global_pages = $generic_status['global_pages'] ?? [];
        $lines[] = 'Booking page override: ' . ( ! empty( $global_pages['booking'] ) ? (int) $global_pages['booking'] : 'Not set' );
        $lines[] = 'Provider dashboard override: ' . ( ! empty( $global_pages['provider_dashboard'] ) ? (int) $global_pages['provider_dashboard'] : 'Not set' );
        $lines[] = 'Customer dashboard override: ' . ( ! empty( $global_pages['customer_dashboard'] ) ? (int) $global_pages['customer_dashboard'] : 'Not set' );
        if ( ! empty( $generic_status['default_provider'] ) ) {
            $lines[] = 'Default provider: ' . (string) $generic_status['default_provider']['label'];
        }
        $lines[] = '';
        $lines[] = 'Support Diagnostics';
        foreach ( $support_checks as $check ) {
            $label = (string) ( $check['label'] ?? '' );
            $state = strtoupper( (string) ( $check['state'] ?? 'info' ) );
            $value = (string) ( $check['value'] ?? '' );
            $detail = (string) ( $check['detail'] ?? '' );
            $next_step = (string) ( $check['next_step'] ?? '' );
            $line = trim( $label . ': ' . $state . ( $value !== '' ? ' (' . $value . ')' : '' ) );
            if ( $line !== '' ) {
                $lines[] = $line;
            }
            if ( $detail !== '' ) {
                $lines[] = '  - ' . $detail;
            }
            if ( ! empty( $check['needs_fix'] ) && ! empty( $check['fix'] ) ) {
                $lines[] = '  - Suggested fix: ' . (string) $check['fix'];
            }
            if ( ! empty( $check['needs_fix'] ) && $next_step !== '' ) {
                $lines[] = '  - ' . $next_step;
            }
        }

        $lines = array_map( [ $this, 'mask_report_text' ], $lines );

        return implode( "\n", $lines );
    }

    private function build_export_payload(
        array $db_status,
        array $cron_status,
        array $api_status,
        array $integration_status,
        array $environment_status,
        array $license_status,
        array $settings_status,
        array $dashboard_status,
        array $generic_status,
        array $services_cache_status,
        array $support_checks,
        array $orphan_status,
        array $launch_readiness = []
    ): array {
        $allowed_types = $generic_status['allowed_listing_types'] ?? [];
        if ( ! is_array( $allowed_types ) ) {
            $allowed_types = [];
        }
        $allowed_pages = $generic_status['allowed_listing_pages'] ?? [];
        if ( ! is_array( $allowed_pages ) ) {
            $allowed_pages = [];
        }
        $launch_blocker_quick_summary = $this->build_launch_blocker_quick_summary( $launch_readiness );
        $launch_blocker_summary = $this->build_launch_blocker_summary( $launch_readiness );
        $support_share_summary = $this->build_support_share_summary( $launch_readiness );

        return [
            'generated_at' => date_i18n( 'c' ),
            'integration' => [
                'site_type' => $generic_status['site_type'] ?? 'directory',
                'lane_id' => $generic_status['lane_id'] ?? '',
                'lane_label' => $generic_status['lane_label'] ?? '',
                'lane_blueprint' => is_array( $generic_status['lane_blueprint'] ?? null ) ? $generic_status['lane_blueprint'] : [],
                'setting' => $generic_status['integration_setting'] ?? 'auto',
                'resolved' => $generic_status['integration_resolved'] ?? '',
                'reason' => $generic_status['integration_reason'] ?? '',
                'generic_confirmation_required' => ! empty( $generic_status['generic_confirmation_required'] ),
                'generic_setup_confirmed' => ! empty( $generic_status['generic_setup_confirmed'] ),
                'generic_setup_explicitly_confirmed' => ! empty( $generic_status['generic_setup_explicitly_confirmed'] ),
                'generic_legacy_fallback_active' => ! empty( $generic_status['generic_legacy_fallback_active'] ),
                'generic_setup_completed' => ! empty( $generic_status['generic_setup_completed'] ),
                'generic_setup_confirmed_at' => (int) ( $generic_status['generic_setup_confirmed_at'] ?? 0 ),
                'generic_setup_confirmation_source' => sanitize_key( (string) ( $generic_status['generic_setup_confirmation_source'] ?? '' ) ),
                'mylisting_detected' => ! empty( $integration_status['mylisting_detected'] ),
                'mylisting_hook_registered' => ! empty( $integration_status['mylisting_hook_ok'] ),
                'mylisting_repeater_class' => $integration_status['mylisting_repeater_class'] ?? 'mybookaro_services',
                'mylisting_repeater_class_configured' => ! empty( $integration_status['mylisting_repeater_class_configured'] ),
                'mylisting_sample_listing_id' => absint( $integration_status['mylisting_sample_listing_id'] ?? 0 ),
                'mylisting_services_diagnostics' => is_array( $integration_status['mylisting_services_diagnostics'] ?? null )
                    ? $integration_status['mylisting_services_diagnostics']
                    : [],
                'booking_placement_strategy' => $generic_status['booking_placement_strategy'] ?? '',
            ],
            'listing' => [
                'allowed_post_types' => array_values( array_unique( array_filter( array_map( 'sanitize_key', $allowed_types ) ) ) ),
                'allowed_pages' => array_values( array_unique( array_filter( array_map( 'absint', $allowed_pages ) ) ) ),
            ],
            'provider_mapping' => [
                'mode' => $generic_status['provider_resolution_mode'] ?? 'author',
                'meta_key' => $generic_status['provider_meta_key'] ?? '',
            ],
            'services' => [
                'model' => $generic_status['services_mode'] ?? 'provider_only',
                'cache' => [
                    'enabled' => ! empty( $services_cache_status['cache_enabled'] ),
                    'ttl_seconds' => (int) ( $services_cache_status['cache_ttl'] ?? 0 ),
                    'global_version' => (int) ( $services_cache_status['global_version'] ?? 0 ),
                    'global_version_timestamp' => (int) ( $services_cache_status['global_version_timestamp'] ?? 0 ),
                    'invalidation_hooks_ok' => ! empty( $services_cache_status['invalidation_hooks_ok'] ),
                    'missing_invalidation_hooks' => array_values( array_map(
                        'sanitize_key',
                        is_array( $services_cache_status['missing_invalidation_hooks'] ?? null )
                            ? $services_cache_status['missing_invalidation_hooks']
                            : []
                    ) ),
                    'listing_buster_meta_key' => sanitize_key( (string) ( $services_cache_status['listing_buster_meta_key'] ?? 'bookaro_services_cache_buster' ) ),
                ],
            ],
            'cron' => [
                'wp_cron_disabled' => ! empty( $cron_status['wp_cron_disabled'] ),
                'auto_complete_scheduled' => ! empty( $cron_status['auto_complete_scheduled'] ),
                'auto_complete_next' => (int) ( $cron_status['auto_complete_next'] ?? 0 ),
            ],
            'db' => [
                'schema_installed' => (int) ( $db_status['schema_installed'] ?? 0 ),
                'schema_expected' => (int) ( $db_status['schema_expected'] ?? 0 ),
                'tables' => $db_status['tables'] ?? [],
            ],
            'api' => [
                'rest_enabled' => ! empty( $api_status['rest_ok'] ),
                'rest_url' => $api_status['rest_url_masked'] ?? ( $api_status['rest_url'] ?? '' ),
                'rest_http_code' => (int) ( $api_status['rest_http_code'] ?? 0 ),
                'rest_access_error' => $api_status['rest_access_error'] ?? '',
                'ajax_url' => $api_status['ajax_url_masked'] ?? ( $api_status['ajax_url'] ?? '' ),
                'ajax_enabled' => ! empty( $api_status['ajax_ok'] ),
                'ajax_http_code' => (int) ( $api_status['ajax_http_code'] ?? 0 ),
                'ajax_access_error' => $api_status['ajax_access_error'] ?? '',
            ],
            'environment' => [
                'wp_version' => $environment_status['wp_version'] ?? '',
                'php_version' => $environment_status['php_version'] ?? '',
                'bookaro_version' => $environment_status['bookaro_version'] ?? '',
                'bookaro_pro_version' => $environment_status['bookaro_pro_version'] ?? '',
                'theme' => [
                    'name' => $environment_status['theme_name'] ?? '',
                    'version' => $environment_status['theme_version'] ?? '',
                    'parent' => $environment_status['theme_parent'] ?? '',
                ],
                'active_plugins' => $environment_status['active_plugins'] ?? [],
            ],
            'settings' => [
                'timezone' => $settings_status['timezone'] ?? '',
                'frontend_enabled' => ! empty( $settings_status['frontend_enabled'] ),
                'spam_protection_enabled' => ! empty( $settings_status['spam_protection_enabled'] ),
                'spam_honeypot_enabled' => ! empty( $settings_status['spam_honeypot_enabled'] ),
                'spam_min_fill_seconds' => (int) ( $settings_status['spam_min_fill_seconds'] ?? 0 ),
                'spam_burst_window_seconds' => (int) ( $settings_status['spam_burst_window_seconds'] ?? 0 ),
                'spam_burst_ip_limit' => (int) ( $settings_status['spam_burst_ip_limit'] ?? 0 ),
                'spam_burst_email_limit' => (int) ( $settings_status['spam_burst_email_limit'] ?? 0 ),
                'spam_duplicate_pending_hours' => (int) ( $settings_status['spam_duplicate_pending_hours'] ?? 0 ),
                'spam_blacklist_words_count' => (int) ( $settings_status['spam_blacklist_words_count'] ?? 0 ),
                'spam_total_blocks' => (int) ( $settings_status['spam_total_blocks'] ?? 0 ),
                'spam_last_blocked_at' => (int) ( $settings_status['spam_last_blocked_at'] ?? 0 ),
                'spam_last_reason' => sanitize_key( (string) ( $settings_status['spam_last_reason'] ?? '' ) ),
                'spam_block_reasons' => array_map(
                    'absint',
                    is_array( $settings_status['spam_block_reasons'] ?? null ) ? $settings_status['spam_block_reasons'] : []
                ),
            ],
            'dashboards' => [
                'ui_mode' => $dashboard_status['ui_mode'] ?? $this->get_default_ui_mode_for_integration_mode(),
                'frontend_enabled' => ! empty( $dashboard_status['frontend_enabled'] ),
                'provider_page_id' => (int) ( $dashboard_status['provider_page_id'] ?? 0 ),
                'customer_page_id' => (int) ( $dashboard_status['customer_page_id'] ?? 0 ),
                'provider_role' => $dashboard_status['provider_role_key'] ?? '',
                'customer_role' => $dashboard_status['customer_role_key'] ?? '',
                'provider_role_exists' => ! empty( $dashboard_status['provider_role_exists'] ),
                'customer_role_exists' => ! empty( $dashboard_status['customer_role_exists'] ),
                'provider_role_has_cap' => ! empty( $dashboard_status['provider_role_has_cap'] ),
                'customer_role_has_cap' => ! empty( $dashboard_status['customer_role_has_cap'] ),
            ],
            'license' => [
                'pro_active' => ! empty( $license_status['pro_active'] ),
                'license_key_present' => ! empty( $license_status['license_key_present'] ),
                'license_key_fingerprint' => $license_status['license_key_fingerprint'] ?? '',
                'status' => $license_status['license_status'] ?? '',
                'expires' => $license_status['license_expires'] ?? '',
                'last_check' => (int) ( $license_status['license_last_check'] ?? 0 ),
                'last_success' => (int) ( $license_status['license_last_success'] ?? 0 ),
                'error' => $license_status['license_error'] ?? '',
                'updates_enabled' => ! empty( $license_status['updates_enabled'] ),
                'update_failures' => (int) ( $license_status['update_failures'] ?? 0 ),
                'update_last_attempt' => (int) ( $license_status['update_last_attempt'] ?? 0 ),
                'update_last_success' => (int) ( $license_status['update_last_success'] ?? 0 ),
                'update_last_error_code' => $license_status['update_last_error_code'] ?? '',
                'update_last_error_message' => $license_status['update_last_error_message'] ?? '',
                'update_backoff_until' => (int) ( $license_status['update_backoff_until'] ?? 0 ),
                'api_url' => $license_status['api_url'] ?? '',
            ],
            'orphans' => [
                'services_orphaned_total' => (int) ( $orphan_status['services_orphaned_total'] ?? 0 ),
                'services_missing_listing' => (int) ( $orphan_status['services_missing_listing'] ?? 0 ),
                'services_missing_provider' => (int) ( $orphan_status['services_missing_provider'] ?? 0 ),
                'bookings_orphaned_total' => (int) ( $orphan_status['bookings_orphaned_total'] ?? 0 ),
                'bookings_missing_listing' => (int) ( $orphan_status['bookings_missing_listing'] ?? 0 ),
                'bookings_missing_service' => (int) ( $orphan_status['bookings_missing_service'] ?? 0 ),
                'bookings_missing_provider' => (int) ( $orphan_status['bookings_missing_provider'] ?? 0 ),
                'bookings_missing_customer' => (int) ( $orphan_status['bookings_missing_customer'] ?? 0 ),
            ],
            'diagnostics' => [
                'failed_count' => count( array_filter(
                    $support_checks,
                    static function ( array $check ): bool {
                        return ! empty( $check['needs_fix'] );
                    }
                ) ),
                'checks' => array_map(
                    function ( array $check ): array {
                        return [
                            'id' => sanitize_key( (string) ( $check['id'] ?? '' ) ),
                            'label' => (string) ( $check['label'] ?? '' ),
                            'state' => sanitize_key( (string) ( $check['state'] ?? 'info' ) ),
                            'value' => (string) ( $check['value'] ?? '' ),
                            'detail' => $this->mask_report_text( (string) ( $check['detail'] ?? '' ) ),
                            'fix' => $this->mask_report_text( (string) ( $check['fix'] ?? '' ) ),
                            'next_step' => $this->mask_report_text( (string) ( $check['next_step'] ?? '' ) ),
                            'needs_fix' => ! empty( $check['needs_fix'] ),
                            'action_url' => $this->mask_report_text( (string) ( $check['action_url'] ?? '' ) ),
                            'action_label' => (string) ( $check['action_label'] ?? '' ),
                        ];
                    },
                    $support_checks
                ),
            ],
            'launch_readiness' => [
                'mode' => sanitize_key( (string) ( $launch_readiness['mode'] ?? '' ) ),
                'mode_label' => (string) ( $launch_readiness['mode_label'] ?? '' ),
                'status' => sanitize_key( (string) ( $launch_readiness['status'] ?? '' ) ),
                'status_label' => (string) ( $launch_readiness['status_label'] ?? '' ),
                'launch_ready' => ! empty( $launch_readiness['launch_ready'] ),
                'summary' => $this->mask_report_text( (string) ( $launch_readiness['summary'] ?? '' ) ),
                'detail' => $this->mask_report_text( (string) ( $launch_readiness['detail'] ?? '' ) ),
                'blocker_count' => (int) ( $launch_readiness['blocker_count'] ?? 0 ),
                'error_count' => (int) ( $launch_readiness['error_count'] ?? 0 ),
                'warn_count' => (int) ( $launch_readiness['warn_count'] ?? 0 ),
                'blockers' => array_map(
                    function ( $check ): array {
                        $check = is_array( $check ) ? $check : [];
                        return [
                            'id' => sanitize_key( (string) ( $check['id'] ?? '' ) ),
                            'label' => (string) ( $check['label'] ?? '' ),
                            'state' => sanitize_key( (string) ( $check['state'] ?? '' ) ),
                            'value' => (string) ( $check['value'] ?? '' ),
                            'summary' => $this->mask_report_text( (string) ( $check['summary'] ?? '' ) ),
                            'detail' => $this->mask_report_text( (string) ( $check['detail'] ?? '' ) ),
                            'fix' => $this->mask_report_text( (string) ( $check['fix'] ?? '' ) ),
                            'next_step' => $this->mask_report_text( (string) ( $check['next_step'] ?? '' ) ),
                            'action_url' => $this->mask_report_text( (string) ( $check['action_url'] ?? '' ) ),
                            'action_label' => (string) ( $check['action_label'] ?? '' ),
                        ];
                    },
                    is_array( $launch_readiness['blockers'] ?? null ) ? $launch_readiness['blockers'] : []
                ),
                'top_blockers' => array_map(
                    function ( $check ): array {
                        $check = is_array( $check ) ? $check : [];
                        return [
                            'id' => sanitize_key( (string) ( $check['id'] ?? '' ) ),
                            'label' => (string) ( $check['label'] ?? '' ),
                            'state' => sanitize_key( (string) ( $check['state'] ?? '' ) ),
                            'value' => (string) ( $check['value'] ?? '' ),
                            'summary' => $this->mask_report_text( (string) ( $check['summary'] ?? '' ) ),
                            'detail' => $this->mask_report_text( (string) ( $check['detail'] ?? '' ) ),
                            'fix' => $this->mask_report_text( (string) ( $check['fix'] ?? '' ) ),
                            'next_step' => $this->mask_report_text( (string) ( $check['next_step'] ?? '' ) ),
                            'action_url' => $this->mask_report_text( (string) ( $check['action_url'] ?? '' ) ),
                            'action_label' => (string) ( $check['action_label'] ?? '' ),
                        ];
                    },
                    is_array( $launch_readiness['top_blockers'] ?? null ) ? $launch_readiness['top_blockers'] : []
                ),
            ],
            'launch_blocker_quick_summary' => $this->mask_report_text( $launch_blocker_quick_summary ),
            'launch_blocker_summary' => $this->mask_report_text( $launch_blocker_summary ),
            'support_share_summary' => $this->mask_report_text( $support_share_summary ),
        ];
    }

    private function is_mylisting_detected(): bool
    {
        return defined( 'MYLISTING_VERSION' )
            || defined( 'MYLISTING_DIR' )
            || class_exists( '\\MyListing\\Plugin' )
            || function_exists( 'mylisting' );
    }

    /**
     * @param mixed $post
     */
    private function evaluate_dashboard_embed( $post, string $dashboard ): array
    {
        if ( ! $post instanceof \WP_Post ) {
            return [
                'ok' => false,
                'label' => __( 'Page missing', 'mybookaro' ),
            ];
        }

        $dashboard = sanitize_key( $dashboard );
        $shortcode = ( 'customer' === $dashboard ) ? 'bookaro_customer_dashboard' : 'bookaro_provider_dashboard';
        $block = ( 'customer' === $dashboard ) ? 'bookaro/customer-dashboard' : 'bookaro/provider-dashboard';
        $content = (string) $post->post_content;

        $has_shortcode = function_exists( 'has_shortcode' )
            ? has_shortcode( $content, $shortcode )
            : ( false !== strpos( $content, '[' . $shortcode ) );
        $has_block = function_exists( 'has_block' )
            ? has_block( $block, $post )
            : ( false !== strpos( $content, 'wp:' . $block ) );
        $ok = $has_shortcode || $has_block;

        $label = __( 'Missing block/shortcode', 'mybookaro' );
        if ( $has_block ) {
            $label = __( 'Block found', 'mybookaro' );
        } elseif ( $has_shortcode ) {
            $label = __( 'Shortcode found', 'mybookaro' );
        }

        return [
            'ok' => $ok,
            'label' => $label,
        ];
    }

    private function probe_http_access( string $url, string $method = 'GET', array $args = [] ): array
    {
        $url = trim( $url );
        if ( '' === $url ) {
            return [
                'http_code' => 0,
                'body' => '',
                'error' => __( 'URL missing', 'mybookaro' ),
            ];
        }

        $request_args = array_merge( [
            'timeout' => 8,
            'redirection' => 2,
            'headers' => [
                'X-Bookaro-System-Status' => '1',
            ],
        ], $args );

        // Round 8 fix (Issue #21), hardened: only skip TLS verification for the
        // self-diagnostic loopback probe when the site host is a LOCAL / non-public
        // address (localhost, a dev TLD, 127.0.0.1, or a public domain mapped to a
        // private IP by a dev/staging hosts file). On such hosts a self-signed or
        // dev-only cert would otherwise block the probe with cURL error 60 and
        // falsely flag "REST API unreachable". Public hosts (with real
        // certificates) are ALWAYS verified — this mirrors WordPress core's own
        // Site Health loopback checks.
        if ( ! isset( $request_args['sslverify'] ) && $this->is_local_loopback_to_self_url( $url ) ) {
            $request_args['sslverify'] = false;
        }

        $response = ( 'POST' === strtoupper( $method ) )
            ? wp_remote_post( $url, $request_args )
            : wp_remote_get( $url, $request_args );

        if ( is_wp_error( $response ) ) {
            return [
                'http_code' => 0,
                'body' => '',
                'error' => $response->get_error_message(),
            ];
        }

        return [
            'http_code' => (int) wp_remote_retrieve_response_code( $response ),
            'body' => (string) wp_remote_retrieve_body( $response ),
            'error' => '',
        ];
    }

    /**
     * Round 8 (Issue #21), hardened: returns true only when $url targets the
     * same host as the WP site itself (loopback) AND that host is a local /
     * non-public address. Used by probe_http_access() to skip TLS verification
     * for self-diagnostic probes on localhost / self-signed-cert dev & staging
     * environments, while always verifying TLS for public production hosts.
     */
    private function is_local_loopback_to_self_url( string $url ): bool
    {
        $probe_host = wp_parse_url( $url, PHP_URL_HOST );
        $site_host  = wp_parse_url( home_url(), PHP_URL_HOST );
        if ( ! $probe_host || ! $site_host ) {
            return false;
        }
        if ( strtolower( (string) $probe_host ) !== strtolower( (string) $site_host ) ) {
            return false;
        }

        return $this->host_is_local_address( (string) $probe_host );
    }

    /**
     * True when $host is localhost, a development TLD, or resolves to a
     * private / reserved (non-public) IP address. Public hosts return false so
     * their TLS certificates are always verified.
     */
    private function host_is_local_address( string $host ): bool
    {
        $host = strtolower( $host );
        if (
            'localhost' === $host
            || str_ends_with( $host, '.localhost' )
            || str_ends_with( $host, '.local' )
            || str_ends_with( $host, '.test' )
        ) {
            return true;
        }

        $ip = $host;
        if ( ! filter_var( $host, FILTER_VALIDATE_IP ) ) {
            $resolved = gethostbyname( $host );
            if ( $resolved === $host ) {
                // Could not resolve — default to verifying TLS (treat as public).
                return false;
            }
            $ip = $resolved;
        }

        // filter_var() returns false for private/reserved IPs when those ranges
        // are excluded; false here therefore means a local / non-public address.
        return false === filter_var(
            $ip,
            FILTER_VALIDATE_IP,
            FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
        );
    }

    private function get_orphan_status(): array
    {
        $services_missing_listing = 0;
        $services_missing_provider = 0;
        $service_orphan_ids = [];

        $service_type = defined( 'BOOKARO_SERVICE_POST_TYPE' ) ? BOOKARO_SERVICE_POST_TYPE : 'bookaro_service';
        $owner_meta = defined( 'BOOKARO_SERVICE_OWNER_META' ) ? BOOKARO_SERVICE_OWNER_META : 'bookaro_service_owner_type';
        $scope_meta = defined( 'BOOKARO_SERVICE_SCOPE_META' ) ? BOOKARO_SERVICE_SCOPE_META : 'bookaro_service_scope';
        $listing_meta = defined( 'BOOKARO_SERVICE_LISTING_META' ) ? BOOKARO_SERVICE_LISTING_META : 'bookaro_service_listing_id';
        $provider_meta = defined( 'BOOKARO_SERVICE_PROVIDER_META' ) ? BOOKARO_SERVICE_PROVIDER_META : 'bookaro_service_provider_id';
        // Single Business has no listings by design, so a provider-owned service
        // legitimately has no listing and must not be flagged as a "missing
        // listing" orphan in that lane. (The provider-existence check below
        // still applies, so a truly dangling provider is still caught.)
        $single_business_lane = function_exists( 'bookaro_is_single_business_site' ) && bookaro_is_single_business_site();

        // get_posts() already defaults suppress_filters to true; removing the
        // explicit setting silences the VIP-Minimum lint without changing
        // runtime behavior.
        $service_ids = get_posts( [
            'post_type' => $service_type,
            'post_status' => [ 'publish', 'private', 'draft', 'pending', 'future' ],
            'posts_per_page' => -1,
            'fields' => 'ids',
            'no_found_rows' => true,
            'update_post_term_cache' => false,
        ] );
        if ( ! is_array( $service_ids ) ) {
            $service_ids = [];
        }

        $listing_exists_cache = [];
        $user_exists_cache = [];

        foreach ( $service_ids as $service_id ) {
            $service_id = absint( $service_id );
            if ( $service_id < 1 ) {
                continue;
            }

            $owner_type = sanitize_key( (string) get_post_meta( $service_id, $owner_meta, true ) );
            $scope = sanitize_key( (string) get_post_meta( $service_id, $scope_meta, true ) );

            $listing_values = get_post_meta( $service_id, $listing_meta, false );
            if ( ! is_array( $listing_values ) ) {
                $listing_values = [];
            }
            $listing_ids = array_values( array_unique( array_filter( array_map( 'absint', $listing_values ) ) ) );
            $has_valid_listing = false;
            foreach ( $listing_ids as $listing_id ) {
                if ( ! array_key_exists( $listing_id, $listing_exists_cache ) ) {
                    $listing_post = get_post( $listing_id );
                    $listing_exists_cache[ $listing_id ] = $listing_post instanceof \WP_Post
                        && ! in_array( (string) $listing_post->post_status, [ 'trash', 'auto-draft' ], true );
                }
                if ( ! empty( $listing_exists_cache[ $listing_id ] ) ) {
                    $has_valid_listing = true;
                    break;
                }
            }

            $requires_listing = ! $single_business_lane
                && ( ( 'provider' === $owner_type ) || in_array( $scope, [ 'listing', 'provider' ], true ) );
            if ( $requires_listing && ! $has_valid_listing ) {
                $services_missing_listing++;
                $service_orphan_ids[ $service_id ] = true;
            }

            if ( 'provider' === $owner_type ) {
                $provider_id = absint( get_post_meta( $service_id, $provider_meta, true ) );
                $provider_ok = false;
                if ( $provider_id > 0 ) {
                    if ( ! array_key_exists( $provider_id, $user_exists_cache ) ) {
                        $user_exists_cache[ $provider_id ] = (bool) get_user_by( 'ID', $provider_id );
                    }
                    $provider_ok = ! empty( $user_exists_cache[ $provider_id ] );
                }
                if ( ! $provider_ok ) {
                    $services_missing_provider++;
                    $service_orphan_ids[ $service_id ] = true;
                }
            }
        }

        $bookings_missing_listing = 0;
        $bookings_missing_service = 0;
        $bookings_missing_provider = 0;
        $bookings_missing_customer = 0;
        $booking_orphan_ids = [];

        $wpdb = $this->db->get_wpdb();
        $bookings_table = $this->db->get_table_name();
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $bookings_table_exists = (bool) $wpdb->get_var(
            $wpdb->prepare( 'SHOW TABLES LIKE %s', $bookings_table )
        );
        if ( $bookings_table_exists ) {
            $posts_table = $wpdb->posts;
            $users_table = $wpdb->users;

            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $missing_listing_ids = (array) $wpdb->get_col(
                "SELECT b.id FROM {$bookings_table} b
                LEFT JOIN {$posts_table} p ON p.ID = b.listing_id AND p.post_status NOT IN ('trash','auto-draft')
                WHERE b.listing_id > 0 AND p.ID IS NULL"
            );
            $bookings_missing_listing = count( $missing_listing_ids );
            foreach ( $missing_listing_ids as $id ) {
                $booking_orphan_ids[ (int) $id ] = true;
            }

            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $missing_service_ids = (array) $wpdb->get_col(
                $wpdb->prepare(
                    "SELECT b.id FROM {$bookings_table} b
                    LEFT JOIN {$posts_table} s ON s.ID = b.service_id AND s.post_type = %s AND s.post_status NOT IN ('trash','auto-draft')
                    WHERE b.service_id IS NOT NULL AND b.service_id > 0 AND s.ID IS NULL",
                    $service_type
                )
            );
            $bookings_missing_service = count( $missing_service_ids );
            foreach ( $missing_service_ids as $id ) {
                $booking_orphan_ids[ (int) $id ] = true;
            }

            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $missing_provider_ids = (array) $wpdb->get_col(
                "SELECT b.id FROM {$bookings_table} b
                LEFT JOIN {$users_table} u ON u.ID = b.provider_id
                WHERE b.provider_id > 0 AND u.ID IS NULL"
            );
            $bookings_missing_provider = count( $missing_provider_ids );
            foreach ( $missing_provider_ids as $id ) {
                $booking_orphan_ids[ (int) $id ] = true;
            }

            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $missing_customer_ids = (array) $wpdb->get_col(
                "SELECT b.id FROM {$bookings_table} b
                LEFT JOIN {$users_table} u ON u.ID = b.customer_id
                WHERE b.customer_id > 0 AND u.ID IS NULL"
            );
            $bookings_missing_customer = count( $missing_customer_ids );
            foreach ( $missing_customer_ids as $id ) {
                $booking_orphan_ids[ (int) $id ] = true;
            }
        }

        return [
            'services_orphaned_total' => count( $service_orphan_ids ),
            'services_missing_listing' => $services_missing_listing,
            'services_missing_provider' => $services_missing_provider,
            'bookings_orphaned_total' => count( $booking_orphan_ids ),
            'bookings_missing_listing' => $bookings_missing_listing,
            'bookings_missing_service' => $bookings_missing_service,
            'bookings_missing_provider' => $bookings_missing_provider,
            'bookings_missing_customer' => $bookings_missing_customer,
        ];
    }

    private function build_support_checks(
        array $api_status,
        array $integration_status,
        array $dashboard_status,
        array $generic_status,
        array $orphan_status,
        array $settings_status,
        array $generic_validation_prompt = []
    ): array {
        $settings_url = admin_url( 'admin.php?page=bookaro-booking-settings&tab=general' );
        $permalinks_url = admin_url( 'options-permalink.php' );
        $site_health_url = admin_url( 'site-health.php' );
        $themes_url = admin_url( 'themes.php' );
        $wizard_modes_url = admin_url( 'admin.php?page=bookaro-setup-wizard&step=modes' );
        $wizard_listings_url = admin_url( 'admin.php?page=bookaro-setup-wizard&step=listings' );
        $wizard_services_url = admin_url( 'admin.php?page=bookaro-setup-wizard&step=services' );
        $wizard_pages_url = admin_url( 'admin.php?page=bookaro-setup-wizard&step=pages' );
        $bookings_url = admin_url( 'admin.php?page=bookaro-bookings' );
        $service_type = defined( 'BOOKARO_SERVICE_POST_TYPE' ) ? BOOKARO_SERVICE_POST_TYPE : 'bookaro_service';
        $services_url = admin_url( 'edit.php?post_type=' . $service_type );
        $create_service_url = admin_url( 'post-new.php?post_type=' . $service_type );
        $runtime_validation = function_exists( 'bookaro_run_generic_admin_validation' )
            ? bookaro_run_generic_admin_validation()
            : [];
        $runtime_validation_checks = [];
        if ( is_array( $runtime_validation ) && ! empty( $runtime_validation['checks'] ) && is_array( $runtime_validation['checks'] ) ) {
            $runtime_validation_checks = $runtime_validation['checks'];
        }
        $runtime_failed_count = is_array( $runtime_validation )
            ? absint( $runtime_validation['failed_count'] ?? 0 )
            : 0;

        $resolved_mode = sanitize_key( (string) ( $generic_status['integration_resolved'] ?? 'auto' ) );
        $generic_mode_active = ( 'generic' === $resolved_mode );
        $site_type = $this->normalize_site_type( (string) ( $generic_status['site_type'] ?? 'directory' ) );
        $lane_id = sanitize_key( (string) ( $generic_status['lane_id'] ?? $this->resolve_product_lane_id( $site_type, $resolved_mode ) ) );
        $lane_label = (string) ( $generic_status['lane_label'] ?? $this->get_product_lane_label( $lane_id ) );
        $single_business_lane = ( 'single_business' === $lane_id );
        $lane_blueprint = ( isset( $generic_status['lane_blueprint'] ) && is_array( $generic_status['lane_blueprint'] ) )
            ? $generic_status['lane_blueprint']
            : $this->get_product_lane_blueprint( $lane_id, 'advanced_mapping' === $site_type );
        $generic_confirmation_required = ! empty( $generic_status['generic_confirmation_required'] );
        $generic_setup_confirmed = ! empty( $generic_status['generic_setup_confirmed'] );
        $generic_legacy_fallback_active = ! empty( $generic_status['generic_legacy_fallback_active'] );
        $generic_setup_completed = ! empty( $generic_status['generic_setup_completed'] );
        $validation_refresh_required = ! empty( $generic_validation_prompt['needs_validation'] );
        $generic_validation_anchor_url = admin_url( 'admin.php?page=bookaro-system-status#bookaro-support-check-generic_validation_provider_resolution_sample' );
        if ( $generic_confirmation_required ) {
            $runtime_validation_checks = [];
            $runtime_failed_count = 0;
            $validation_refresh_required = false;
        }
        $mylisting_required = ( 'mylisting' === $resolved_mode );
        $mylisting_active = ! empty( $integration_status['mylisting_detected'] );
        $mylisting_sample_listing_id = absint( $integration_status['mylisting_sample_listing_id'] ?? 0 );
        $mylisting_services_diagnostics = is_array( $integration_status['mylisting_services_diagnostics'] ?? null )
            ? $integration_status['mylisting_services_diagnostics']
            : [];
        $mylisting_repeater_class_for_checks = sanitize_key( (string) ( $integration_status['mylisting_repeater_class'] ?? 'mybookaro_services' ) );
        if ( '' === $mylisting_repeater_class_for_checks ) {
            $mylisting_repeater_class_for_checks = 'mybookaro_services';
        }
        $mylisting_services_check = $this->build_mylisting_services_check_state(
            $mylisting_services_diagnostics,
            $mylisting_sample_listing_id,
            $mylisting_repeater_class_for_checks
        );
        $generic_confirmation_state = 'ok';
        $generic_confirmation_value = __( 'Explicitly confirmed', 'mybookaro' );
        $generic_confirmation_detail = $generic_setup_completed
            ? __( 'Generic path is explicitly confirmed and setup is marked complete. Continue validating before launch.', 'mybookaro' )
            : __( 'Generic path is explicitly confirmed. Continue through setup and validation before launch.', 'mybookaro' );
        $generic_confirmation_fix = '';
        $generic_confirmation_next_step = '';
        if ( 'mylisting' === $resolved_mode ) {
            $generic_confirmation_state = 'info';
            $generic_confirmation_value = __( 'Not required', 'mybookaro' );
            $generic_confirmation_detail = __( 'Generic confirmation is only required when MyListing is not detected and integration relies on the Generic Directory lane.', 'mybookaro' );
        } elseif ( $generic_confirmation_required ) {
            $generic_confirmation_state = 'error';
            $generic_confirmation_value = __( 'Required', 'mybookaro' );
            $generic_confirmation_detail = __( 'MyListing is not detected. Generic Directory is available, but explicit lane confirmation is still missing for this site.', 'mybookaro' );
            $generic_confirmation_fix = __( 'Open Setup Wizard > Lane, explicitly select Generic Directory, save, then complete validation before launch.', 'mybookaro' );
            $generic_confirmation_next_step = __( 'Next step: Open Setup Wizard > Lane, confirm Generic Directory, save, then re-run System Status validation.', 'mybookaro' );
        } elseif ( ! $generic_setup_confirmed ) {
            $generic_confirmation_state = 'error';
            $generic_confirmation_value = __( 'Required', 'mybookaro' );
            $generic_confirmation_detail = __( 'Generic Directory is available, but explicit lane confirmation is still missing for this site.', 'mybookaro' );
            $generic_confirmation_fix = __( 'Open Setup Wizard > Lane, explicitly select Generic Directory, save, then complete validation before launch.', 'mybookaro' );
            $generic_confirmation_next_step = __( 'Next step: Open Setup Wizard > Lane, confirm Generic Directory, save, then re-run System Status validation.', 'mybookaro' );
        } elseif ( $generic_legacy_fallback_active ) {
            $generic_confirmation_state = 'warn';
            $generic_confirmation_value = __( 'Review', 'mybookaro' );
            $generic_confirmation_detail = __( 'Generic compatibility is active from legacy automatic settings, but explicit lane confirmation metadata is missing.', 'mybookaro' );
            $generic_confirmation_fix = __( 'Open Setup Wizard > Lane and save once to record explicit Generic confirmation metadata.', 'mybookaro' );
            $generic_confirmation_next_step = __( 'Next step: Open Setup Wizard > Lane, save, then verify System Status reports Generic confirmation as explicit.', 'mybookaro' );
        }

        $mylisting_state = 'ok';
        $mylisting_value = __( 'Active', 'mybookaro' );
        $mylisting_detail = __( 'MyListing was detected on this site.', 'mybookaro' );
        $mylisting_fix = '';
        $mylisting_next_step = '';
        if ( ! $mylisting_active && $mylisting_required ) {
            $mylisting_state = 'error';
            $mylisting_value = __( 'Missing', 'mybookaro' );
            $mylisting_detail = __( 'Integration resolves to MyListing, but the theme was not detected.', 'mybookaro' );
            $mylisting_fix = __( 'Activate the MyListing theme, then reload this page.', 'mybookaro' );
            $mylisting_next_step = __( 'Next step: Open Themes, activate MyListing, then reload System Status.', 'mybookaro' );
        } elseif ( ! $mylisting_active ) {
            if ( $generic_mode_active ) {
                $mylisting_state = 'info';
                $mylisting_value = __( 'Not required', 'mybookaro' );
                $mylisting_detail = __( 'MyListing is not active, and this site is currently using the Generic integration path.', 'mybookaro' );
            } else {
                $mylisting_state = 'warn';
                $mylisting_value = __( 'Not detected', 'mybookaro' );
                $mylisting_detail = __( 'MyListing is not active. Compatibility checks may not apply.', 'mybookaro' );
                $mylisting_fix = __( 'If this site should run with MyListing, activate the theme and keep Directory lane choice on Auto-select or MyListing Directory.', 'mybookaro' );
                $mylisting_next_step = __( 'Next step: Open Setup Wizard > Lane and confirm whether this site should use Generic Directory or MyListing Directory.', 'mybookaro' );
            }
        }

        $repeater_configured = ! empty( $integration_status['mylisting_repeater_class_configured'] );
        $repeater_requires = $mylisting_active || $mylisting_required;
        $repeater_class = (string) ( $integration_status['mylisting_repeater_class'] ?? 'mybookaro_services' );
        $repeater_state = 'ok';
        $repeater_value = __( 'Configured', 'mybookaro' );
        $repeater_detail = sprintf(
            /* translators: %s: CSS class */
            __( 'Current repeater class: %s', 'mybookaro' ),
            $repeater_class
        );
        $repeater_fix = '';
        $repeater_next_step = '';
        if ( ! $repeater_configured && $repeater_requires ) {
            $repeater_state = 'error';
            $repeater_value = __( 'Missing', 'mybookaro' );
            $repeater_fix = __( 'Set Services Repeater Class in Settings > General to match your MyListing repeater row CSS class.', 'mybookaro' );
            $repeater_next_step = __( 'Next step: Open settings, set the repeater class used in your listing type, save, then refresh this page.', 'mybookaro' );
        } elseif ( ! $repeater_configured ) {
            $repeater_state = 'info';
            $repeater_value = __( 'Not required', 'mybookaro' );
            $repeater_detail = __( 'MyListing is not active, so this class is not currently used.', 'mybookaro' );
        } elseif ( $mylisting_active ) {
            $repeater_state = sanitize_key( (string) ( $mylisting_services_check['state'] ?? 'ok' ) );
            if ( ! in_array( $repeater_state, [ 'ok', 'warn', 'error', 'info' ], true ) ) {
                $repeater_state = 'ok';
            }
            $repeater_value = (string) ( $mylisting_services_check['value'] ?? __( 'Configured', 'mybookaro' ) );
            $repeater_detail = sprintf(
                /* translators: 1: repeater class, 2: diagnostics detail */
                __( 'Current repeater class: %1$s. %2$s', 'mybookaro' ),
                $repeater_class,
                (string) ( $mylisting_services_check['detail'] ?? '' )
            );
            $repeater_fix = (string) ( $mylisting_services_check['fix'] ?? '' );
            $repeater_next_step = (string) ( $mylisting_services_check['next_step'] ?? '' );
        }

        $allowed_types = $generic_status['allowed_listing_types'] ?? [];
        if ( ! is_array( $allowed_types ) ) {
            $allowed_types = [];
        }
        $allowed_types = array_values( array_unique( array_filter( array_map( 'sanitize_key', $allowed_types ) ) ) );
        $existing_types = array_values( array_filter(
            $allowed_types,
            static function ( string $type ): bool {
                return post_type_exists( $type );
            }
        ) );
        $missing_types = array_values( array_diff( $allowed_types, $existing_types ) );

        $types_state = 'ok';
        $types_value = __( 'Valid', 'mybookaro' );
        $types_detail = ! empty( $allowed_types )
            /* translators: %s: dynamic string */
            ? sprintf( __( 'Selected: %s', 'mybookaro' ), implode( ', ', $allowed_types ) )
            : __( 'No listing post types selected.', 'mybookaro' );
        $types_fix = '';
        $types_next_step = '';
        if ( ! $generic_mode_active ) {
            $types_state = 'info';
            $types_value = __( 'Not required', 'mybookaro' );
            $types_detail = __( 'Listing post type checks apply only in the Generic Directory lane.', 'mybookaro' );
        } elseif ( empty( $existing_types ) ) {
            $types_state = 'error';
            $types_value = __( 'Invalid', 'mybookaro' );
            $types_fix = __( 'Choose at least one existing listing post type in Settings > General.', 'mybookaro' );
            $types_next_step = __( 'Next step: Open Setup Wizard > Listings, select at least one active listing post type, save, then re-run System Status.', 'mybookaro' );
        } elseif ( ! empty( $missing_types ) ) {
            $types_state = 'warn';
            $types_value = __( 'Invalid', 'mybookaro' );
            /* translators: %s: dynamic string */
            $types_detail .= ' ' . sprintf( __( 'Unknown post types: %s', 'mybookaro' ), implode( ', ', $missing_types ) );
            $types_fix = __( 'Remove invalid post types and keep only active listing post types.', 'mybookaro' );
            $types_next_step = __( 'Next step: Open Setup Wizard > Listings, remove unknown post types, save, and check status again.', 'mybookaro' );
        }

        $shortcodes_mode = ( 'shortcodes' === (string) ( $dashboard_status['ui_mode'] ?? $this->get_default_ui_mode_for_integration_mode() ) );
        $provider_page_ready = ! empty( $dashboard_status['provider_page_exists'] ) && ! empty( $dashboard_status['provider_page_embed_ok'] );
        $provider_page_state = 'ok';
        $provider_page_value = __( 'Ready', 'mybookaro' );
        $provider_page_detail = (string) ( $dashboard_status['provider_page_embed_label'] ?? '' );
        $provider_page_fix = '';
        $provider_page_next_step = '';
        $provider_page_edit_url = ! empty( $dashboard_status['provider_page_edit'] ) ? (string) $dashboard_status['provider_page_edit'] : '';
        $provider_page_action_url = $provider_page_edit_url !== '' ? $provider_page_edit_url : $wizard_pages_url;
        $provider_page_action_label = $provider_page_edit_url !== '' ? __( 'Edit provider page', 'mybookaro' ) : __( 'Open pages step', 'mybookaro' );
        if ( ! $shortcodes_mode ) {
            $provider_page_state = 'info';
            $provider_page_value = __( 'Not required', 'mybookaro' );
            $provider_page_detail = __( 'UI mode uses WooCommerce My Account, so a provider dashboard page is optional.', 'mybookaro' );
            $provider_page_action_url = $settings_url;
            $provider_page_action_label = __( 'Open settings', 'mybookaro' );
        } elseif ( ! $provider_page_ready ) {
            $provider_page_state = 'error';
            $provider_page_value = __( 'Action needed', 'mybookaro' );
            $provider_page_detail = ! empty( $dashboard_status['provider_page_exists'] )
                ? __( 'Provider dashboard page is assigned, but the MyBookaro Provider Dashboard block/shortcode is missing.', 'mybookaro' )
                : __( 'Provider dashboard page is not assigned.', 'mybookaro' );
            $provider_page_fix = ! empty( $dashboard_status['provider_page_exists'] )
                ? __( 'Edit the assigned provider dashboard page and add the MyBookaro Provider Dashboard block (or [bookaro_provider_dashboard]).', 'mybookaro' )
                : __( 'Open Setup Wizard > Pages and assign a Provider Dashboard page.', 'mybookaro' );
            if ( ! empty( $dashboard_status['provider_page_exists'] ) && $provider_page_edit_url !== '' ) {
                $provider_page_next_step = __( 'Next step: Open the provider page editor, add the MyBookaro Provider Dashboard block (or shortcode), update, then re-run System Status.', 'mybookaro' );
            } else {
                $provider_page_action_url = $wizard_pages_url;
                $provider_page_action_label = __( 'Open pages step', 'mybookaro' );
                $provider_page_next_step = __( 'Next step: Open Setup Wizard > Pages, assign Provider Dashboard page, save, then re-run System Status.', 'mybookaro' );
            }
        }

        $customer_page_ready = ! empty( $dashboard_status['customer_page_exists'] ) && ! empty( $dashboard_status['customer_page_embed_ok'] );
        $customer_page_state = 'ok';
        $customer_page_value = __( 'Ready', 'mybookaro' );
        $customer_page_detail = (string) ( $dashboard_status['customer_page_embed_label'] ?? '' );
        $customer_page_fix = '';
        $customer_page_next_step = '';
        $customer_page_edit_url = ! empty( $dashboard_status['customer_page_edit'] ) ? (string) $dashboard_status['customer_page_edit'] : '';
        $customer_page_action_url = $customer_page_edit_url !== '' ? $customer_page_edit_url : $wizard_pages_url;
        $customer_page_action_label = $customer_page_edit_url !== '' ? __( 'Edit customer page', 'mybookaro' ) : __( 'Open pages step', 'mybookaro' );
        if ( ! $shortcodes_mode ) {
            $customer_page_state = 'info';
            $customer_page_value = __( 'Not required', 'mybookaro' );
            $customer_page_detail = __( 'UI mode uses WooCommerce My Account, so a customer dashboard page is optional.', 'mybookaro' );
            $customer_page_action_url = $settings_url;
            $customer_page_action_label = __( 'Open settings', 'mybookaro' );
        } elseif ( ! $customer_page_ready ) {
            $customer_page_state = 'error';
            $customer_page_value = __( 'Action needed', 'mybookaro' );
            $customer_page_detail = ! empty( $dashboard_status['customer_page_exists'] )
                ? __( 'Customer dashboard page is assigned, but the MyBookaro Customer Dashboard block/shortcode is missing.', 'mybookaro' )
                : __( 'Customer dashboard page is not assigned.', 'mybookaro' );
            $customer_page_fix = ! empty( $dashboard_status['customer_page_exists'] )
                ? __( 'Edit the assigned customer dashboard page and add the MyBookaro Customer Dashboard block (or [bookaro_customer_dashboard]).', 'mybookaro' )
                : __( 'Open Setup Wizard > Pages and assign a Customer Dashboard page.', 'mybookaro' );
            if ( ! empty( $dashboard_status['customer_page_exists'] ) && $customer_page_edit_url !== '' ) {
                $customer_page_next_step = __( 'Next step: Open the customer page editor, add the MyBookaro Customer Dashboard block (or shortcode), update, then re-run System Status.', 'mybookaro' );
            } else {
                $customer_page_action_url = $wizard_pages_url;
                $customer_page_action_label = __( 'Open pages step', 'mybookaro' );
                $customer_page_next_step = __( 'Next step: Open Setup Wizard > Pages, assign Customer Dashboard page, save, then re-run System Status.', 'mybookaro' );
            }
        }

        $global_pages = $generic_status['global_pages'] ?? [];
        if ( ! is_array( $global_pages ) ) {
            $global_pages = [];
        }
        $context_pages = function ( string $context ) use ( $existing_types, $global_pages ): array {
            $context = sanitize_key( $context );
            $ids = [];
            if ( function_exists( 'bookaro_get_page_for_context' ) && ! empty( $existing_types ) ) {
                foreach ( $existing_types as $post_type ) {
                    $post_type = sanitize_key( (string) $post_type );
                    if ( '' === $post_type ) {
                        continue;
                    }
                    $context_page_id = absint( bookaro_get_page_for_context( 'generic', $post_type, $context ) );
                    if ( $context_page_id > 0 ) {
                        $ids[ $context_page_id ] = $context_page_id;
                    }
                }
            }

            if ( empty( $ids ) ) {
                $global_id = absint( $global_pages[ $context ] ?? 0 );
                if ( $global_id > 0 ) {
                    $ids[ $global_id ] = $global_id;
                }
            }

            $posts = [];
            foreach ( $ids as $id ) {
                $post = get_post( $id );
                if ( ! $post instanceof \WP_Post ) {
                    continue;
                }
                if ( in_array( (string) $post->post_status, [ 'trash', 'auto-draft' ], true ) ) {
                    continue;
                }
                $posts[ $id ] = $post;
            }

            return [
                'ids' => array_values( $ids ),
                'posts' => $posts,
            ];
        };

        $format_page_labels = static function ( array $posts ): string {
            if ( empty( $posts ) ) {
                return '';
            }
            $labels = [];
            foreach ( $posts as $id => $post ) {
                if ( ! $post instanceof \WP_Post ) {
                    continue;
                }
                $title = trim( (string) $post->post_title );
                if ( '' === $title ) {
                    /* translators: %d: numeric value */
                    $title = sprintf( __( 'Page #%d', 'mybookaro' ), (int) $id );
                } else {
                    $title .= ' (#' . (int) $id . ')';
                }
                $labels[] = $title;
            }
            return implode( ', ', $labels );
        };

        $booking_context_pages = $context_pages( 'booking' );
        $provider_context_pages = $context_pages( 'provider_dashboard' );
        $customer_context_pages = $context_pages( 'customer_dashboard' );

        $booking_page_exists = ! empty( $booking_context_pages['posts'] );
        $provider_context_exists = ! empty( $provider_context_pages['posts'] );
        $customer_context_exists = ! empty( $customer_context_pages['posts'] );

        $provider_context_embed_ok = false;
        if ( $provider_context_exists ) {
            foreach ( $provider_context_pages['posts'] as $provider_post ) {
                $embed = $this->evaluate_dashboard_embed( $provider_post, 'provider' );
                if ( ! empty( $embed['ok'] ) ) {
                    $provider_context_embed_ok = true;
                    break;
                }
            }
        }

        $customer_context_embed_ok = false;
        if ( $customer_context_exists ) {
            foreach ( $customer_context_pages['posts'] as $customer_post ) {
                $embed = $this->evaluate_dashboard_embed( $customer_post, 'customer' );
                if ( ! empty( $embed['ok'] ) ) {
                    $customer_context_embed_ok = true;
                    break;
                }
            }
        }

        $missing_pages_state = 'ok';
        $missing_pages_value = __( 'Valid', 'mybookaro' );
        $missing_pages_detail_parts = [];
        $missing_pages_fix = '';
        $missing_pages_next_step = '';
        if ( ! $generic_mode_active ) {
            $missing_pages_state = 'info';
            $missing_pages_value = __( 'Not required', 'mybookaro' );
            $missing_pages_detail_parts[] = __( 'Page assignment checks apply only in the Generic Directory lane.', 'mybookaro' );
        } else {
            $missing_items = [];
            $booking_missing = ! $booking_page_exists;
            $provider_page_missing = $shortcodes_mode && ! $provider_context_exists;
            $customer_page_missing = $shortcodes_mode && ! $customer_context_exists;
            $provider_embed_missing = $shortcodes_mode && $provider_context_exists && ! $provider_context_embed_ok;
            $customer_embed_missing = $shortcodes_mode && $customer_context_exists && ! $customer_context_embed_ok;

            if ( $booking_missing ) {
                $missing_items[] = __( 'Booking page', 'mybookaro' );
            }
            if ( $provider_page_missing ) {
                $missing_items[] = __( 'Provider dashboard page', 'mybookaro' );
            } elseif ( $provider_embed_missing ) {
                $missing_items[] = __( 'Provider dashboard block/shortcode', 'mybookaro' );
            }
            if ( $customer_page_missing ) {
                $missing_items[] = __( 'Customer dashboard page', 'mybookaro' );
            } elseif ( $customer_embed_missing ) {
                $missing_items[] = __( 'Customer dashboard block/shortcode', 'mybookaro' );
            }

            if ( empty( $missing_items ) ) {
                $missing_pages_detail_parts[] = sprintf(
                    /* translators: %s: configured booking page labels */
                    __( 'Booking page: %s', 'mybookaro' ),
                    $format_page_labels( $booking_context_pages['posts'] )
                );
                if ( $shortcodes_mode ) {
                    $missing_pages_detail_parts[] = sprintf(
                        /* translators: %s: configured provider page labels */
                        __( 'Provider dashboards: %s', 'mybookaro' ),
                        $format_page_labels( $provider_context_pages['posts'] )
                    );
                    $missing_pages_detail_parts[] = sprintf(
                        /* translators: %s: configured customer page labels */
                        __( 'Customer dashboards: %s', 'mybookaro' ),
                        $format_page_labels( $customer_context_pages['posts'] )
                    );
                } else {
                    $missing_pages_detail_parts[] = __( 'Dashboard pages are optional in WooCommerce My Account mode.', 'mybookaro' );
                }
            } else {
                $critical_missing = $provider_page_missing || $customer_page_missing || $provider_embed_missing || $customer_embed_missing;
                $missing_pages_state = $critical_missing ? 'error' : 'warn';
                $missing_pages_value = __( 'Invalid', 'mybookaro' );
                $missing_pages_detail_parts[] = sprintf(
                    /* translators: %s: list of missing page requirements */
                    __( 'Missing: %s.', 'mybookaro' ),
                    implode( ', ', $missing_items )
                );
                if ( $shortcodes_mode ) {
                    $missing_pages_fix = $single_business_lane
                        ? __( 'Single Business listings are optional, but Shortcodes mode requires Booking + Provider Dashboard + Customer Dashboard pages with dashboard embeds.', 'mybookaro' )
                        : __( 'Open Setup Wizard > Pages, assign Booking + Provider Dashboard + Customer Dashboard pages, then edit the dashboard pages and add the matching MyBookaro dashboard blocks or shortcodes.', 'mybookaro' );
                    $missing_pages_next_step = $single_business_lane
                        ? __( 'Next step: Open Setup Wizard > Pages, assign booking/provider/customer pages, add dashboard embeds, save, then re-run System Status.', 'mybookaro' )
                        : __( 'Next step: Open Setup Wizard > Pages, assign booking/provider/customer pages, save, then edit the two dashboard pages to add dashboard embeds and re-run System Status.', 'mybookaro' );
                } else {
                    $missing_pages_fix = $single_business_lane
                        ? __( 'Single Business listings are optional, but you still need a Booking page or a valid placement strategy in Setup Wizard > Services.', 'mybookaro' )
                        : __( 'Assign a Booking page in Setup Wizard > Pages, then place Booking Button/Services Cards explicitly or configure Auto-Insert fallback in Setup Wizard > Services.', 'mybookaro' );
                    $missing_pages_next_step = $single_business_lane
                        ? __( 'Next step: Open Setup Wizard > Pages, assign Booking page, save, then verify placement in Setup Wizard > Services.', 'mybookaro' )
                        : __( 'Next step: Open Setup Wizard > Pages, assign Booking page, save, then open Setup Wizard > Services and choose one booking entry method.', 'mybookaro' );
                }
            }
        }
        $missing_pages_detail = implode( ' | ', array_filter( $missing_pages_detail_parts ) );

        $all_settings = $this->options->get_all();
        if ( ! is_array( $all_settings ) ) {
            $all_settings = [];
        }
        $auto_insert_mode = function_exists( 'bookaro_get_auto_insert_booking_button_mode' )
            ? (string) bookaro_get_auto_insert_booking_button_mode()
            : '';
        $auto_insert_mode = sanitize_key( $auto_insert_mode );
        $auto_insert_enabled = array_key_exists( 'auto_insert_booking_button_enabled', $all_settings )
            ? ! empty( $all_settings['auto_insert_booking_button_enabled'] )
            : ( '' !== $auto_insert_mode );
        $auto_insert_selector = function_exists( 'bookaro_get_auto_insert_booking_button_selector' )
            ? sanitize_text_field( (string) bookaro_get_auto_insert_booking_button_selector() )
            : '';
        $button_insert_state = 'ok';
        $button_insert_value = __( 'Valid', 'mybookaro' );
        $button_insert_detail = '';
        $button_insert_fix = '';
        $button_insert_next_step = '';
        $button_insert_action_url = $wizard_services_url;
        $button_insert_action_label = __( 'Open services step', 'mybookaro' );
        $auto_insert_valid = in_array( $auto_insert_mode, [ 'before_content', 'after_content', 'selector' ], true );
        $selector_required = ( 'selector' === $auto_insert_mode );
        $selector_ready = ! $selector_required || '' !== $auto_insert_selector;
        $button_insert_ready = ( $auto_insert_enabled && $auto_insert_valid && $selector_ready ) || $booking_page_exists;

        if ( ! $generic_mode_active ) {
            $button_insert_state = 'info';
            $button_insert_value = __( 'Not required', 'mybookaro' );
            $button_insert_detail = __( 'Booking button insertion checks apply only in the Generic Directory lane.', 'mybookaro' );
        } elseif ( $button_insert_ready ) {
            if ( $auto_insert_enabled && $auto_insert_valid ) {
                $button_insert_detail = ( 'selector' === $auto_insert_mode )
                    ? sprintf(
                        /* translators: %s: css selector */
                        __( 'Auto-insert is enabled via selector: %s', 'mybookaro' ),
                        $auto_insert_selector
                    )
                    : sprintf(
                        /* translators: %s: placement mode */
                        __( 'Auto-insert is enabled (%s).', 'mybookaro' ),
                        $auto_insert_mode
                    );
            } else {
                $button_insert_detail = __( 'Booking page is assigned for explicit Booking Button/Services Cards placement.', 'mybookaro' );
            }
        } else {
            $button_insert_state = 'error';
            $button_insert_value = __( 'Invalid', 'mybookaro' );
            if ( $auto_insert_enabled && 'selector' === $auto_insert_mode && '' === $auto_insert_selector ) {
                $button_insert_detail = __( 'Auto-Insert uses CSS selector placement, but the selector field is empty.', 'mybookaro' );
                $button_insert_fix = __( 'Open Setup Wizard > Services, keep Auto-Insert on CSS selector, and enter a valid selector.', 'mybookaro' );
                $button_insert_next_step = __( 'Next step: Open Setup Wizard > Services, fill the selector, save, then verify booking entry on a listing/page.', 'mybookaro' );
            } elseif ( $auto_insert_enabled && ! $auto_insert_valid ) {
                $button_insert_detail = __( 'Auto-Insert is enabled, but placement mode is missing or invalid.', 'mybookaro' );
                $button_insert_fix = __( 'Open Setup Wizard > Services and select a valid Auto-Insert placement (Before content, After content, or CSS selector).', 'mybookaro' );
                $button_insert_next_step = __( 'Next step: Open Setup Wizard > Services, select placement, save, then verify booking entry on a listing/page.', 'mybookaro' );
            } else {
                $button_insert_detail = $single_business_lane
                    ? __( 'Booking page is not assigned and Auto-Insert booking entry is off. Single Business listings are optional, but booking still needs one explicit entry path.', 'mybookaro' )
                    : __( 'Booking page is not assigned and Auto-Insert booking entry is off, so customers have no booking entry point yet.', 'mybookaro' );
                $button_insert_fix = $single_business_lane
                    ? __( 'Open Setup Wizard > Pages and assign a Booking page, or open Setup Wizard > Services and configure a valid Normal page/Shortcode/CSS selector placement.', 'mybookaro' )
                    : __( 'Open Setup Wizard > Pages and assign a Booking page, then place Booking Button/Services Cards explicitly or enable Auto-Insert fallback in Setup Wizard > Services.', 'mybookaro' );
                $button_insert_next_step = $single_business_lane
                    ? __( 'Next step: Open Setup Wizard > Pages, assign Booking page, save, then verify placement strategy in Setup Wizard > Services.', 'mybookaro' )
                    : __( 'Next step: Open Setup Wizard > Pages, assign Booking page, save, then open Setup Wizard > Services and choose one booking entry method.', 'mybookaro' );
                $button_insert_action_url = $wizard_pages_url;
                $button_insert_action_label = __( 'Open pages step', 'mybookaro' );
            }
        }

        $booking_placement_strategy = sanitize_key( (string) ( $generic_status['booking_placement_strategy'] ?? '' ) );
        if ( ! in_array( $booking_placement_strategy, [ 'directory_template', 'normal_page', 'shortcode_only', 'css_selector' ], true ) ) {
            $booking_placement_strategy = function_exists( 'bookaro_get_booking_placement_strategy' )
                ? sanitize_key( (string) bookaro_get_booking_placement_strategy() )
                : '';
        }
        if ( ! in_array( $booking_placement_strategy, [ 'directory_template', 'normal_page', 'shortcode_only', 'css_selector' ], true ) ) {
            $booking_placement_strategy = ( 'single_business' === $site_type ) ? 'normal_page' : 'directory_template';
        }
        $placement_labels = [
            'directory_template' => __( 'Directory listing template', 'mybookaro' ),
            'normal_page' => __( 'Normal page', 'mybookaro' ),
            'shortcode_only' => __( 'Shortcode/block only', 'mybookaro' ),
            'css_selector' => __( 'CSS selector insertion', 'mybookaro' ),
        ];
        $placement_label = $placement_labels[ $booking_placement_strategy ] ?? $booking_placement_strategy;

        $rest_state = ! empty( $api_status['rest_ok'] ) ? 'ok' : 'error';
        $rest_value = ! empty( $api_status['rest_ok'] ) ? __( 'Reachable', 'mybookaro' ) : __( 'Unreachable', 'mybookaro' );
        $rest_detail = (string) ( $api_status['rest_url_masked'] ?? '' );
        $rest_code = (int) ( $api_status['rest_http_code'] ?? 0 );
        if ( $rest_code > 0 ) {
            $rest_detail .= sprintf( ' | %s %d', __( 'HTTP', 'mybookaro' ), $rest_code );
        }
        if ( ! empty( $api_status['rest_access_error'] ) ) {
            $rest_detail .= ' | ' . (string) $api_status['rest_access_error'];
        }
        $rest_fix = ( 'error' === $rest_state )
            ? __( 'Save Settings > Permalinks to refresh rewrite rules, then verify /wp-json/ is not blocked by firewall/security plugins.', 'mybookaro' )
            : '';
        $rest_next_step = ( 'error' === $rest_state )
            ? __( 'Next step: Open Permalinks, click Save Changes, then reload this status page.', 'mybookaro' )
            : '';

        $ajax_state = ! empty( $api_status['ajax_ok'] ) ? 'ok' : 'error';
        $ajax_value = ! empty( $api_status['ajax_ok'] ) ? __( 'Reachable', 'mybookaro' ) : __( 'Unreachable', 'mybookaro' );
        $ajax_detail = (string) ( $api_status['ajax_url_masked'] ?? '' );
        $ajax_code = (int) ( $api_status['ajax_http_code'] ?? 0 );
        if ( $ajax_code > 0 ) {
            $ajax_detail .= sprintf( ' | %s %d', __( 'HTTP', 'mybookaro' ), $ajax_code );
        }
        if ( ! empty( $api_status['ajax_access_error'] ) ) {
            $ajax_detail .= ' | ' . (string) $api_status['ajax_access_error'];
        }
        $ajax_fix = ( 'error' === $ajax_state )
            ? __( 'Check that admin-ajax.php is not blocked by CDN/firewall rules and review Site Health loopback tests.', 'mybookaro' )
            : '';
        $ajax_next_step = ( 'error' === $ajax_state )
            ? __( 'Next step: Open Site Health and fix loopback/HTTP issues, then test status again.', 'mybookaro' )
            : '';

        $provider_mode = sanitize_key( (string) ( $generic_status['provider_resolution_mode'] ?? 'author' ) );
        $provider_mode_valid = ! empty( $generic_status['provider_resolution_mode_valid'] );
        $provider_meta_key = sanitize_key( (string) ( $generic_status['provider_meta_key'] ?? '' ) );
        $provider_mode_labels = [
            'author' => __( 'Listing Author', 'mybookaro' ),
            'meta_key' => __( 'Listing Meta Key', 'mybookaro' ),
        ];
        $provider_mode_label = $provider_mode_labels[ $provider_mode ] ?? __( 'Listing Author', 'mybookaro' );
        $provider_mode_state = 'ok';
        $provider_mode_value = __( 'Valid', 'mybookaro' );
        $provider_mode_detail = ( 'meta_key' === $provider_mode && '' !== $provider_meta_key )
            ? sprintf(
                /* translators: 1: provider mapping label, 2: provider meta key */
                __( 'Provider Mapping is set to %1$s using the `%2$s` field. Bookaro will read that listing field to decide which provider receives bookings.', 'mybookaro' ),
                $provider_mode_label,
                $provider_meta_key
            )
            : sprintf(
                /* translators: %s: provider mapping label */
                __( 'Provider Mapping is set to %s. Bookaro will use that rule to decide which provider receives bookings.', 'mybookaro' ),
                $provider_mode_label
            );
        $provider_mode_fix = '';
        $provider_mode_next_step = '';
        if ( ! $generic_mode_active ) {
            $provider_mode_state = 'info';
            $provider_mode_value = __( 'Not required', 'mybookaro' );
            $provider_mode_detail = __( 'Provider mapping checks apply only in the Generic Directory lane.', 'mybookaro' );
        } elseif ( ! $provider_mode_valid ) {
            $provider_mode_state = 'error';
            $provider_mode_value = __( 'Invalid', 'mybookaro' );
            $provider_mode_detail = __( 'Provider Mapping is not set to a supported option yet. Until this is fixed, Bookaro cannot tell which provider should receive bookings.', 'mybookaro' );
            $provider_mode_fix = __( 'Open Setup Wizard > Listings and set Provider Mapping to Listing Author, or choose Listing Meta Key and fill Provider Meta Key with the listing field that stores the provider user ID.', 'mybookaro' );
            $provider_mode_next_step = __( 'Next step: Open Setup Wizard > Listings, update Provider Mapping and Provider Meta Key as needed, save, then re-run System Status.', 'mybookaro' );
        } elseif ( 'meta_key' === $provider_mode && '' === $provider_meta_key ) {
            $provider_mode_state = 'warn';
            $provider_mode_value = __( 'Invalid', 'mybookaro' );
            $provider_mode_detail = __( 'Provider Mapping is set to Listing Meta Key, but Provider Meta Key is empty. Bookaro cannot read the provider user ID from your listings until you fill that field.', 'mybookaro' );
            $provider_mode_fix = __( 'Provider Mapping is set to Listing Meta Key, but Provider Meta Key is empty. Fill Provider Meta Key with the listing field that stores the provider user ID, or switch Provider Mapping back to Listing Author.', 'mybookaro' );
            $provider_mode_next_step = __( 'Next step: Open Setup Wizard > Listings, fill Provider Meta Key (for example provider_user_id), save, then re-run System Status.', 'mybookaro' );
        }

        $services_model_primary_raw = sanitize_key( (string) $this->options->get( 'services_model', '' ) );
        $services_model_legacy_raw = sanitize_key( (string) $this->options->get( 'generic_services_mode', '' ) );
        $normalize_services_model = static function ( string $value ): string {
            $value = sanitize_key( $value );
            if ( 'admin_catalog' === $value ) {
                return 'admin_only';
            }
            if ( in_array( $value, [ 'provider_only', 'admin_only', 'hybrid' ], true ) ) {
                return $value;
            }
            return '';
        };
        $services_model_primary = $normalize_services_model( $services_model_primary_raw );
        $services_model_legacy = $normalize_services_model( $services_model_legacy_raw );
        $services_model_effective = function_exists( 'bookaro_get_services_model' )
            ? sanitize_key( (string) bookaro_get_services_model() )
            : ( $services_model_primary !== '' ? $services_model_primary : $services_model_legacy );
        if ( ! in_array( $services_model_effective, [ 'provider_only', 'admin_only', 'hybrid' ], true ) ) {
            $services_model_effective = 'hybrid';
        }
        $services_model_labels = [
            'provider_only' => __( 'Provider Only', 'mybookaro' ),
            'admin_only' => __( 'Admin Catalog Only', 'mybookaro' ),
            'hybrid' => __( 'Hybrid', 'mybookaro' ),
        ];
        $services_source_state = 'ok';
        $services_source_value = $services_model_labels[ $services_model_effective ] ?? __( 'Hybrid', 'mybookaro' );
        $services_source_detail = sprintf(
            /* translators: %s: effective services model */
            __( 'Services Source is %s. This decides whether customers see provider-managed services, the shared admin catalog, or both.', 'mybookaro' ),
            $services_source_value
        );
        $services_source_fix = '';
        $services_source_next_step = '';
        if ( ! $generic_mode_active ) {
            $services_source_state = 'info';
            $services_source_value = __( 'Not required', 'mybookaro' );
            $services_source_detail = __( 'Services source checks apply only in the Generic Directory lane.', 'mybookaro' );
        } else {
            $has_invalid_primary_source = ( '' !== $services_model_primary_raw && '' === $services_model_primary );
            $has_invalid_legacy_source = ( '' !== $services_model_legacy_raw && '' === $services_model_legacy );

            if ( $has_invalid_primary_source || $has_invalid_legacy_source ) {
                $services_source_state = 'error';
                $services_source_value = __( 'Invalid', 'mybookaro' );
                $services_source_detail = __( 'Bookaro found unsupported Services Source values in settings. Different screens may resolve services differently until this is normalized.', 'mybookaro' );
                $services_source_fix = __( 'Open Setup Wizard > Services and set Services Source to Provider Only, Admin Catalog Only, or Hybrid.', 'mybookaro' );
                $services_source_next_step = __( 'Next step: Open Setup Wizard > Services, choose the correct Services Source, save, then refresh this check.', 'mybookaro' );
            } elseif ( '' !== $services_model_primary && '' !== $services_model_legacy && $services_model_primary !== $services_model_legacy ) {
                $services_source_state = 'warn';
                $services_source_value = __( 'Mismatch', 'mybookaro' );
                $services_source_detail .= ' ' . __( 'Bookaro found conflicting saved Services Source values. That can make older and newer settings screens behave differently until you save the Services step again.', 'mybookaro' );
                $services_source_fix = __( 'Save Setup Wizard > Services once to normalize Services Source values and avoid inconsistent behavior.', 'mybookaro' );
                $services_source_next_step = __( 'Next step: Open Setup Wizard > Services, confirm Services Source, save, then refresh this check.', 'mybookaro' );
            }
        }

        $lane_provider_mapping = (string) ( $lane_blueprint['provider_mapping'] ?? '' );
        $lane_services_model = (string) ( $lane_blueprint['services_model'] ?? '' );
        $lane_placement_model = (string) ( $lane_blueprint['placement_model'] ?? '' );
        $lane_pages_required = (string) ( $lane_blueprint['pages_required'] ?? '' );
        $generic_setup_preset = sanitize_key( (string) ( $generic_status['generic_setup_preset'] ?? '' ) );
        $preset_launch_detail = GenericPresetProfiles::build_launch_readiness_detail( $generic_setup_preset );
        $preset_alignment = GenericPresetProfiles::evaluate_alignment(
            $generic_setup_preset,
            $provider_mode,
            $services_model_effective,
            $provider_meta_key
        );
        $preset_expectation = ! empty( $preset_alignment['has_preset'] )
            ? GenericPresetProfiles::get( $generic_setup_preset )
            : [];
        if ( empty( $preset_expectation ) ) {
            $preset_expectation = null;
        }

        $lane_state = 'ok';
        $lane_value = $lane_label;
        $lane_detail = trim(
            sprintf(
                /* translators: 1: provider mapping description, 2: services model description, 3: placement model description, 4: required pages description */
                __( 'This lane expects %1$s. It also expects %2$s, %3$s, and %4$s.', 'mybookaro' ),
                $lane_provider_mapping,
                $lane_services_model,
                $lane_placement_model,
                $lane_pages_required
            )
        );
        if ( 'generic_directory' === $lane_id && '' !== trim( $preset_launch_detail ) ) {
            $lane_detail .= ' ' . $preset_launch_detail;
        }
        $lane_fix = '';
        $lane_next_step = '';
        if ( 'mylisting_directory' === $lane_id && ! $mylisting_active ) {
            $lane_state = 'error';
            $lane_value = __( 'Incomplete', 'mybookaro' );
            $lane_fix = __( 'Activate MyListing or switch this site to the Generic Directory lane in Setup Wizard > Lane.', 'mybookaro' );
            $lane_next_step = __( 'Next step: Open Setup Wizard > Lane and confirm whether this site should use MyListing Directory or Generic Directory.', 'mybookaro' );
        } elseif ( 'generic_directory' === $lane_id && null === $preset_expectation ) {
            $lane_state = 'warn';
            $lane_value = __( 'Needs guided preset', 'mybookaro' );
            $lane_detail .= ' ' . __( 'No Generic preset is selected, so Bookaro cannot confirm which ownership path, Services Source, or placement path you intended.', 'mybookaro' );
            $lane_fix = __( 'Open Setup Wizard > Lane and choose Provider-Owned Directory, Editorial + Meta Key Directory, or Shared Catalog Directory so Bookaro can validate the right Generic path.', 'mybookaro' );
            $lane_next_step = __( 'Next step: Open Setup Wizard > Lane, choose the matching Generic preset, save, then refresh System Status.', 'mybookaro' );
        }

        $lane_provider_state = 'ok';
        $lane_provider_value = __( 'Valid', 'mybookaro' );
        $lane_provider_detail = $lane_provider_mapping;
        $lane_provider_fix = '';
        $lane_provider_next_step = '';
        if ( 'single_business' === $lane_id ) {
            $default_provider = is_array( $generic_status['default_provider'] ?? null ) ? $generic_status['default_provider'] : [];
            $default_provider_label = trim( (string) ( $default_provider['label'] ?? '' ) );
            if ( '' === $default_provider_label ) {
                $lane_provider_state = 'error';
                $lane_provider_value = __( 'Missing', 'mybookaro' );
                $lane_provider_detail = __( 'Single Business listings are optional, but Default Provider is required. Without it, booking shortcodes and provider-first services cannot resolve context.', 'mybookaro' );
                $lane_provider_fix = __( 'Next action: open Setup Wizard > Listings, set the Default Provider field to a real provider user, save, then refresh this page.', 'mybookaro' );
                $lane_provider_next_step = __( 'Next step: Open Setup Wizard > Listings, choose Default Provider, save, then refresh this page.', 'mybookaro' );
            } else {
                $lane_provider_detail = sprintf(
                    /* translators: %s: default provider label */
                    __( 'Default Provider: %s. Single Business listings are optional.', 'mybookaro' ),
                    $default_provider_label
                );
            }
        } elseif ( 'mylisting_directory' === $lane_id ) {
            if ( ! $mylisting_active ) {
                $lane_provider_state = 'error';
                $lane_provider_value = __( 'Missing', 'mybookaro' );
                $lane_provider_detail = __( 'MyListing is not active, so listing-owner provider mapping cannot run.', 'mybookaro' );
                $lane_provider_fix = __( 'Activate MyListing or switch to a Generic Directory lane.', 'mybookaro' );
                $lane_provider_next_step = __( 'Next step: Open Themes to activate MyListing, then re-run System Status.', 'mybookaro' );
            } else {
                $lane_provider_detail = __( 'Provider mapping follows MyListing listing ownership context.', 'mybookaro' );
            }
        } else {
            $lane_provider_state = $provider_mode_state;
            $lane_provider_value = $provider_mode_value;
            $lane_provider_detail = trim( $lane_provider_mapping . '. ' . $provider_mode_detail );
            $lane_provider_fix = $provider_mode_fix;
            $lane_provider_next_step = $provider_mode_next_step;
            if ( 'generic_directory' === $lane_id && is_array( $preset_expectation ) && ! empty( $preset_alignment['provider_mismatch'] ) && 'error' !== $lane_provider_state ) {
                $expected_provider_mode = sanitize_key( (string) ( $preset_alignment['provider_expected'] ?? '' ) );
                $expected_provider_label = (string) ( $preset_alignment['provider_expected_label'] ?? ( $preset_expectation['provider_mode_label'] ?? '' ) );
                $provider_actual_label = (string) ( $preset_alignment['provider_actual_label'] ?? $provider_mode_label );
                if ( '' === $expected_provider_label ) {
                    $expected_provider_label = (string) ( $provider_mode_labels[ $expected_provider_mode ] ?? $expected_provider_mode );
                }
                $lane_provider_state = 'error';
                $lane_provider_value = __( 'Preset mismatch', 'mybookaro' );
                $lane_provider_detail .= ' ' . sprintf(
                    /* translators: 1: preset label, 2: expected provider mapping, 3: current provider mapping */
                    __( '%1$s expects Provider Mapping = %2$s, but this site is currently using %3$s. Bookings can route to the wrong provider until those two match.', 'mybookaro' ),
                    (string) ( $preset_expectation['label'] ?? __( 'Generic preset', 'mybookaro' ) ),
                    $expected_provider_label,
                    $provider_actual_label
                );
                $lane_provider_fix = ( 'meta_key' === $expected_provider_mode )
                    ? __( 'This preset needs Provider Mapping = Listing Meta Key. Open Setup Wizard > Listings, switch Provider Mapping to Listing Meta Key, fill Provider Meta Key, then save.', 'mybookaro' )
                    : __( 'This preset needs Provider Mapping = Listing Author. Open Setup Wizard > Listings and switch Provider Mapping back to Listing Author.', 'mybookaro' );
                $lane_provider_next_step = __( 'Next step: Open Setup Wizard > Listings, update Provider Mapping to match the preset, save, then refresh this page.', 'mybookaro' );
            }
        }

        $lane_services_state = 'ok';
        $lane_services_value = __( 'Valid', 'mybookaro' );
        $lane_services_detail = $lane_services_model;
        $lane_services_fix = '';
        $lane_services_next_step = '';
        if ( 'mylisting_directory' === $lane_id ) {
            if ( ! $mylisting_active ) {
                $lane_services_state = 'error';
                $lane_services_value = __( 'Missing', 'mybookaro' );
                $lane_services_detail = __( 'MyListing is not active, so Bookaro cannot resolve MyListing service rows.', 'mybookaro' );
                $lane_services_fix = __( 'Activate MyListing or switch this site to a Generic Directory lane.', 'mybookaro' );
                $lane_services_next_step = __( 'Next step: Activate MyListing, then refresh this page to run services diagnostics.', 'mybookaro' );
            } else {
                $lane_services_state = sanitize_key( (string) ( $mylisting_services_check['state'] ?? 'warn' ) );
                if ( ! in_array( $lane_services_state, [ 'ok', 'warn', 'error', 'info' ], true ) ) {
                    $lane_services_state = 'warn';
                }
                $lane_services_value = (string) ( $mylisting_services_check['value'] ?? __( 'Needs review', 'mybookaro' ) );
                $lane_services_detail_parts = [ trim( $lane_services_model ) ];
                if ( $mylisting_sample_listing_id > 0 ) {
                    $lane_services_detail_parts[] = sprintf(
                        /* translators: %d: listing ID */
                        __( 'Sample listing: #%d.', 'mybookaro' ),
                        $mylisting_sample_listing_id
                    );
                }
                $lane_services_detail_parts[] = (string) ( $mylisting_services_check['detail'] ?? '' );
                $lane_services_detail = trim( implode( ' ', array_filter( $lane_services_detail_parts ) ) );
                $lane_services_fix = (string) ( $mylisting_services_check['fix'] ?? '' );
                $lane_services_next_step = (string) ( $mylisting_services_check['next_step'] ?? '' );
            }
        } else {
            $lane_services_state = $services_source_state;
            $lane_services_value = $services_source_value;
            $lane_services_detail = trim( $lane_services_model . '. ' . $services_source_detail );
            $lane_services_fix = $services_source_fix;
            $lane_services_next_step = $services_source_next_step;
            if ( 'generic_directory' === $lane_id && is_array( $preset_expectation ) && ! empty( $preset_alignment['services_mismatch'] ) && 'error' !== $lane_services_state ) {
                $expected_services_model = sanitize_key( (string) ( $preset_alignment['services_expected'] ?? '' ) );
                $expected_services_label = (string) ( $preset_alignment['services_expected_label'] ?? ( $preset_expectation['services_model_label'] ?? '' ) );
                $services_actual_label = (string) ( $preset_alignment['services_actual_label'] ?? $services_source_value );
                if ( '' === $expected_services_label ) {
                    $expected_services_label = (string) ( $services_model_labels[ $expected_services_model ] ?? $expected_services_model );
                }
                $lane_services_state = 'error';
                $lane_services_value = __( 'Preset mismatch', 'mybookaro' );
                $lane_services_detail .= ' ' . sprintf(
                    /* translators: 1: preset label, 2: expected services model, 3: current services model */
                    __( '%1$s expects Services Source = %2$s, but this site is currently using %3$s. Customers may see the wrong service list until those two match.', 'mybookaro' ),
                    (string) ( $preset_expectation['label'] ?? __( 'Generic preset', 'mybookaro' ) ),
                    $expected_services_label,
                    $services_actual_label
                );
                $lane_services_fix = sprintf(
                    /* translators: %s: expected services source */
                    __( 'This preset needs Services Source = %s. Open Setup Wizard > Services and update Services Source.', 'mybookaro' ),
                    $expected_services_label
                );
                $lane_services_next_step = __( 'Next step: Open Setup Wizard > Services, update Services Source to match the preset, save, then refresh this page.', 'mybookaro' );
            }
            if ( 'single_business' === $lane_id && 'provider_only' !== $services_model_effective && 'error' !== $lane_services_state ) {
                $lane_services_state = 'warn';
                $lane_services_value = $services_source_value;
                $lane_services_detail .= ' ' . __( 'Provider Only is the recommended default for Single Business onboarding.', 'mybookaro' );
                if ( '' === $lane_services_fix ) {
                    $lane_services_fix = __( 'Use Provider Only unless you intentionally run a shared admin catalog or hybrid workflow.', 'mybookaro' );
                }
                if ( '' === $lane_services_next_step ) {
                    $lane_services_next_step = __( 'Next step: Open Setup Wizard > Services, choose Provider Only, save, and refresh.', 'mybookaro' );
                }
            }
        }

        $lane_placement_state = 'ok';
        $lane_placement_value = $placement_label;
        $lane_placement_detail = trim( $lane_placement_model . ' | ' . $placement_label );
        $lane_placement_fix = '';
        $lane_placement_next_step = '';
        if ( 'mylisting_directory' === $lane_id && ! in_array( $booking_placement_strategy, [ 'directory_template', 'shortcode_only' ], true ) ) {
            $lane_placement_state = 'warn';
            $lane_placement_fix = __( 'Use Directory listing template placement for MyListing Directory lane unless you intentionally run shortcode-only placement.', 'mybookaro' );
            $lane_placement_next_step = __( 'Next step: Open Settings > General, set Booking placement strategy to Directory listing template, save, then re-check.', 'mybookaro' );
        } elseif ( 'single_business' === $lane_id && ! in_array( $booking_placement_strategy, [ 'normal_page', 'shortcode_only', 'css_selector' ], true ) ) {
            $lane_placement_state = 'error';
            $lane_placement_fix = __( 'Single Business should use Normal page, Shortcode/block only, or CSS selector placement (not listing template placement).', 'mybookaro' );
            $lane_placement_next_step = __( 'Next step: Open Settings > General, change Booking placement strategy, save, and refresh System Status.', 'mybookaro' );
        }

        $services_page_id = absint( $this->options->get( 'generic_setup_services_page_id', 0 ) );
        $lane_pages_state = 'ok';
        $lane_pages_value = __( 'Ready', 'mybookaro' );
        $lane_pages_detail_parts = [];
        $lane_pages_fix = '';
        $lane_pages_next_step = '';
        if ( 'mylisting_directory' === $lane_id ) {
            if ( $shortcodes_mode ) {
                $lane_pages_detail_parts[] = __( 'Shortcode dashboard mode is active, so provider and customer dashboard pages are required.', 'mybookaro' );
                if ( ! $provider_page_ready || ! $customer_page_ready ) {
                    $lane_pages_state = 'error';
                    $lane_pages_value = __( 'Missing pages', 'mybookaro' );
                    $lane_pages_fix = __( 'Assign provider/customer dashboard pages and add dashboard blocks/shortcodes.', 'mybookaro' );
                    $lane_pages_next_step = __( 'Next step: Open Setup Wizard > Pages, configure dashboard pages, save, then refresh this page.', 'mybookaro' );
                }
            } else {
                $lane_pages_value = __( 'Optional', 'mybookaro' );
                $lane_pages_detail_parts[] = __( 'WooCommerce My Account mode is active; dedicated dashboard pages are optional.', 'mybookaro' );
            }
        } elseif ( 'single_business' === $lane_id ) {
            $lane_pages_detail_parts[] = __( 'Single Business listings are optional; launch depends on provider-first page setup.', 'mybookaro' );
            $single_business_missing_booking_page = ! $booking_page_exists;
            $single_business_missing_provider_dashboard = $shortcodes_mode && ! $provider_page_ready;
            $single_business_missing_customer_dashboard = $shortcodes_mode && ! $customer_page_ready;
            $single_business_missing_dashboard_pages = $single_business_missing_provider_dashboard || $single_business_missing_customer_dashboard;
            if ( $single_business_missing_booking_page || $single_business_missing_dashboard_pages ) {
                $lane_pages_state = 'error';
                if ( $single_business_missing_booking_page && $single_business_missing_dashboard_pages ) {
                    $lane_pages_value = __( 'Missing booking + dashboard pages', 'mybookaro' );
                } elseif ( $single_business_missing_booking_page ) {
                    $lane_pages_value = __( 'Missing booking page', 'mybookaro' );
                } else {
                    $lane_pages_value = __( 'Missing dashboard pages', 'mybookaro' );
                }
                if ( $single_business_missing_booking_page ) {
                    $lane_pages_detail_parts[] = __( 'Booking page is required for Single Business launch.', 'mybookaro' );
                }
                if ( $single_business_missing_dashboard_pages ) {
                    $lane_pages_detail_parts[] = __( 'Shortcodes mode requires provider/customer dashboard pages with dashboard embeds.', 'mybookaro' );
                }
            }
            if ( $lane_pages_state === 'error' ) {
                if ( $single_business_missing_booking_page ) {
                    $lane_pages_fix = __( 'Next action: open Setup Wizard > Pages, assign Booking page, save, then confirm the booking page includes Booking Button/Services Cards placement.', 'mybookaro' );
                    $lane_pages_next_step = __( 'Next step: Open Setup Wizard > Pages, set Booking page, save, then refresh this page.', 'mybookaro' );
                } else {
                    $lane_pages_fix = __( 'Next action: open Setup Wizard > Pages and assign missing Provider/Customer dashboard pages, then add the matching dashboard embeds.', 'mybookaro' );
                    $lane_pages_next_step = __( 'Next step: Open Setup Wizard > Pages, configure dashboard pages, save, then refresh this page.', 'mybookaro' );
                }
                if ( $single_business_missing_booking_page && $single_business_missing_dashboard_pages ) {
                    $lane_pages_fix .= ' ' . __( 'After Booking page is assigned, assign missing dashboard pages in the same Pages step if you use Shortcodes mode.', 'mybookaro' );
                    $lane_pages_next_step = __( 'Next step: Open Setup Wizard > Pages, assign Booking + dashboard pages, save, then refresh this page.', 'mybookaro' );
                }
            }
            if ( $services_page_id < 1 ) {
                if ( 'error' !== $lane_pages_state ) {
                    $lane_pages_state = 'warn';
                    $lane_pages_value = __( 'Services page recommended', 'mybookaro' );
                }
                $lane_pages_detail_parts[] = __( 'Services page is optional but recommended for Single Business onboarding.', 'mybookaro' );
                if ( '' === $lane_pages_fix ) {
                    $lane_pages_fix = __( 'Assign a services page in Setup Wizard > Pages to give customers a clear service entry point.', 'mybookaro' );
                }
                if ( '' === $lane_pages_next_step ) {
                    $lane_pages_next_step = __( 'Next step: Open Setup Wizard > Pages, assign Services page, save, and refresh this page.', 'mybookaro' );
                }
            }
        } else {
            if ( $shortcodes_mode && ( ! $booking_page_exists || ! $provider_page_ready || ! $customer_page_ready ) ) {
                $lane_pages_state = 'error';
                $lane_pages_value = __( 'Missing pages', 'mybookaro' );
                $lane_pages_fix = __( 'Generic Directory in Shortcodes mode requires Booking + Provider Dashboard + Customer Dashboard pages. After assigning them in Setup Wizard > Pages, edit the two dashboard pages and add the matching MyBookaro dashboard blocks or shortcodes.', 'mybookaro' );
                $lane_pages_next_step = __( 'Next step: Open Setup Wizard > Pages, assign the three required pages, save, then edit the dashboard pages to add embeds and refresh this page.', 'mybookaro' );
            } elseif ( ! $booking_page_exists && ! $auto_insert_enabled ) {
                $lane_pages_state = 'warn';
                $lane_pages_value = __( 'Booking entry missing', 'mybookaro' );
                $lane_pages_fix = __( 'Assign a Booking page in Setup Wizard > Pages, then place Booking Button/Services Cards where customers start bookings, or enable Auto-Insert fallback in Setup Wizard > Services.', 'mybookaro' );
                $lane_pages_next_step = __( 'Next step: Open Setup Wizard > Pages, assign Booking page, save, then refresh this page.', 'mybookaro' );
            }
        }
        $lane_pages_detail_parts[] = $lane_pages_required;
        $lane_pages_detail = implode( ' | ', array_filter( $lane_pages_detail_parts ) );

        $single_business_services_state = 'info';
        $single_business_services_value = __( 'Not required', 'mybookaro' );
        $single_business_services_detail = __( 'Default Provider service inventory checks apply only in Single Business lane.', 'mybookaro' );
        $single_business_services_fix = '';
        $single_business_services_next_step = '';
        $single_business_services_action_url = $wizard_services_url;
        $single_business_services_action_label = __( 'Open services step', 'mybookaro' );
        if ( 'single_business' === $lane_id ) {
            $default_provider = is_array( $generic_status['default_provider'] ?? null ) ? $generic_status['default_provider'] : [];
            $default_provider_id = absint( $default_provider['id'] ?? 0 );
            if ( $default_provider_id < 1 ) {
                $single_business_services_state = 'error';
                $single_business_services_value = __( 'Blocked', 'mybookaro' );
                $single_business_services_detail = __( 'Cannot validate Single Business service inventory until Default Provider is set.', 'mybookaro' );
                $single_business_services_fix = __( 'Next action: open Setup Wizard > Listings, set Default Provider, save, then return to this check.', 'mybookaro' );
                $single_business_services_next_step = __( 'Next step: Open Setup Wizard > Listings, choose Default Provider, save, then refresh this page.', 'mybookaro' );
                $single_business_services_action_url = $wizard_listings_url;
                $single_business_services_action_label = __( 'Set Default Provider', 'mybookaro' );
            } else {
                $available_services = function_exists( 'bookaro_get_generic_provider_context_services' )
                    ? bookaro_get_generic_provider_context_services( $default_provider_id )
                    : [];
                $available_services = is_array( $available_services ) ? $available_services : [];
                $available_service_count = count( $available_services );

                if ( $available_service_count > 0 ) {
                    $single_business_services_state = 'ok';
                    $single_business_services_value = __( 'Ready', 'mybookaro' );
                    $single_business_services_detail = sprintf(
                        /* translators: %d: available services count */
                        __( 'Available services for the Default Provider: %d. Provider-first booking pages have at least one service to render.', 'mybookaro' ),
                        $available_service_count
                    );
                    $single_business_services_action_url = $services_url;
                    $single_business_services_action_label = __( 'Open services', 'mybookaro' );
                } else {
                    $single_business_services_state = 'error';
                    $single_business_services_value = __( 'Missing services', 'mybookaro' );
                    $single_business_services_detail = __( 'No services are currently available for the Default Provider, so the Single Business booking UI will load without any service choices.', 'mybookaro' );
                    $single_business_services_fix = __( 'Next action: create at least one service for the Default Provider, then return to Setup Wizard > Services to confirm Services Source if needed.', 'mybookaro' );
                    $single_business_services_next_step = __( 'Next step: Click Create first service, publish it for the Default Provider, then refresh this page.', 'mybookaro' );
                    $single_business_services_action_url = $create_service_url;
                    $single_business_services_action_label = __( 'Create first service', 'mybookaro' );
                }
            }
        }

        $services_orphans = (int) ( $orphan_status['services_orphaned_total'] ?? 0 );
        $services_state = $services_orphans > 0 ? 'warn' : 'ok';
        $services_value = $services_orphans > 0 ? __( 'Found', 'mybookaro' ) : __( 'None', 'mybookaro' );
        $services_detail = sprintf(
            /* translators: %1$d: numeric value, %2$d: numeric value, %3$d: numeric value */
            __( '%1$d orphaned services (missing listing: %2$d, missing provider: %3$d).', 'mybookaro' ),
            $services_orphans,
            (int) ( $orphan_status['services_missing_listing'] ?? 0 ),
            (int) ( $orphan_status['services_missing_provider'] ?? 0 )
        );
        $services_fix = $services_orphans > 0
            ? __( 'Review services and reassign or remove entries linked to deleted listings/providers.', 'mybookaro' )
            : '';

        $bookings_orphans = (int) ( $orphan_status['bookings_orphaned_total'] ?? 0 );
        $bookings_state = $bookings_orphans > 0 ? 'warn' : 'ok';
        $bookings_value = $bookings_orphans > 0 ? __( 'Found', 'mybookaro' ) : __( 'None', 'mybookaro' );
        $bookings_detail = sprintf(
            /* translators: %1$d: numeric value, %2$d: numeric value, %3$d: numeric value, %4$d: numeric value, %5$d: numeric value */
            __( '%1$d orphaned bookings (listing: %2$d, service: %3$d, provider: %4$d, customer: %5$d).', 'mybookaro' ),
            $bookings_orphans,
            (int) ( $orphan_status['bookings_missing_listing'] ?? 0 ),
            (int) ( $orphan_status['bookings_missing_service'] ?? 0 ),
            (int) ( $orphan_status['bookings_missing_provider'] ?? 0 ),
            (int) ( $orphan_status['bookings_missing_customer'] ?? 0 )
        );
        $bookings_fix = $bookings_orphans > 0
            ? __( 'Review affected bookings and update references or remove stale records.', 'mybookaro' )
            : '';

        $spam_protection_enabled = ! empty( $settings_status['spam_protection_enabled'] );
        $spam_config_state = $spam_protection_enabled ? 'ok' : 'warn';
        $spam_config_value = $spam_protection_enabled ? __( 'Enabled', 'mybookaro' ) : __( 'Disabled', 'mybookaro' );
        $spam_config_detail = sprintf(
            /* translators: %1$s: dynamic string, %2$s: dynamic string, %3$d: numeric value, %4$d: numeric value, %5$s: dynamic string, %6$d: numeric value */
            __( 'Honeypot: %1$s | Min fill: %2$ss | IP limit: %3$d | Email limit: %4$d | Duplicate window: %5$sh | Blacklist words: %6$d', 'mybookaro' ),
            ! empty( $settings_status['spam_honeypot_enabled'] ) ? __( 'On', 'mybookaro' ) : __( 'Off', 'mybookaro' ),
            (int) ( $settings_status['spam_min_fill_seconds'] ?? 0 ),
            (int) ( $settings_status['spam_burst_ip_limit'] ?? 0 ),
            (int) ( $settings_status['spam_burst_email_limit'] ?? 0 ),
            (int) ( $settings_status['spam_duplicate_pending_hours'] ?? 0 ),
            (int) ( $settings_status['spam_blacklist_words_count'] ?? 0 )
        );
        $spam_config_fix = $spam_protection_enabled
            ? ''
            : __( 'Enable at least one spam protection option in Settings > General > Spam protection.', 'mybookaro' );

        $spam_total_blocks = (int) ( $settings_status['spam_total_blocks'] ?? 0 );
        $spam_reasons = is_array( $settings_status['spam_block_reasons'] ?? null ) ? $settings_status['spam_block_reasons'] : [];
        $reason_labels = [
            'honeypot' => __( 'honeypot', 'mybookaro' ),
            'too_fast' => __( 'too fast', 'mybookaro' ),
            'burst_ip' => __( 'burst IP', 'mybookaro' ),
            'burst_email' => __( 'burst email', 'mybookaro' ),
            'blacklist' => __( 'blacklist', 'mybookaro' ),
            'duplicate_pending' => __( 'duplicate pending', 'mybookaro' ),
        ];
        $reason_parts = [];
        foreach ( $spam_reasons as $reason => $count ) {
            $count = absint( $count );
            if ( $count < 1 ) {
                continue;
            }
            $reason_key = sanitize_key( (string) $reason );
            $reason_label = $reason_labels[ $reason_key ] ?? $reason_key;
            $reason_parts[] = $reason_label . ': ' . $count;
        }
        $spam_activity_state = 'info';
        $spam_activity_value = __( 'No blocks recorded', 'mybookaro' );
        $spam_activity_detail = __( 'No spam blocks have been recorded yet.', 'mybookaro' );
        $spam_activity_fix = '';
        if ( $spam_total_blocks > 0 ) {
            $spam_activity_value = sprintf(
                /* translators: %d: total blocked booking submissions */
                __( '%d blocked requests', 'mybookaro' ),
                $spam_total_blocks
            );
            $spam_activity_detail = ! empty( $reason_parts )
                ? sprintf(
                    /* translators: %s: dynamic string */
                    __( 'By reason: %s', 'mybookaro' ),
                    implode( ', ', $reason_parts )
                )
                : __( 'Blocked requests were recorded.', 'mybookaro' );
            if ( $spam_total_blocks >= 25 ) {
                $spam_activity_state = 'warn';
                $spam_activity_fix = __( 'If legitimate users report issues, lower strict spam thresholds in Settings > General > Spam protection.', 'mybookaro' );
            }
        }

        $checks = [
            $this->build_support_check(
                'lane_active',
                __( 'Active lane', 'mybookaro' ),
                $lane_state,
                $lane_value,
                $lane_detail,
                $lane_fix,
                $wizard_modes_url,
                __( 'Open lane step', 'mybookaro' ),
                $lane_next_step
            ),
            $this->build_support_check(
                'lane_provider_mapping',
                __( 'Lane provider routing', 'mybookaro' ),
                $lane_provider_state,
                $lane_provider_value,
                $lane_provider_detail,
                $lane_provider_fix,
                $wizard_listings_url,
                __( 'Open listings step', 'mybookaro' ),
                $lane_provider_next_step
            ),
            $this->build_support_check(
                'lane_services_model',
                __( 'Lane services source', 'mybookaro' ),
                $lane_services_state,
                $lane_services_value,
                $lane_services_detail,
                $lane_services_fix,
                $wizard_services_url,
                __( 'Open services step', 'mybookaro' ),
                $lane_services_next_step
            ),
            $this->build_support_check(
                'lane_placement_model',
                __( 'Lane placement model', 'mybookaro' ),
                $lane_placement_state,
                $lane_placement_value,
                $lane_placement_detail,
                $lane_placement_fix,
                $wizard_services_url,
                __( 'Open services step', 'mybookaro' ),
                $lane_placement_next_step
            ),
            $this->build_support_check(
                'lane_required_pages',
                __( 'Lane required pages and dashboards', 'mybookaro' ),
                $lane_pages_state,
                $lane_pages_value,
                $lane_pages_detail,
                $lane_pages_fix,
                $wizard_pages_url,
                __( 'Open pages step', 'mybookaro' ),
                $lane_pages_next_step
            ),
            $this->build_support_check(
                'single_business_service_inventory',
                __( 'Single Business service inventory', 'mybookaro' ),
                $single_business_services_state,
                $single_business_services_value,
                $single_business_services_detail,
                $single_business_services_fix,
                $single_business_services_action_url,
                $single_business_services_action_label,
                $single_business_services_next_step
            ),
            $this->build_support_check(
                'generic_confirmation_state',
                __( 'Generic path confirmation state', 'mybookaro' ),
                $generic_confirmation_state,
                $generic_confirmation_value,
                $generic_confirmation_detail,
                $generic_confirmation_fix,
                $wizard_modes_url,
                __( 'Open lane step', 'mybookaro' ),
                $generic_confirmation_next_step
            ),
            $this->build_support_check(
                'mylisting_active',
                __( 'MyListing active', 'mybookaro' ),
                $mylisting_state,
                $mylisting_value,
                $mylisting_detail,
                $mylisting_fix,
                $mylisting_required ? $themes_url : $wizard_modes_url,
                $mylisting_required ? __( 'Open themes', 'mybookaro' ) : __( 'Open lane step', 'mybookaro' ),
                $mylisting_next_step
            ),
            $this->build_support_check(
                'repeater_class',
                __( 'Repeater CSS class configured', 'mybookaro' ),
                $repeater_state,
                $repeater_value,
                $repeater_detail,
                $repeater_fix,
                $mylisting_active ? $wizard_services_url : $settings_url,
                $mylisting_active ? __( 'Open services step', 'mybookaro' ) : __( 'Open settings', 'mybookaro' ),
                $repeater_next_step
            ),
            $this->build_support_check(
                'listing_post_types',
                __( 'Selected listing post type valid', 'mybookaro' ),
                $types_state,
                $types_value,
                $types_detail,
                $types_fix,
                $wizard_listings_url,
                __( 'Open listings step', 'mybookaro' ),
                $types_next_step
            ),
            $this->build_support_check(
                'required_pages',
                __( 'Page assignment valid', 'mybookaro' ),
                $missing_pages_state,
                $missing_pages_value,
                $missing_pages_detail,
                $missing_pages_fix,
                $wizard_pages_url,
                __( 'Open pages step', 'mybookaro' ),
                $missing_pages_next_step
            ),
            $this->build_support_check(
                'provider_dashboard_page',
                __( 'Provider dashboard page ready', 'mybookaro' ),
                $provider_page_state,
                $provider_page_value,
                $provider_page_detail,
                $provider_page_fix,
                $provider_page_action_url,
                $provider_page_action_label,
                $provider_page_next_step
            ),
            $this->build_support_check(
                'customer_dashboard_page',
                __( 'Customer dashboard page ready', 'mybookaro' ),
                $customer_page_state,
                $customer_page_value,
                $customer_page_detail,
                $customer_page_fix,
                $customer_page_action_url,
                $customer_page_action_label,
                $customer_page_next_step
            ),
            $this->build_support_check(
                'rest_access',
                __( 'REST API accessible', 'mybookaro' ),
                $rest_state,
                $rest_value,
                $rest_detail,
                $rest_fix,
                $permalinks_url,
                __( 'Open permalinks', 'mybookaro' ),
                $rest_next_step
            ),
            $this->build_support_check(
                'ajax_access',
                __( 'AJAX endpoint accessible', 'mybookaro' ),
                $ajax_state,
                $ajax_value,
                $ajax_detail,
                $ajax_fix,
                $site_health_url,
                __( 'Open Site Health', 'mybookaro' ),
                $ajax_next_step
            ),
            $this->build_support_check(
                'provider_resolution_mode',
                __( 'Provider mapping valid', 'mybookaro' ),
                $provider_mode_state,
                $provider_mode_value,
                $provider_mode_detail,
                $provider_mode_fix,
                $wizard_listings_url,
                __( 'Open listings step', 'mybookaro' ),
                $provider_mode_next_step
            ),
            $this->build_support_check(
                'services_source',
                __( 'Services source alignment', 'mybookaro' ),
                $services_source_state,
                $services_source_value,
                $services_source_detail,
                $services_source_fix,
                $wizard_services_url,
                __( 'Open services step', 'mybookaro' ),
                $services_source_next_step
            ),
            $this->build_support_check(
                'booking_button_insertion',
                __( 'Placement strategy valid', 'mybookaro' ),
                $button_insert_state,
                $button_insert_value,
                $button_insert_detail,
                $button_insert_fix,
                $button_insert_action_url,
                $button_insert_action_label,
                $button_insert_next_step
            ),
            $this->build_support_check(
                'spam_protection',
                __( 'Spam protection configured', 'mybookaro' ),
                $spam_config_state,
                $spam_config_value,
                $spam_config_detail,
                $spam_config_fix,
                $settings_url,
                __( 'Open settings', 'mybookaro' )
            ),
            $this->build_support_check(
                'spam_activity',
                __( 'Spam blocks recorded', 'mybookaro' ),
                $spam_activity_state,
                $spam_activity_value,
                $spam_activity_detail,
                $spam_activity_fix,
                $settings_url,
                __( 'Open settings', 'mybookaro' )
            ),
            $this->build_support_check(
                'orphaned_services',
                __( 'Orphaned services', 'mybookaro' ),
                $services_state,
                $services_value,
                $services_detail,
                $services_fix,
                $services_url,
                __( 'Open services', 'mybookaro' )
            ),
            $this->build_support_check(
                'orphaned_bookings',
                __( 'Orphaned bookings', 'mybookaro' ),
                $bookings_state,
                $bookings_value,
                $bookings_detail,
                $bookings_fix,
                $bookings_url,
                __( 'Open bookings', 'mybookaro' )
            ),
        ];

        if ( $generic_mode_active && ! $generic_confirmation_required ) {
            $checks = array_merge(
                [
                    $this->build_support_check(
                        'generic_validation_runtime_status',
                        __( 'Generic validation result summary', 'mybookaro' ),
                        $runtime_failed_count > 0 ? 'error' : 'ok',
                        $runtime_failed_count > 0 ? __( 'Blocked', 'mybookaro' ) : __( 'Clear', 'mybookaro' ),
                        $runtime_failed_count > 0
                            ? sprintf(
                                /* translators: %d: number of runtime checks needing attention */
                                _n(
                                    '%d Generic validation check still needs attention. At least one directory lane choice, services source, booking entry, or page rule can still block bookings.',
                                    '%d Generic validation checks still need attention. At least one directory lane choice, services source, booking entry, or page rule can still block bookings.',
                                    $runtime_failed_count,
                                    'mybookaro'
                                ),
                                (int) $runtime_failed_count
                            )
                            : __( 'Generic validation checks are currently passing for directory lane choice, services source, booking entry placement, and required pages.', 'mybookaro' ),
                        $runtime_failed_count > 0
                            ? __( 'Open the Generic validation checks on this page and resolve every warning or error before launch.', 'mybookaro' )
                            : '',
                        $generic_validation_anchor_url,
                        $runtime_failed_count > 0 ? __( 'Open Generic validation checks', 'mybookaro' ) : __( 'Jump to validation checks', 'mybookaro' ),
                        $runtime_failed_count > 0
                            ? __( 'Next step: Apply the fix for each failed Generic validation check, then refresh this page to confirm everything passes.', 'mybookaro' )
                            : ''
                    ),
                    $this->build_support_check(
                        'generic_validation_refresh',
                        __( 'Generic validation freshness', 'mybookaro' ),
                        $validation_refresh_required ? 'error' : 'ok',
                        $validation_refresh_required ? __( 'Required', 'mybookaro' ) : __( 'Current', 'mybookaro' ),
                        $validation_refresh_required
                            ? __( 'Settings changed after the last validation run. Until you re-run validation, Bookaro cannot confirm that directory lane choice, services source, placement, and pages still match.', 'mybookaro' )
                            : __( 'Generic validation reflects the current directory lane choice, services source, placement, and page setup.', 'mybookaro' ),
                        $validation_refresh_required
                            ? __( 'Open the Generic validation results below and work through every warning or error before launch.', 'mybookaro' )
                            : '',
                        $generic_validation_anchor_url,
                        $validation_refresh_required ? __( 'Run validation now', 'mybookaro' ) : __( 'Jump to validation checks', 'mybookaro' ),
                        $validation_refresh_required
                            ? __( 'Next step: Review the Generic validation checks on this page, apply the fixes, then confirm all critical checks pass.', 'mybookaro' )
                            : ''
                    ),
                ],
                $checks
            );
        }

        foreach ( $runtime_validation_checks as $runtime_check ) {
            if ( ! is_array( $runtime_check ) ) {
                continue;
            }
            $runtime_id = sanitize_key( (string) ( $runtime_check['id'] ?? '' ) );
            if ( '' === $runtime_id ) {
                continue;
            }
            $runtime_label = (string) ( $runtime_check['label'] ?? '' );
            if ( '' === $runtime_label ) {
                continue;
            }
            $runtime_state = sanitize_key( (string) ( $runtime_check['state'] ?? 'info' ) );
            if ( ! in_array( $runtime_state, [ 'ok', 'warn', 'error', 'info' ], true ) ) {
                $runtime_state = 'info';
            }
            $runtime_value = (string) ( $runtime_check['value'] ?? '' );
            $runtime_detail = (string) ( $runtime_check['detail'] ?? '' );
            $runtime_fix = (string) ( $runtime_check['fix'] ?? '' );
            $runtime_action_url = (string) ( $runtime_check['action_url'] ?? $settings_url );
            $runtime_action_label = (string) ( $runtime_check['action_label'] ?? __( 'Open settings', 'mybookaro' ) );
            $runtime_next_step = (string) ( $runtime_check['next_step'] ?? '' );
            if ( in_array( $runtime_state, [ 'warn', 'error' ], true ) && '' === trim( $runtime_fix ) ) {
                $runtime_fix = __( 'Apply the expected configuration for this validation item, then run System Status again.', 'mybookaro' );
            }
            if ( in_array( $runtime_state, [ 'warn', 'error' ], true ) && '' === trim( $runtime_next_step ) ) {
                $runtime_next_step = __( 'Next step: Open the linked page, apply the fix, save, and re-run this check.', 'mybookaro' );
            }

            $checks[] = $this->build_support_check(
                'generic_validation_' . $runtime_id,
                $runtime_label,
                $runtime_state,
                $runtime_value,
                $runtime_detail,
                $runtime_fix,
                $runtime_action_url,
                $runtime_action_label,
                $runtime_next_step
            );
        }

        return $checks;
    }

    private function build_support_check(
        string $id,
        string $label,
        string $state,
        string $value,
        string $detail,
        string $fix = '',
        string $action_url = '',
        string $action_label = '',
        string $next_step = ''
    ): array {
        $state = sanitize_key( $state );
        if ( ! in_array( $state, [ 'ok', 'warn', 'error', 'info' ], true ) ) {
            $state = 'info';
        }

        $action_url = trim( $action_url );
        $action_label = trim( $action_label );
        $fix = trim( $fix );
        $next_step = trim( $next_step );
        if ( in_array( $state, [ 'warn', 'error' ], true ) ) {
            if ( '' === $fix ) {
                if ( '' !== $action_url && '' !== $action_label ) {
                    $fix = sprintf(
                        /* translators: %s: action label */
                        __( 'Use %s and align this check with the expected lane configuration.', 'mybookaro' ),
                        $action_label
                    );
                } else {
                    $fix = __( 'Align this check with the expected lane configuration before launch.', 'mybookaro' );
                }
            }
            if ( '' === $next_step ) {
                if ( '' !== $action_url && '' !== $action_label ) {
                    $next_step = sprintf(
                        /* translators: %s: action label */
                        __( 'Next step: %s, apply the suggested fix, save, then re-run System Status.', 'mybookaro' ),
                        $action_label
                    );
                } else {
                    $next_step = __( 'Next step: Apply the suggested fix, save, then re-run System Status.', 'mybookaro' );
                }
            }
        }
        $needs_fix = in_array( $state, [ 'warn', 'error' ], true ) && ( '' !== $fix || '' !== $next_step );

        return [
            'id' => sanitize_key( $id ),
            'label' => $label,
            'state' => $state,
            'value' => $value,
            'detail' => $detail,
            'fix' => $fix,
            'next_step' => $next_step,
            'needs_fix' => $needs_fix,
            'action_url' => $action_url,
            'action_label' => $action_label,
        ];
    }

    private function mask_report_text( string $text ): string
    {
        $text = preg_replace_callback(
            '~https?://[^\s]+~i',
            function( array $matches ): string {
                return $this->mask_url( $matches[0] ?? '' );
            },
            $text
        );

        $text = preg_replace_callback(
            '/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i',
            function( array $matches ): string {
                return $this->mask_email( $matches[0] ?? '' );
            },
            $text
        );

        return $text;
    }

    private function mask_url( string $url ): string
    {
        $url = trim( $url );
        if ( $url === '' ) {
            return $url;
        }

        $parts = wp_parse_url( $url );
        if ( empty( $parts['host'] ) ) {
            return $url;
        }

        $scheme = isset( $parts['scheme'] ) ? $parts['scheme'] : 'https';
        $host = $parts['host'];
        $port = isset( $parts['port'] ) ? ':' . $parts['port'] : '';

        return sprintf( '%s://%s%s/...', $scheme, $host, $port );
    }

    private function mask_email( string $email ): string
    {
        $email = sanitize_email( $email );
        if ( $email === '' || strpos( $email, '@' ) === false ) {
            return $email;
        }

        [ $local, $domain ] = explode( '@', $email, 2 );
        if ( $local === '' ) {
            return '***@' . $domain;
        }

        $first = substr( $local, 0, 1 );
        return $first . '***@' . $domain;
    }
}
