<?php
/**
 * Shared logging component - boot config facade.
 *
 * The one seam between the logger/Log-UI and the consuming plugin. A consumer
 * boots it once (early, before anything logs) and everything else derives:
 *
 *   SSAA_Log::boot( array(
 *     'slug'             => 'dynamic-og-image-generator', // REQUIRED - drives the
 *                                                          // log path (uploads/<slug>/<slug>.log,
 *                                                          // the cross-plugin standard) and the
 *                                                          // download filename
 *     'prefix'           => 'doig',                        // REQUIRED - hook/action names
 *     'log_level_getter' => callable,                      // returns off|error|warning|info|debug
 *                                                          // (the plugin's live setting)
 *     'option_key'       => 'doig_settings',               // settings option holding log_level
 *                                                          // (the Log UI's save target)
 *     'settings_slug'    => 'doig-settings',               // settings page slug (redirect target;
 *                                                          // the Logs tab lives at &tab=logs)
 *     'redact_patterns'  => array(                         // optional: regex => replacement,
 *       '/([?&]access_key=)[^&\s"]+/' => '$1[redacted]',   // applied to every string context
 *     ),                                                   // value before writing
 *   ) );
 *
 * Extracted from the shared render engine (2026-07-05) so plugins that do NOT
 * use the engine still get the identical logger + Logs tab. The engine itself
 * becomes a consumer of this component (planned engine 0.1.7).
 *
 * CANONICAL SOURCE - do not edit the vendored copy in a plugin's includes/.
 * Edit here in _shared/shared-logging/src/ and re-run sync.sh, which rewrites
 * the class prefix and the text domain (search-social-appearance-audit) per consumer.
 *
 * @package search-social-appearance-audit
 */

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

class SSAA_Log {

	/** @var array Boot config. */
	private static $config = array();

	/** @var bool */
	private static $booted = false;

	/**
	 * Boot the logging component. Idempotent; call early (plugins_loaded or
	 * plain require-time) so cron/REST/front-end paths can log too.
	 *
	 * @param array $config See the class docblock for keys.
	 */
	public static function boot( array $config ) {
		if ( self::$booted ) {
			return;
		}
		self::$config = $config;

		// The Logs tab actions (save level / clear / download) are admin-only.
		if ( is_admin() ) {
			SSAA_Log_UI::init();
		}

		self::$booted = true;
	}

	/**
	 * Read a boot config value.
	 *
	 * @param string|null $key     Config key, or null for the whole array.
	 * @param mixed       $default Fallback when the key is absent.
	 * @return mixed
	 */
	public static function config( $key = null, $default = null ) {
		if ( null === $key ) {
			return self::$config;
		}
		return array_key_exists( $key, self::$config ) ? self::$config[ $key ] : $default;
	}

	/**
	 * Lower-case consumer prefix (e.g. 'doig').
	 *
	 * @return string
	 */
	public static function prefix() {
		return strtolower( (string) self::config( 'prefix', 'log' ) );
	}

	/**
	 * Sanitised consumer slug - the log path + download filename standard
	 * derives from this (uploads/<slug>/<slug>.log).
	 *
	 * @return string
	 */
	public static function slug() {
		$slug = strtolower( (string) self::config( 'slug', 'search-social-appearance-audit' ) );
		$slug = trim( preg_replace( '/[^a-z0-9_-]/', '', $slug ), '-_' );
		return '' === $slug ? 'search-social-appearance-audit' : $slug;
	}

	/**
	 * Build a prefixed runtime name for an option / hook / action.
	 * E.g. key('clear_log') => 'doig_clear_log'.
	 *
	 * @param string $suffix Unprefixed suffix.
	 * @return string
	 */
	public static function key( $suffix ) {
		return self::prefix() . '_' . ltrim( (string) $suffix, '_' );
	}
}
