<?php
if (!defined('ABSPATH')) exit;


/*
 * CAS health check diagnostics owner.
 *
 * This module runs explicit admin diagnostics. Direct read-only $wpdb table
 * existence checks are intentional because WordPress has no higher-level API for
 * CAS custom-table presence checks.
 *
 * Health checks must reflect the current environment, so caching is intentionally
 * avoided. Do not copy these disables to request/input/rendering code.
 */
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery -- Intentional read-only admin health diagnostics.
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Health checks must reflect current environment state.


/**
 * CAS Admin Health Check
 */


if (!function_exists('custausu_admin_logs_dir')) {
  function custausu_admin_logs_dir(): string {
    $uploads = function_exists('wp_upload_dir') ? wp_upload_dir(null, false) : [];

    if (!empty($uploads['basedir']) && is_string($uploads['basedir'])) {
      return rtrim($uploads['basedir'], '/') . '/custom-auth-suite/logs';
    }

    return rtrim(get_temp_dir(), '/') . '/custom-auth-suite/logs';
  }
}

if (!function_exists('custausu_admin_min_php_ok')) {
  function custausu_admin_min_php_ok(): bool {
    return defined('PHP_VERSION_ID')
      ? (PHP_VERSION_ID >= 80100)
      : version_compare(PHP_VERSION, '8.1', '>=');
  }
}

if (!function_exists('custausu_admin_health_check_site_slug')) {
  function custausu_admin_health_check_site_slug(): string {
    $site_locale = (string) get_option('WPLANG');
    if ($site_locale === '') $site_locale = 'en_US';

    $slug = sanitize_key(strtolower(explode('_', $site_locale)[0] ?? 'en'));
    return $slug !== '' ? $slug : 'en';
  }
}

if (!function_exists('custausu_admin_health_check_langs')) {
  function custausu_admin_health_check_langs(array $opt): array {
    $lang = sanitize_key((string)($opt['routes_default_lang'] ?? ''));
    if ($lang === '') $lang = custausu_admin_health_check_site_slug();
    return [$lang];
  }
}

if (!function_exists('custausu_admin_health_check_normalize_path')) {
  function custausu_admin_health_check_normalize_path($path): string {
    $path = trim((string)$path);
    if ($path === '') return '';

    $parsed = wp_parse_url($path, PHP_URL_PATH);
    if (is_string($parsed) && $parsed !== '') {
      $path = $parsed;
    }

    if ($path === '') return '';
    if ($path[0] !== '/') $path = '/' . $path;

    // WordPress route/path comparison in admin should be case-insensitive
    $path = strtolower($path);

    return rtrim($path, '/') . '/';
  }
}

if (!function_exists('custausu_admin_health_check_get_valid_page')) {
  function custausu_admin_health_check_get_valid_page($page_id): ?WP_Post {
    $page_id = (int) $page_id;
    if ($page_id <= 0) return null;

    $post = get_post($page_id);
    if (!$post instanceof WP_Post) return null;
    if ($post->post_type !== 'page') return null;

    return $post;
  }
}

if (!function_exists('custausu_admin_health_check_collect_protected_paths')) {
  function custausu_admin_health_check_collect_protected_paths(array $opt): array {
    $raw = (string)($opt['protected_paths'] ?? '');

    // Accept one-per-line, but also recover gracefully if the stored value
    // contains multiple paths on the same line separated by spaces/tabs/commas/semicolons.
    $tokens = preg_split('/(?:\r\n|\r|\n|[\t ,;]+)/', $raw);
    $paths = [];

    foreach ((array)$tokens as $token) {
      $p = custausu_admin_health_check_normalize_path($token);
      if ($p !== '') $paths[] = $p;
    }

    return array_values(array_unique($paths));
  }
}

