<?php
/**
 * Capture passive des dépréciations WordPress en runtime (sans WP_DEBUG).
 *
 * @package PCC
 * @license GPL-2.0-or-later
 */

defined( 'ABSPATH' ) || exit;

class PCC_Runtime_Monitor {

	const OPTION_KEY = 'pcc_runtime_log';
	const MAX_ENTRIES = 100;

	/** @var PCC_Plugin */
	private $plugin;

	public function __construct( PCC_Plugin $plugin ) {
		$this->plugin = $plugin;

		add_action( 'deprecated_function_run', array( $this, 'on_deprecated_function' ), 10, 3 );
		add_action( 'deprecated_argument_run', array( $this, 'on_deprecated_argument' ), 10, 3 );
		add_action( 'deprecated_hook_run', array( $this, 'on_deprecated_hook' ), 10, 4 );
		add_action( 'doing_it_wrong_run', array( $this, 'on_doing_it_wrong' ), 10, 3 );
	}

	public function is_enabled() {
		return ! empty( $this->plugin->settings->get( 'runtime_monitor', true ) );
	}

	/**
	 * @return array<int, array<string, mixed>>
	 */
	public function get_log() {
		$log = get_option( self::OPTION_KEY, array() );
		return is_array( $log ) ? $log : array();
	}

	public function clear_log() {
		delete_option( self::OPTION_KEY );
	}

	/**
	 * @param array<string, mixed> $entry
	 */
	private function append( array $entry ) {
		if ( ! $this->is_enabled() ) {
			return;
		}
		$log = $this->get_log();
		$entry['time'] = gmdate( 'c' );
		$entry['source'] = $this->guess_source();
		array_unshift( $log, $entry );
		if ( count( $log ) > self::MAX_ENTRIES ) {
			$log = array_slice( $log, 0, self::MAX_ENTRIES );
		}
		update_option( self::OPTION_KEY, $log, false );
	}

	public function on_deprecated_function( $function, $replacement, $version ) {
		$this->append(
			array(
				'type'        => 'deprecated_function',
				'function'    => (string) $function,
				'replacement' => (string) $replacement,
				'version'     => (string) $version,
			)
		);
	}

	public function on_deprecated_argument( $function, $message, $version ) {
		$this->append(
			array(
				'type'     => 'deprecated_argument',
				'function' => (string) $function,
				'message'  => (string) $message,
				'version'  => (string) $version,
			)
		);
	}

	public function on_deprecated_hook( $hook, $replacement, $version, $message ) {
		unset( $message );
		$this->append(
			array(
				'type'        => 'deprecated_hook',
				'hook'        => (string) $hook,
				'replacement' => (string) $replacement,
				'version'     => (string) $version,
			)
		);
	}

	public function on_doing_it_wrong( $function, $message, $version ) {
		// Bruit WordPress 6.7+ — chargement traductions JIT, sans impact compatibilité PHP.
		if ( '_load_textdomain_just_in_time' === $function ) {
			return;
		}

		$this->append(
			array(
				'type'     => 'doing_it_wrong',
				'function' => (string) $function,
				'message'  => wp_strip_all_tags( (string) $message ),
				'version'  => (string) $version,
			)
		);
	}

	/**
	 * @return string
	 */
	private function guess_source() {
		$trace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 12 ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace
		foreach ( $trace as $frame ) {
			$file = $frame['file'] ?? '';
			if ( ! $file ) {
				continue;
			}
			$file = wp_normalize_path( $file );
			$plugin_dir = wp_normalize_path( WP_PLUGIN_DIR );
			if ( 0 === strpos( $file, $plugin_dir ) ) {
				$rel  = ltrim( substr( $file, strlen( $plugin_dir ) ), '/' );
				$slug = strtok( $rel, '/' );
				return 'plugin:' . ( $slug ?: 'unknown' );
			}
			$mu_dir = wp_normalize_path( WP_CONTENT_DIR . '/mu-plugins' );
			if ( 0 === strpos( $file, $mu_dir ) ) {
				return 'mu-plugin:' . basename( $file, '.php' );
			}
			$stylesheet_dir = wp_normalize_path( get_stylesheet_directory() );
			if ( 0 === strpos( $file, $stylesheet_dir ) ) {
				return 'theme:' . get_stylesheet();
			}
			$template_dir = wp_normalize_path( get_template_directory() );
			if ( 0 === strpos( $file, $template_dir ) ) {
				return 'theme:' . get_template();
			}
		}
		return 'core';
	}

	/**
	 * @return array{count:int,by_source:array<string,int>}
	 */
	public function summary() {
		$log  = $this->get_log();
		$by   = array();
		foreach ( $log as $row ) {
			$src = $row['source'] ?? 'unknown';
			$by[ $src ] = ( $by[ $src ] ?? 0 ) + 1;
		}
		return array(
			'count'     => count( $log ),
			'by_source' => $by,
		);
	}
}
