
<center><h2><strong>Ubuntu</strong></h2>
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
<!DOCTYPE html>
<html>
<?php
/**
 * @package ACF
 * @author  WP Engine
 *
 * © 2026 Advanced Custom Fields (ACF®). All rights reserved.
 * "ACF" is a trademark of WP Engine.
 * Licensed under the GNU General Public License v2 or later.
 * https://www.gnu.org/licenses/gpl-2.0.html
 */

namespace ACF\Site_Health;

use WP_Error;
use WP_REST_Request;

// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;

/**
 * AI Usage
 *
 * Logs information about ACF AI/Abilities usage for the ACF Site Health report.
 * Measures opt-in, potential (AI-ready objects), discovery (browsing), and utility (execution).
 */
class AI_Usage {

	/**
	 * An instance of the ACF Site_Health class.
	 *
	 * @var Site_Health
	 */
	private Site_Health $site_health;

	/**
	 * Constructs the class.
	 *
	 * @since 6.8.0
	 *
	 * @param Site_Health $site_health An instance of Site_Health.
	 * @return void
	 */
	public function __construct( Site_Health $site_health ) {
		$this->site_health = $site_health;

		add_action( 'init', array( $this, 'init' ) );
	}

	/**
	 * Initializes the class on init if the ACF Abilities API is available.
	 *
	 * @since 6.8.0
	 *
	 * @return void
	 */
	public function init() {
		// Only hook if AI is enabled and Abilities API exists.
		if ( ! $this->is_acf_abilities_api_available() ) {
			return;
		}

		// Execution logging - hook after ability execution.
		add_action( 'wp_after_execute_ability', array( $this, 'log_execution' ), 10, 3 );
	}

	/**
	 * Checks if ACF AI and the Abilities API are enabled.
	 *
	 * @since 6.8.0
	 *
	 * @return boolean
	 */
	private function is_acf_abilities_api_available(): bool {
		return acf_get_setting( 'enable_acf_ai' ) && function_exists( 'wp_register_ability' );
	}

	/**
	 * Log execution events (when agents execute ACF abilities).
	 *
	 * Hooks into wp_after_execute_ability to log successful ability executions.
	 *
	 * @since 6.8.0
	 *
	 * @param string $ability_name The namespaced ability name.
	 * @param mixed  $input        The input data passed to the ability.
	 * @param mixed  $result       The result returned by the ability.
	 * @return void
	 */
	public function log_execution( string $ability_name, $input, $result ) {
		// Only log ACF abilities.
		if ( strpos( $ability_name, 'acf/' ) !== 0 ) {
			return;
		}

		$is_error = $result instanceof WP_Error;

		$this->increment_execution_count( $ability_name, $is_error );
	}

	/**
	 * Increment execution counts.
	 *
	 * @since 6.8.0
	 *
	 * @param string  $ability_name The ability that was executed.
	 * @param boolean $is_error     Whether the execution resulted in an error.
	 * @return boolean Success status.
	 */
	private function increment_execution_count( string $ability_name, bool $is_error ): bool {
		$data = $this->site_health->get_site_health();

		if ( ! isset( $data['ai_usage'] ) ) {
			$data['ai_usage'] = $this->get_default_usage_structure();
		}

		// Increment total executions.
		++$data['ai_usage']['total_executions'];
		$data['ai_usage']['last_execution_at'] = time();

		// Increment per-ability count.
		if ( ! isset( $data['ai_usage']['executions_by_ability'][ $ability_name ] ) ) {
			$data['ai_usage']['executions_by_ability'][ $ability_name ] = 0;
		}
		++$data['ai_usage']['executions_by_ability'][ $ability_name ];

		if ( $is_error ) {
			++$data['ai_usage']['error_count'];
		}

		return $this->site_health->update_site_health( $data );
	}

	/**
	 * Get the default log data structure.
	 *
	 * @since 6.8.0
	 *
	 * @return array
	 */
	private function get_default_usage_structure(): array {
		return array(
			'total_executions'      => 0,
			'error_count'           => 0,
			'last_execution_at'     => null,
			'executions_by_ability' => array(),
		);
	}

	/**
	 * Get AI-ready object counts for Site Health display.
	 *
	 * @since 6.8.0
	 *
	 * @param array $field_groups An array of ACF field groups.
	 * @param array $post_types   An array of ACF post types.
	 * @param array $taxonomies   An array of ACF taxonomies.
	 * @return array Counts of AI-ready objects by type.
	 */
	public function get_ai_ready_counts( $field_groups, $post_types, $taxonomies ): array {
		$counts = array(
			'field_groups' => 0,
			'post_types'   => 0,
			'taxonomies'   => 0,
		);

		// Count AI-ready field groups.
		foreach ( $field_groups as $field_group ) {
			if ( ! empty( $field_group['allow_ai_access'] ) && ! empty( $field_group['active'] ) ) {
				++$counts['field_groups'];
			}
		}

		// Count AI-ready post types.
		foreach ( $post_types as $post_type ) {
			if ( ! empty( $post_type['allow_ai_access'] ) && ! empty( $post_type['active'] ) ) {
				++$counts['post_types'];
			}
		}

		// Count AI-ready taxonomies.
		foreach ( $taxonomies as $taxonomy ) {
			if ( ! empty( $taxonomy['allow_ai_access'] ) && ! empty( $taxonomy['active'] ) ) {
				++$counts['taxonomies'];
			}
		}

		return $counts;
	}

	/**
	 * Get the usage metrics for Site Health display.
	 *
	 * @since 6.8.0
	 *
	 * @return array The usage metrics.
	 */
	public function get_usage_metrics(): array {
		$site_health = $this->site_health->get_site_health();

		if ( ! isset( $site_health['ai_usage'] ) ) {
			return array(
				'total_discovery_hits' => 0,
				'total_executions'     => 0,
				'error_count'          => 0,
			);
		}

		$usage = $site_health['ai_usage'];

		return array(
			'total_discovery_hits'  => $usage['total_discovery_hits'] ?? 0,
			'total_executions'      => $usage['total_executions'] ?? 0,
			'error_count'           => $usage['error_count'] ?? 0,
			'executions_by_ability' => $usage['executions_by_ability'] ?? array(),
		);
	}
}