if (!function_exists('custausu_admin_health_check_collect_auth_route_targets')) {
  function custausu_admin_health_check_collect_auth_route_targets(array $opt): array {
    $targets = [];

    $routes_paths = is_array($opt['routes_paths'] ?? null) ? $opt['routes_paths'] : [];
    $routes_ids   = is_array($opt['routes_page_ids'] ?? null) ? $opt['routes_page_ids'] : [];
    $langs        = custausu_admin_health_check_langs($opt);

    $route_keys = ['login','register','lostpassword','lostpassword_confirm'];

    foreach ($langs as $lng) {
      foreach ($route_keys as $route_key) {
        $page = custausu_admin_health_check_get_valid_page($routes_ids[$lng][$route_key] ?? 0);
        $path = custausu_admin_health_check_normalize_path($routes_paths[$lng][$route_key] ?? '');

        if ($page instanceof WP_Post) {
          $permalink = get_permalink((int)$page->ID);
          $page_path = custausu_admin_health_check_normalize_path($permalink);

          if ($page_path !== '') {
            $targets[] = [
              'lang'       => $lng,
              'route_key'  => $route_key,
              'route_path' => $page_path,
              'source'     => 'page',
              'page_id'    => (int)$page->ID,
            ];
          }
        }

        if ($path !== '') {
          $targets[] = [
            'lang'       => $lng,
            'route_key'  => $route_key,
            'route_path' => $path,
            'source'     => 'path',
            'page_id'    => 0,
          ];
        }
      }
    }

    $unique = [];
    foreach ($targets as $row) {
      $fingerprint = $row['lang'] . '|' . $row['route_key'] . '|' . $row['source'] . '|' . $row['route_path'];
      $unique[$fingerprint] = $row;
    }

    return array_values($unique);
  }
}

if (!function_exists('custausu_admin_health_check_detect_protected_auth_collisions')) {
  function custausu_admin_health_check_detect_protected_auth_collisions(array $opt): array {
    $protected_paths = custausu_admin_health_check_collect_protected_paths($opt);
    $route_targets   = custausu_admin_health_check_collect_auth_route_targets($opt);

    $collisions = [];

    foreach ($route_targets as $target) {
      $route_path = rtrim((string)$target['route_path'], '/');
      if ($route_path === '') continue;

      foreach ($protected_paths as $protected_path_raw) {
        $protected_path = rtrim((string)$protected_path_raw, '/');
        if ($protected_path === '') continue;

        $exact = ($route_path === $protected_path);
        $route_inside_protected = (strpos($route_path . '/', $protected_path . '/') === 0);
        $protected_inside_route = (strpos($protected_path . '/', $route_path . '/') === 0);

        if ($exact || $route_inside_protected || $protected_inside_route) {
          $fingerprint = $target['lang'] . '|' . $target['route_key'] . '|' . $target['route_path'] . '|' . $protected_path_raw;

          $collisions[$fingerprint] = [
            'lang'           => (string)$target['lang'],
            'route_key'      => (string)$target['route_key'],
            'route_path'     => (string)$target['route_path'],
            'protected_path' => (string)$protected_path_raw,
            'source'         => (string)$target['source'],
            'page_id'        => (int)($target['page_id'] ?? 0),
          ];
        }
      }
    }

    return array_values($collisions);
  }
}

if (!function_exists('custausu_admin_health_check_route_label')) {
  function custausu_admin_health_check_route_label(string $key, callable $T): string {
    return match ($key) {
      'login'                => $T('Login route', 'Route login'),
      'register'             => $T('Register route', 'Route registrazione'),
      'lostpassword'         => $T('Lost password route', 'Route recupero password'),
      'lostpassword_confirm' => $T('Reset confirm route', 'Route conferma reset password'),
      'landing'              => $T('Landing route', 'Route landing'),
      default                => $key,
    };
  }
}

