<?php
/**
 * User-facing error message helpers.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Support;

/**
 * Records internal exception detail while returning stable public copy.
 */
final class PublicErrorMessages {
	/**
	 * Returns a stable public message after emitting protected diagnostic detail.
	 *
	 * @param string               $code Error code.
	 * @param string               $message Public message.
	 * @param \Throwable           $throwable Internal failure.
	 * @param array<string, mixed> $context Non-sensitive context.
	 */
	public static function message( string $code, string $message, \Throwable $throwable, array $context = array() ): string {
		self::record( $code, $throwable, $context );

		return $message;
	}

	/**
	 * Returns a stable AJAX payload after emitting protected diagnostic detail.
	 *
	 * @param string               $code Error code.
	 * @param string               $message Public message.
	 * @param \Throwable           $throwable Internal failure.
	 * @param array<string, mixed> $context Non-sensitive context.
	 * @return array<string,string>
	 */
	public static function ajaxPayload( string $code, string $message, \Throwable $throwable, array $context = array() ): array {
		self::record( $code, $throwable, $context );

		return array(
			'code'    => $code,
			'message' => $message,
		);
	}

	/**
	 * Emits internal failure detail for protected diagnostics.
	 *
	 * @param string               $code Error code.
	 * @param \Throwable           $throwable Internal failure.
	 * @param array<string, mixed> $context Non-sensitive context.
	 */
	private static function record( string $code, \Throwable $throwable, array $context ): void {
		$detail = array(
			'message' => $throwable->getMessage(),
			'class'   => get_class( $throwable ),
			'line'    => $throwable->getLine(),
			'context' => $context,
		);

		if ( self::debugLogEnabled() ) {
			$encoded = wp_json_encode(
				array(
					'code'   => $code,
					'detail' => $detail,
				),
				JSON_UNESCAPED_SLASHES
			);

			error_log( 'scheduled_changes_public_error_detail ' . ( is_string( $encoded ) ? $encoded : $code ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug-log fallback is gated by WP_DEBUG_LOG.
		}

		do_action(
			'scheduled_changes_public_error_detail',
			$code,
			$detail,
			$throwable
		);
	}

	/**
	 * Returns whether WordPress debug logging is explicitly enabled.
	 */
	private static function debugLogEnabled(): bool {
		if ( ! defined( 'WP_DEBUG_LOG' ) ) {
			return false;
		}

		$value = constant( 'WP_DEBUG_LOG' );

		return false !== $value && '' !== $value && '0' !== $value;
	}
}