if (!function_exists('custausu_admin_health_check_routes_checks')) {
  function custausu_admin_health_check_routes_checks(callable $T, array $opt): array {
    $checks = [];

    $routes_paths_raw = is_array($opt['routes_paths'] ?? null) ? $opt['routes_paths'] : [];
    $routes_ids_raw   = is_array($opt['routes_page_ids'] ?? null) ? $opt['routes_page_ids'] : [];
    $langs            = custausu_admin_health_check_langs($opt);

    /**
     * Normalize option arrays to string-keyed maps so static analyzers do not
     * treat them as numeric lists.
     *
     * @var array<string, array<string, mixed>> $routes_paths
     * @var array<string, array<string, mixed>> $routes_ids
     */
    $routes_paths = [];
    foreach ($routes_paths_raw as $lang_key => $lang_routes) {
      $lang_key = sanitize_key((string) $lang_key);

      if ($lang_key !== '' && is_array($lang_routes)) {
        $routes_paths[$lang_key] = $lang_routes;
      }
    }

    $routes_ids = [];
    foreach ($routes_ids_raw as $lang_key => $lang_routes) {
      $lang_key = sanitize_key((string) $lang_key);

      if ($lang_key !== '' && is_array($lang_routes)) {
        $routes_ids[$lang_key] = $lang_routes;
      }
    }

    $route_keys = ['login', 'register', 'lostpassword', 'lostpassword_confirm'];

    /**
     * @var array<string, array<int, array<string, mixed>>> $collision_map
     */
    $collision_map = [];

    foreach (custausu_admin_health_check_detect_protected_auth_collisions($opt) as $row) {
      if (!is_array($row)) {
        continue;
      }

      $row_lang = sanitize_key((string)($row['lang'] ?? ''));
      $row_route_key = sanitize_key((string)($row['route_key'] ?? ''));

      if ($row_lang === '' || $row_route_key === '') {
        continue;
      }

      $map_key = $row_lang . '|' . $row_route_key;

      if (!isset($collision_map[$map_key])) {
        $collision_map[$map_key] = [];
      }

      $collision_map[$map_key][] = $row;
    }

    foreach ($langs as $lng_raw) {
      $lng = sanitize_key((string) $lng_raw);

      if ($lng === '') {
        continue;
      }

      $lng_routes_ids = isset($routes_ids[$lng]) && is_array($routes_ids[$lng])
        ? $routes_ids[$lng]
        : [];

      $lng_routes_paths = isset($routes_paths[$lng]) && is_array($routes_paths[$lng])
        ? $routes_paths[$lng]
        : [];

      foreach ($route_keys as $route_key_raw) {
        $route_key = sanitize_key((string) $route_key_raw);

        if ($route_key === '') {
          continue;
        }

        $pid_raw  = $lng_routes_ids[$route_key] ?? 0;
        $path_raw = $lng_routes_paths[$route_key] ?? '';

        $page = custausu_admin_health_check_get_valid_page($pid_raw);
        $path = custausu_admin_health_check_normalize_path($path_raw);

        $has_page = ($page instanceof WP_Post);
        $has_path = ($path !== '');

        $ok  = ($has_page || $has_path);
        $sev = $ok ? 'ok' : 'err';

        if ($has_page && $has_path) {
          $value = sprintf(
            $T('Page #%1$d + path %2$s', 'Pagina #%1$d + path %2$s'),
            (int) $page->ID,
            $path
          );

          $hint = $T(
            'Configured via both page and path. This is valid and useful for dynamic/theme-driven routes.',
            'Configurato sia via pagina che via path. È valido ed è utile per route dinamiche/generate dal tema.'
          );

          $reason = 'page_and_path';
        } elseif ($has_page) {
          $value = sprintf($T('Page #%d', 'Pagina #%d'), (int) $page->ID);

          $hint = $T(
            'Configured via selected WordPress page.',
            'Configurato tramite pagina WordPress selezionata.'
          );

          $reason = 'page_selected';
        } elseif ($has_path) {
          $value = $path;

          $hint = $T(
            'Configured via path. Useful for dynamic/theme-generated pages.',
            'Configurato tramite path. Utile per pagine dinamiche/generate dal tema.'
          );

          $reason = 'path_set';
        } else {
          $value = $T('Missing', 'Mancante');

          $hint = $T(
            'Set either a WordPress page OR a path for this route.',
            'Imposta per questa route una pagina WordPress OPPURE un path.'
          );

          $reason = 'missing_page_or_path';
        }

        $map_key = $lng . '|' . $route_key;
        $route_collisions = $collision_map[$map_key] ?? [];

        if (!empty($route_collisions)) {
          $sev = 'err';
          $ok = false;
          $reason = 'auth_route_collision';

          $examples = [];

          foreach ($route_collisions as $collision) {
            if (!is_array($collision)) {
              continue;
            }

            $protected_path = (string)($collision['protected_path'] ?? '');

            if ($protected_path !== '') {
              $examples[] = $protected_path;
            }
          }

          $examples = array_values(array_unique($examples));

          $hint = sprintf(
            $T(
              'This auth route collides with Protected Paths: %s.',
              'Questa route auth collide con i Percorsi Protetti: %s.'
            ),
            implode(', ', $examples)
          );
        }

        $checks[] = [
          'group'  => 'routes',
          'key'    => 'route_' . $lng . '_' . $route_key,
          'ok'     => $ok,
          'sev'    => $sev,
          'reason' => $reason,
          'label'  => strtoupper($lng) . ' — ' . custausu_admin_health_check_route_label($route_key, $T),
          'value'  => $value,
          'hint'   => $hint,
        ];
      }
    }

    return $checks;
  }
}

if (!function_exists('custausu_admin_health_check_protected_paths_checks')) {
  function custausu_admin_health_check_protected_paths_checks(callable $T, array $opt): array {
    $checks = [];

    $paths = custausu_admin_health_check_collect_protected_paths($opt);
    $count = count($paths);

    $checks[] = [
      'group'  => 'protected_paths',
      'key'    => 'protected_paths_count',
      'ok'     => ($count > 0),
      'sev'    => ($count > 0) ? 'ok' : 'warn',
      'reason' => ($count > 0) ? 'ok' : 'no_protected_paths',
      'label'  => $T('Protected paths', 'Percorsi protetti'),
      'value'  => ($count > 0)
        ? sprintf($T('%d configured', '%d configurati'), $count)
        : $T('None configured', 'Nessuno configurato'),
      'hint'   => ($count > 0)
        ? $T('Protected paths are configured.', 'I percorsi protetti sono configurati.')
        : $T('No protected path is configured yet.', 'Nessun percorso protetto è ancora configurato.'),
    ];

    $collisions = custausu_admin_health_check_detect_protected_auth_collisions($opt);

    $collision_values = [];
    foreach ($collisions as $row) {
      $collision_values[] =
        (string)$row['protected_path'] .
        ' ↔ ' .
        strtoupper((string)$row['lang']) . ' ' .
        custausu_admin_health_check_route_label((string)$row['route_key'], $T);
    }

    $collision_values = array_values(array_unique($collision_values));

    $checks[] = [
      'group'  => 'protected_paths',
      'key'    => 'protected_paths_collision',
      'ok'     => empty($collisions),
      'sev'    => empty($collisions) ? 'ok' : 'err',
      'reason' => empty($collisions) ? 'ok' : 'auth_route_collision',
      'label'  => $T('Protected/auth path collisions', 'Collisioni tra percorsi protetti e auth'),
      'value'  => empty($collision_values)
        ? $T('None', 'Nessuna')
        : implode(', ', $collision_values),
      'hint'   => empty($collisions)
        ? $T('No collision detected with auth routes.', 'Nessuna collisione rilevata con le route auth.')
        : $T('One or more protected paths collide with CAS auth routes. Review the configuration.', 'Uno o più percorsi protetti collidono con route auth CAS. Controlla la configurazione.'),
    ];

    return $checks;
  }
}


if (!function_exists('custausu_admin_health_check_auth_route_consistency_checks')) {
  function custausu_admin_health_check_auth_route_consistency_checks(callable $T, array $opt = []): array {
    if (!function_exists('custausu_auth_page_route_consistency_issues')) {
      return [];
    }

    $issues = custausu_auth_page_route_consistency_issues($opt);

    if (empty($issues)) {
      return [[
        'group'  => 'auth',
        'key'    => 'custausu_auth_route_consistency',
        'ok'     => true,
        'sev'    => 'ok',
        'reason' => 'ok',
        'label'  => $T('CAS auth route consistency', 'Coerenza route Auth CAS'),
        'value'  => $T('OK', 'OK'),
        'hint'   => $T(
          'Selected Auth pages match the saved route paths.',
          'Le pagine Auth selezionate coincidono con i percorsi route salvati.'
        ),
      ]];
    }

    $checks = [];

    foreach ($issues as $issue) {
      $reason = (string)($issue['reason'] ?? '');
      $route  = (string)($issue['route'] ?? '');
      $lang   = (string)($issue['lang'] ?? '');
      $page_id = absint($issue['page_id'] ?? 0);

      $stored  = (string)($issue['stored_path'] ?? '');
      $current = (string)($issue['current_path'] ?? '');

      if ($reason === 'auth_route_stale_path') {
        $value = trim($stored . ' → ' . $current);
        $hint = sprintf(
          $T(
            'The selected Auth page #%d changed URL/slug. Update Routes & Templates or run the Auth pages tool again.',
            'La pagina Auth selezionata #%d ha cambiato URL/slug. Aggiorna Percorsi e Template oppure esegui di nuovo lo strumento pagine Auth.'
          ),
          $page_id
        );
      } elseif ($reason === 'auth_route_template_mismatch') {
        $value = (string)($issue['template'] ?? '') . ' ≠ ' . (string)($issue['expected'] ?? '');
        $hint = sprintf(
          $T(
            'The selected Auth page #%d does not use the expected CAS template.',
            'La pagina Auth selezionata #%d non usa il template CAS previsto.'
          ),
          $page_id
        );
      } else {
        $value = $stored !== '' ? $stored : ('#' . $page_id);
        $hint = sprintf(
          $T(
            'The selected Auth page #%d no longer exists or is not available.',
            'La pagina Auth selezionata #%d non esiste più o non è disponibile.'
          ),
          $page_id
        );
      }

      $checks[] = [
        'group'  => 'auth',
        'key'    => 'custausu_auth_route_consistency_' . sanitize_key($lang . '_' . $route . '_' . $reason),
        'ok'     => false,
        'sev'    => 'err',
        'reason' => $reason,
        'label'  => sprintf(
          $T('Auth route changed: %s (%s)', 'Route Auth modificata: %s (%s)'),
          $route,
          strtoupper($lang)
        ),
        'value'  => $value,
        'hint'   => $hint,
      ];
    }

    return $checks;
  }
}


if (!function_exists('custausu_admin_health_check_tables_checks')) {
  function custausu_admin_health_check_tables_checks(callable $T): array {
    global $wpdb;

    $tables = function_exists('custausu_db_expected_tables')
      ? array_values((array) custausu_db_expected_tables())
      : [
        $wpdb->prefix . 'cas_email_verifications',
      ];

    $missing = [];

    foreach ($tables as $table) {
      $found = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table));

      if ($found !== $table) {
        $missing[] = $table;
      }
    }

    return [[
      'group'  => 'database',
      'key'    => 'custausu_custom_tables',
      'ok'     => empty($missing),
      'sev'    => empty($missing) ? 'ok' : 'err',
      'reason' => empty($missing) ? 'ok' : 'missing_custom_tables',
      'label'  => $T('CAS custom tables', 'Tabelle custom CAS'),
      'value'  => empty($missing)
        ? $T('All present', 'Tutte presenti')
        : $T('Missing tables', 'Tabelle mancanti'),
      'hint'   => empty($missing)
        ? $T('All required CAS SQL tables are present.', 'Tutte le tabelle SQL CAS richieste sono presenti.')
        : implode(', ', $missing),
    ]];
  }
}

if (!function_exists('custausu_admin_health_check_plan_label')) {
  function custausu_admin_health_check_plan_label(string $plan, callable $T): string {
    if (function_exists('custausu_free_package_sanitize_plan')) {
      $plan = custausu_free_package_sanitize_plan($plan, true);
    } else {
      $plan = sanitize_key((string)$plan);
      if ($plan === 'base') {
        $plan = 'advanced';
      }
    }

    return match ($plan) {
      'freemium' => $T('Free', 'Free'),
      'advanced' => $T('Advanced', 'Advanced'),
      'premium'  => $T('Premium', 'Premium'),
      default    => $plan !== '' ? ucfirst($plan) : $T('Unknown', 'Sconosciuto'),
    };
  }
}

if (!function_exists('custausu_admin_health_check_installed_package_checks')) {
  function custausu_admin_health_check_installed_package_checks(callable $T): array {
    return [[
      'group' => 'package',
      'key' => 'installed_package',
      'ok' => true,
      'sev' => 'info',
      'reason' => 'public_free_package',
      'label' => $T('Installed CAS package', 'Pacchetto CAS installato'),
      'value' => $T('Free', 'Free'),
      'hint' => $T(
        'This WordPress.org ZIP contains the Free implementation only.',
        'Questo ZIP WordPress.org contiene soltanto l’implementazione Free.'
      ),
    ]];
  }
}

if (!function_exists('custausu_admin_health_check_package_preview_checks')) {
  function custausu_admin_health_check_package_preview_checks(callable $T): array {
    $rows = [
      ['key' => 'preview_polylang_i18n', 'label' => 'Polylang / i18n', 'package' => 'Advanced'],
      ['key' => 'preview_assets_customization', 'label' => 'Assets customization', 'package' => 'Advanced'],
      ['key' => 'preview_recaptcha_enterprise', 'label' => 'reCAPTCHA Enterprise', 'package' => 'Advanced'],
      ['key' => 'preview_cf7_mathcheck', 'label' => 'CF7 Math Check', 'package' => 'Advanced'],
      ['key' => 'preview_settings_export_import', 'label' => 'Settings export/import', 'package' => 'Advanced'],
      ['key' => 'preview_advanced_debug_tools', 'label' => 'Advanced debug tools', 'package' => 'Premium'],
      ['key' => 'preview_logs_export_tools', 'label' => 'Log export tools', 'package' => 'Premium'],
      ['key' => 'preview_webauthn_passkeys', 'label' => 'WebAuthn / Passkeys', 'package' => 'Premium'],
    ];
    $checks = [];
    foreach ($rows as $row) {
      $checks[] = [
        'group' => 'package_previews',
        'key' => (string)$row['key'],
        'ok' => false,
        'sev' => 'preview',
        'reason' => 'separate_package_required',
        'label' => (string)$row['label'],
        'value' => $T('Informational preview', 'Anteprima informativa'),
        'hint' => sprintf(
          $T(
            'The implementation is available in the separately distributed %s package.',
            'L’implementazione è disponibile nel pacchetto %s distribuito separatamente.'
          ),
          (string)$row['package']
        ),
      ];
    }
    return $checks;
  }
}

if (!function_exists('custausu_admin_health_check_rest_root_urls_from_pretty')) {
  function custausu_admin_health_check_rest_root_urls_from_pretty(string $pretty_url): array {
    $pretty_url = trim($pretty_url);
    if ($pretty_url === '') {
      return [
        'pretty_root'   => '',
        'fallback_root' => '',
      ];
    }

    $parts = wp_parse_url($pretty_url);
    if (!is_array($parts)) {
      return [
        'pretty_root'   => '',
        'fallback_root' => '',
      ];
    }

    $scheme = strtolower((string)($parts['scheme'] ?? ''));
    $host   = strtolower((string)($parts['host'] ?? ''));
    $port   = isset($parts['port']) ? (int) $parts['port'] : 0;
    $path   = '/' . ltrim((string)($parts['path'] ?? ''), '/');

    if ($scheme === '' || $host === '' || $path === '') {
      return [
        'pretty_root'   => '',
        'fallback_root' => '',
      ];
    }

    $needle = '/wp-json/';
    $pos = stripos($path, $needle);

    if ($pos === false) {
      return [
        'pretty_root'   => '',
        'fallback_root' => '',
      ];
    }

    $before_wp_json = substr($path, 0, $pos);

    $origin = $scheme . '://' . $host;
    if ($port > 0) {
      $origin .= ':' . $port;
    }

    $site_root = rtrim($origin . '/' . trim($before_wp_json, '/'), '/');

    return [
      'pretty_root'   => $site_root . '/wp-json/',
      'fallback_root' => $site_root . '/?rest_route=/',
    ];
  }
}

if (!function_exists('custausu_admin_health_check_run')) {
  function custausu_admin_health_check_run(callable $T): array {
    global $wp_version;

    $checks = [];
    $opt = get_option('custausu_global_settings', []);
    $opt = is_array($opt) ? $opt : [];

    // PHP
    $php_ok = custausu_admin_min_php_ok();
    $checks[] = [
      'group'  => 'environment',
      'key'    => 'php',
      'ok'     => $php_ok,
      'sev'    => $php_ok ? 'ok' : 'err',
      'reason' => $php_ok ? 'ok' : 'php_too_old',
      'label'  => $T('PHP', 'PHP'),
      'value'  => PHP_VERSION,
      'hint'   => $php_ok ? '' : $T('Minimum required: PHP 8.1+ (recommended 8.4+).', 'Minimo richiesto: PHP 8.1+ (consigliato 8.4+).'),
    ];

    // WordPress
    $wp_ok = version_compare((string)$wp_version, '6.0', '>=');
    $checks[] = [
      'group'  => 'environment',
      'key'    => 'wp',
      'ok'     => $wp_ok,
      'sev'    => $wp_ok ? 'ok' : 'warn',
      'reason' => $wp_ok ? 'ok' : 'wp_outdated',
      'label'  => $T('WordPress', 'WordPress'),
      'value'  => (string)$wp_version,
      'hint'   => $wp_ok ? '' : $T('Please update WordPress (recommended 6.x+).', 'Aggiorna WordPress (consigliato 6.x+).'),
    ];

    // Logs directory (read-only health observation).
    // Do not create the directory merely by opening Settings/Doctor/Health.
    // The real filesystem logger creates it only when file logging is used.
    $dir = custausu_admin_logs_dir();
    $logs_exists = file_exists($dir);
    $logs_is_dir = is_dir($dir);
    $writable = $logs_is_dir && wp_is_writable($dir);

    if (!$logs_exists) {
      $logs_ok = true;
      $logs_sev = 'info';
      $logs_reason = 'logs_not_initialized';
      $logs_hint = $T(
        'The filesystem logs folder has not been initialized yet. It is created automatically only when file logging is used.',
        'La cartella dei log su filesystem non è ancora stata inizializzata. Viene creata automaticamente solo quando viene usato il logging su file.'
      );
    } elseif (!$logs_is_dir) {
      $logs_ok = false;
      $logs_sev = 'err';
      $logs_reason = 'logs_path_not_directory';
      $logs_hint = $T(
        'The expected logs path exists but is not a directory. Please check the filesystem.',
        'Il percorso previsto per i log esiste ma non è una directory. Verifica il filesystem.'
      );
    } elseif (!$writable) {
      $logs_ok = false;
      $logs_sev = 'err';
      $logs_reason = 'logs_not_writable';
      $logs_hint = $T(
        'Logs folder is not writable. Please check filesystem permissions.',
        'La cartella log non è scrivibile. Verifica i permessi del filesystem.'
      );
    } else {
      $logs_ok = true;
      $logs_sev = 'ok';
      $logs_reason = 'ok';
      $logs_hint = '';
    }

    $checks[] = [
      'group'  => 'environment',
      'key'    => 'logs',
      'ok'     => $logs_ok,
      'sev'    => $logs_sev,
      'reason' => $logs_reason,
      'label'  => $T('Logs folder', 'Cartella log'),
      'value'  => 'wp-content/uploads/custom-auth-suite/logs/',
      'hint'   => $logs_hint,
    ];

    // CAS tables
    if (function_exists('custausu_admin_health_check_auth_route_consistency_checks')) {
      $checks = array_merge($checks, custausu_admin_health_check_auth_route_consistency_checks($T, $opt));
    }

    $checks = array_merge($checks, custausu_admin_health_check_tables_checks($T));


    // Contact Form 7 / Math Check - Advanced preview.
    $checks[] = [
      'group'  => 'integrations',
      'key'    => 'cf7',
      'ok'     => false,
      'sev'    => 'preview',
      'reason' => 'preview_by_plan',
      'label'  => $T('Contact Form 7 + Math Check', 'Contact Form 7 + Math Check'),
      'value'  => $T('Plan feature', 'Funzione piano'),
      'hint'   => $T('Available with Advanced.', 'Disponibile con Advanced.'),
    ];

    // reCAPTCHA Enterprise - Advanced preview.
    $checks[] = [
      'group'  => 'integrations',
      'key'    => 'recaptcha',
      'ok'     => false,
      'sev'    => 'preview',
      'reason' => 'preview_by_plan',
      'label'  => $T('reCAPTCHA Enterprise', 'reCAPTCHA Enterprise'),
      'value'  => $T('Plan feature', 'Funzione piano'),
      'hint'   => $T('Available with Advanced.', 'Disponibile con Advanced.'),
    ];
    // Fixed public-package identity and local informational previews.
    $checks = array_merge($checks, custausu_admin_health_check_installed_package_checks($T));
    $checks = array_merge($checks, custausu_admin_health_check_package_preview_checks($T));

    // Route checks (page OR path)
    $checks = array_merge($checks, custausu_admin_health_check_routes_checks($T, $opt));

    // Protected paths
    $checks = array_merge($checks, custausu_admin_health_check_protected_paths_checks($T, $opt));

    return $checks;
  }
}

if (!function_exists('custausu_admin_health_check_html')) {
  function custausu_admin_health_check_html(callable $T): string {
    $checks = custausu_admin_health_check_run($T);

    $title    = esc_html($T('Health Check', 'Controllo stato'));
    $desc     = esc_html($T('Checks environment and configuration.', 'Controlla ambiente e configurazione.'));
    $run_lbl  = esc_html($T('Run check', 'Esegui controllo'));

    $counts = [
      'ok'     => 0,
      'warn'   => 0,
      'err'    => 0,
      'info'   => 0,
      'preview' => 0,
    ];

    foreach ((array)$checks as $c) {
      $sev = strtolower(trim((string)($c['sev'] ?? '')));
      if (isset($counts[$sev])) {
        $counts[$sev]++;
      }
    }

    ob_start();

    echo '<details id="custausu-section-health-check" class="custausu-health-card custausu-module-card custausu-module-card--health" data-health="1">';
    echo '<summary class="custausu-module-card__head custausu-health-card__summary">';

    echo '<div class="custausu-module-card__main">';

    if (function_exists('custausu_admin_module_icon_html')) {
      echo wp_kses( custausu_admin_module_icon_html('custausu-health-check-icon.png', 'custausu-module-card__icon--health'), custausu_admin_allowed_output_html() );
    } else {
      echo '<span class="custausu-module-card__icon custausu-module-card__icon--fallback" aria-hidden="true"><span class="dashicons dashicons-heart"></span></span>';
    }

    echo '<span class="custausu-module-card__text">';
    echo '<span class="custausu-module-card__title">' . esc_html($title) . '</span>';
    echo '<span class="custausu-module-card__desc">' . esc_html($desc) . '</span>';
    echo '</span>';

    echo '</div>';

    echo '<div class="custausu-module-card__side custausu-health-card__side">';
    echo '<span class="custausu-badge custausu-badge--ok">OK: ' . (int)$counts['ok'] . '</span>';
    echo '<span class="custausu-badge custausu-badge--info">Info: ' . (int)$counts['info'] . '</span>';

    if ((int)$counts['warn'] > 0) {
      echo '<span class="custausu-badge custausu-badge--warn">Warning: ' . (int)$counts['warn'] . '</span>';
    }

    if ((int)$counts['err'] > 0) {
      echo '<span class="custausu-badge custausu-badge--error">Error: ' . (int)$counts['err'] . '</span>';
    }

    echo '<button type="button" class="button button-primary custausu-module-card__button custausu-health-run-btn" id="custausu-health-run" data-custausu-health-run="1">' . esc_html($run_lbl) . '</button>';
    echo '<span class="custausu-module-card__chevron" aria-hidden="true">›</span>';
    echo '</div>';

    echo '</summary>';

    echo '<div class="custausu-health-card__body">';
    echo '<div class="custausu-health-box">';
    echo '<div class="custausu-table-wrap">';
    echo '<table class="widefat striped custausu-health-table">';
    echo '<thead><tr>';
    echo '<th class="custausu-health-status-col">'.esc_html($T('Status', 'Stato')).'</th>';
    echo '<th>'.esc_html($T('Check', 'Controllo')).'</th>';
    echo '<th>'.esc_html($T('Value', 'Valore')).'</th>';
    echo '<th>'.esc_html($T('Notes', 'Note')).'</th>';
    echo '</tr></thead>';
    echo '<tbody>';

    foreach ((array)$checks as $c) {
      $sev = isset($c['sev']) ? strtolower(trim((string)$c['sev'])) : 'err';
      if (!in_array($sev, ['ok','warn','err','info','preview'], true)) {
        $sev = !empty($c['ok']) ? 'ok' : 'err';
      }

      $label = isset($c['label']) ? (string)$c['label'] : '';
      $value = isset($c['value']) ? (string)$c['value'] : '';
      $hint  = isset($c['hint'])  ? (string)$c['hint']  : '';

      echo '<tr class="custausu-hc-row custausu-hc-'.esc_attr($sev).'">';
      echo '<td class="custausu-hc-status"><span class="custausu-hc-dot" aria-hidden="true"></span></td>';
      echo '<td>'.esc_html($label).'</td>';
      echo '<td><span class="custausu-health-val">'.esc_html($value).'</span></td>';
      echo '<td>'.esc_html($hint).'</td>';
      echo '</tr>';
    }

    echo '</tbody></table>';
    echo '</div>';
    echo '</div>';
    echo '</div>';
    echo '</div>';
    echo '</details>';

    return (string) ob_get_clean();
  }
}

// Top panel rendering is owned by inc/admin/wizard.php.
// This file only provides health-check data + health-check HTML.

if (!function_exists('custausu_admin_ajax_health_check')) {
  function custausu_admin_ajax_health_check(): void {
    if (!current_user_can('manage_options')) wp_send_json_error('forbidden', 403);
    check_ajax_referer('custausu_health_check', 'nonce');

    $T = function_exists('custausu_admin_t')
      ? 'custausu_admin_t'
      : static function(string $en, string $it = ''): string {
        return $en;
      };

    $html = custausu_admin_health_check_html($T);
    wp_send_json_success(['html' => $html]);
  }
}
