<?php
/**
 * Public API for extensions.
 *
 * Prefixed helper functions that wrap internal classes and pass every value
 * through apply_filters/do_action. This is the stable public surface for
 * the pro plugin and any third-party extensions.
 *
 * Follows the pattern used by WooCommerce (wc_*), EDD (edd_*), and ACF (acf_*).
 * Every returned value is filterable so extensions can override behavior.
 *
 * All functions are safe to call from any plugin. They return sensible
 * defaults if the free plugin's subsystems are not yet initialized.
 *
 * @package IPAIS\Core
 * @since   1.1.0
 */

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// ─── Global Accessor ─────────────────────────────────────────────────────────

if ( ! function_exists( 'infyp' ) ) {
	/**
	 * Returns the main plugin instance.
	 *
	 * This is the primary entry point for extensions. Use this to access
	 * singleton subsystems when you need the object itself (e.g. multiple
	 * method calls). For simple one-shot operations, prefer the infyp_*()
	 * helper functions below.
	 *
	 * @since 1.1.0
	 *
	 * @return \IPAIS\Core\INFYP_Plugin
	 */
	function infyp() {
		return \IPAIS\Core\INFYP_Plugin::instance();
	}
}

// ─── Settings ────────────────────────────────────────────────────────────────

if ( ! function_exists( 'infyp_get_setting' ) ) {
	/**
	 * Get a plugin setting by key.
	 *
	 * Wraps get_option() and passes the value through apply_filters()
	 * so extensions can override any setting. Follows the EDD pattern.
	 *
	 * @since 1.1.0
	 *
	 * @param string $key     Setting key (e.g. 'ai_model', 'batch_size', 'timeout').
	 * @param mixed  $default Default value if setting is not found.
	 * @return mixed
	 */
	function infyp_get_setting( $key, $default = null ) {
		// Check optimization settings first, then prompt settings.
		$opt_settings    = get_option( 'infyp_optimization_settings', [] );
		$prompt_settings = get_option( 'infyp_prompt_settings', [] );

		if ( isset( $opt_settings[ $key ] ) ) {
			$value = $opt_settings[ $key ];
		} elseif ( isset( $prompt_settings[ $key ] ) ) {
			$value = $prompt_settings[ $key ];
		} else {
			$value = $default;
		}

		/**
		 * Filter a plugin setting value.
		 *
		 * @since 1.1.0
		 *
		 * @param mixed  $value   The setting value.
		 * @param string $key     The setting key.
		 * @param mixed  $default The default value.
		 */
		return apply_filters( 'infyp_get_setting', $value, $key, $default );
	}
}

if ( ! function_exists( 'infyp_get_api_key' ) ) {
	/**
	 * Get the API key for a provider.
	 *
	 * @since 1.1.0
	 *
	 * @param string $provider Provider slug: 'openai', 'google', or 'anthropic'.
	 * @return string|null The decrypted API key, or null.
	 */
	function infyp_get_api_key( $provider ) {
		$plugin = infyp();

		if ( $plugin->api_keys ) {
			$key = $plugin->api_keys->get_api_key( $provider );
		} else {
			$key = null;
		}

		/**
		 * Filter the API key for a provider.
		 *
		 * @since 1.1.0
		 *
		 * @param string|null $key      The API key.
		 * @param string      $provider The provider slug.
		 */
		return apply_filters( 'infyp_get_api_key', $key, $provider );
	}
}

if ( ! function_exists( 'infyp_get_active_model' ) ) {
	/**
	 * Get the currently configured AI model.
	 *
	 * @since 1.1.0
	 *
	 * @return string Model identifier (e.g. 'gemini-3.1-flash-lite-preview').
	 */
	function infyp_get_active_model() {
		$model = infyp_get_setting( 'ai_model', INFYP_DEFAULT_MODEL );

		/**
		 * Filter the active AI model.
		 *
		 * @since 1.1.0
		 *
		 * @param string $model The model identifier.
		 */
		return apply_filters( 'infyp_get_active_model', $model );
	}
}

if ( ! function_exists( 'infyp_get_language' ) ) {
	/**
	 * Get the configured language for AI prompts.
	 *
	 * @since 1.1.0
	 *
	 * @return string Language name (e.g. 'English').
	 */
	function infyp_get_language() {
		$lang = infyp_get_setting( 'language', 'English' );

		/**
		 * Filter the AI prompt language.
		 *
		 * @since 1.1.0
		 *
		 * @param string $lang The language name.
		 */
		return apply_filters( 'infyp_get_language', $lang );
	}
}

if ( ! function_exists( 'infyp_get_provider_for_model' ) ) {
	/**
	 * Get the provider slug for a given AI model.
	 *
	 * @since 1.1.0
	 *
	 * @param string $model Model identifier.
	 * @return string|null Provider slug ('openai', 'google', 'anthropic') or null.
	 */
	function infyp_get_provider_for_model( $model ) {
		$plugin = infyp();

		if ( $plugin->api_keys ) {
			$provider = $plugin->api_keys->get_provider_for_model( $model );
		} else {
			$provider = null;
		}

		/**
		 * Filter the provider for a given model.
		 *
		 * @since 1.1.0
		 *
		 * @param string|null $provider The provider slug.
		 * @param string      $model    The model identifier.
		 */
		return apply_filters( 'infyp_get_provider_for_model', $provider, $model );
	}
}

// ─── Image Queries ───────────────────────────────────────────────────────────

if ( ! function_exists( 'infyp_get_image_ids' ) ) {
	/**
	 * Get image attachment IDs matching given arguments.
	 *
	 * Wraps INFYP_Image_List_Table::get_images() so extensions never
	 * import the table class directly.
	 *
	 * @since 1.1.0
	 *
	 * @param array $args {
	 *     Optional. Query arguments.
	 *
	 *     @type int    $per_page         Images per page. Default -1 (all).
	 *     @type int    $page_number      Page number. Default 1.
	 *     @type string $search_term      Search term. Default ''.
	 *     @type string $orderby          Order by field. Default 'date'.
	 *     @type string $order            Order direction. Default 'desc'.
	 *     @type string $post_type_filter Post type filter. Default null.
	 * }
	 * @return array Array of image IDs.
	 */
	function infyp_get_image_ids( $args = [] ) {
		$defaults = [
			'per_page'         => -1,
			'page_number'      => 1,
			'search_term'      => '',
			'orderby'          => 'date',
			'order'            => 'desc',
			'post_type_filter' => null,
		];
		$args = wp_parse_args( $args, $defaults );

		/**
		 * Filter the image query arguments.
		 *
		 * @since 1.1.0
		 *
		 * @param array $args The query arguments.
		 */
		$args = apply_filters( 'infyp_image_query_args', $args );

		$table = new \IPAIS\Tables\INFYP_Image_List_Table();
		$result = $table->get_images(
			$args['per_page'],
			$args['page_number'],
			$args['search_term'],
			$args['orderby'],
			$args['order'],
			null,
			$args['post_type_filter']
		);

		$ids = [];
		if ( ! empty( $result['items'] ) ) {
			$ids = wp_list_pluck( $result['items'], 'ID' );
		}

		/**
		 * Filter the returned image IDs.
		 *
		 * @since 1.1.0
		 *
		 * @param array $ids  The image IDs.
		 * @param array $args The query arguments used.
		 */
		return apply_filters( 'infyp_get_image_ids', $ids, $args );
	}
}

if ( ! function_exists( 'infyp_get_image_count' ) ) {
	/**
	 * Get total count of image attachments matching arguments.
	 *
	 * @since 1.1.0
	 *
	 * @param array $args Optional. Same arguments as infyp_get_image_ids().
	 * @return int Image count.
	 */
	function infyp_get_image_count( $args = [] ) {
		$defaults = [
			'per_page'         => -1,
			'page_number'      => 1,
			'search_term'      => '',
			'orderby'          => 'date',
			'order'            => 'desc',
			'post_type_filter' => null,
		];
		$args = wp_parse_args( $args, $defaults );

		$table  = new \IPAIS\Tables\INFYP_Image_List_Table();
		$result = $table->get_images(
			$args['per_page'],
			$args['page_number'],
			$args['search_term'],
			$args['orderby'],
			$args['order'],
			null,
			$args['post_type_filter']
		);

		$count = isset( $result['total'] ) ? (int) $result['total'] : 0;

		/**
		 * Filter the image count.
		 *
		 * @since 1.1.0
		 *
		 * @param int   $count The image count.
		 * @param array $args  The query arguments used.
		 */
		return apply_filters( 'infyp_get_image_count', $count, $args );
	}
}

// ─── AI Optimization ─────────────────────────────────────────────────────────

if ( ! function_exists( 'infyp_optimize_field' ) ) {
	/**
	 * Run AI optimization on a single image field.
	 *
	 * Wraps INFYP_AI_Optimizer::optimize_single_field() so extensions
	 * never import the static class directly.
	 *
	 * @since 1.1.0
	 *
	 * @param int    $image_id     Attachment ID.
	 * @param string $field_type   Field to optimize ('alt_text', 'title', 'filename', 'caption', 'description').
	 * @param array  $options      {
	 *     Optional. Extra options.
	 *
	 *     @type array  $existing_keywords Existing keywords for context.
	 *     @type string $custom_prompt     Custom prompt addon text.
	 * }
	 * @return array|WP_Error Optimization result or error.
	 */
	function infyp_optimize_field( $image_id, $field_type, $options = [] ) {
		$keywords = isset( $options['existing_keywords'] ) ? $options['existing_keywords'] : null;
		$prompt   = isset( $options['custom_prompt'] ) ? $options['custom_prompt'] : '';

		$result = \IPAIS\Core\INFYP_AI_Optimizer::optimize_single_field(
			$image_id,
			$field_type,
			$keywords,
			$prompt
		);

		/**
		 * Filter the single-field optimization result.
		 *
		 * @since 1.1.0
		 *
		 * @param array|WP_Error $result     The optimization result.
		 * @param int            $image_id   The attachment ID.
		 * @param string         $field_type The field type.
		 * @param array          $options    The options passed.
		 */
		return apply_filters( 'infyp_run_single_field_optimization', $result, $image_id, $field_type, $options );
	}
}

if ( ! function_exists( 'infyp_optimize_image' ) ) {
	/**
	 * Run full AI optimization on an image (all fields).
	 *
	 * Wraps INFYP_AI_Optimizer::generate_seo_data().
	 *
	 * @since 1.1.0
	 *
	 * @param int    $image_id          Attachment ID.
	 * @param array  $existing_keywords Optional. Existing keywords.
	 * @param string $custom_prompt     Optional. Custom prompt addon.
	 * @return array|WP_Error Optimization result with 'keywords', 'filename', 'alt_text', 'title'.
	 */
	function infyp_optimize_image( $image_id, $existing_keywords = null, $custom_prompt = '' ) {
		$result = \IPAIS\Core\INFYP_AI_Optimizer::generate_seo_data(
			$image_id,
			$existing_keywords,
			$custom_prompt
		);

		/**
		 * Filter the full optimization result.
		 *
		 * @since 1.1.0
		 *
		 * @param array|WP_Error $result            The optimization result.
		 * @param int            $image_id          The attachment ID.
		 * @param array|null     $existing_keywords The existing keywords.
		 * @param string         $custom_prompt     The custom prompt.
		 */
		return apply_filters( 'infyp_run_optimization', $result, $image_id, $existing_keywords, $custom_prompt );
	}
}

if ( ! function_exists( 'infyp_get_image_base64' ) ) {
	/**
	 * Get base64-encoded image data for AI API calls.
	 *
	 * Wraps INFYP_AI_Optimizer::get_cached_base64().
	 *
	 * @since 1.1.0
	 *
	 * @param int $image_id Attachment ID.
	 * @return string|WP_Error Base64 string or error.
	 */
	function infyp_get_image_base64( $image_id ) {
		$base64 = \IPAIS\Core\INFYP_AI_Optimizer::get_cached_base64( $image_id );

		/**
		 * Filter the base64 image data.
		 *
		 * @since 1.1.0
		 *
		 * @param string|WP_Error $base64   The base64 data.
		 * @param int             $image_id The attachment ID.
		 */
		return apply_filters( 'infyp_get_image_base64', $base64, $image_id );
	}
}

// ─── Validation ──────────────────────────────────────────────────────────────

if ( ! function_exists( 'infyp_is_valid_image' ) ) {
	/**
	 * Validate that an attachment ID is a valid image.
	 *
	 * Wraps INFYP_Security_Manager::validate_attachment_id().
	 *
	 * @since 1.1.0
	 *
	 * @param int $image_id Attachment ID to validate.
	 * @return bool True if valid image attachment.
	 */
	function infyp_is_valid_image( $image_id ) {
		$plugin = infyp();

		if ( $plugin->security ) {
			$is_valid = $plugin->security->validate_attachment_id( $image_id );
		} else {
			// Fallback: basic WordPress check.
			$is_valid = wp_attachment_is_image( $image_id );
		}

		/**
		 * Filter whether an image ID is valid.
		 *
		 * @since 1.1.0
		 *
		 * @param bool $is_valid Whether the image is valid.
		 * @param int  $image_id The attachment ID.
		 */
		return apply_filters( 'infyp_validate_image_id', $is_valid, $image_id );
	}
}

if ( ! function_exists( 'infyp_user_can' ) ) {
	/**
	 * Check if the current user has capability for a plugin action.
	 *
	 * Wraps INFYP_Security_Manager::check_capability_for_action().
	 *
	 * @since 1.1.0
	 *
	 * @param string $action The action to check (e.g. 'optimize', 'edit_field', 'manage_settings').
	 * @return bool True if user has the required capability.
	 */
	function infyp_user_can( $action ) {
		$plugin = infyp();

		if ( $plugin->security ) {
			$has_cap = $plugin->security->check_capability_for_action( $action );
		} else {
			// Fallback: require upload_files capability.
			$has_cap = current_user_can( 'upload_files' );
		}

		/**
		 * Filter the capability check.
		 *
		 * @since 1.1.0
		 *
		 * @param bool   $has_cap Whether the user has the capability.
		 * @param string $action  The action being checked.
		 */
		return apply_filters( 'infyp_check_capability', $has_cap, $action );
	}
}

// ─── Changelog / Logging ─────────────────────────────────────────────────────

if ( ! function_exists( 'infyp_log_change' ) ) {
	/**
	 * Log a field change to the changelog.
	 *
	 * Wraps INFYP_Changelog::add_entry() so extensions never import the class.
	 *
	 * @since 1.1.0
	 *
	 * @param int         $image_id  Attachment ID.
	 * @param string      $field     Field name (e.g. 'alt_text', 'title', 'caption').
	 * @param string      $old_value Previous value.
	 * @param string      $new_value New value.
	 * @param string|null $source    Source of the change (e.g. 'manual', 'ai', 'pro'). Optional.
	 * @return void
	 */
	function infyp_log_change( $image_id, $field, $old_value, $new_value, $source = null ) {
		/**
		 * Fires before a field change is logged.
		 *
		 * @since 1.1.0
		 *
		 * @param int         $image_id  The attachment ID.
		 * @param string      $field     The field name.
		 * @param string      $old_value The old value.
		 * @param string      $new_value The new value.
		 * @param string|null $source    The change source.
		 */
		do_action( 'infyp_log_field_change', $image_id, $field, $old_value, $new_value, $source );

		\IPAIS\Database\INFYP_Changelog::add_entry( $image_id, $field, $old_value, $new_value, $source );
	}
}

// ─── Image Usage ─────────────────────────────────────────────────────────────

if ( ! function_exists( 'infyp_find_image_usage' ) ) {
	/**
	 * Find where an image is used across the site.
	 *
	 * Wraps INFYP_Image_Usage::find_usage().
	 *
	 * @since 1.1.0
	 *
	 * @param int $image_id Attachment ID.
	 * @return array Array of usage data objects.
	 */
	function infyp_find_image_usage( $image_id ) {
		$usage = \IPAIS\Core\INFYP_Image_Usage::find_usage( $image_id );

		/**
		 * Filter the image usage results.
		 *
		 * @since 1.1.0
		 *
		 * @param array $usage    The usage data.
		 * @param int   $image_id The attachment ID.
		 */
		return apply_filters( 'infyp_find_image_usage', $usage, $image_id );
	}
}

// ─── API Usage Tracking ──────────────────────────────────────────────────────

if ( ! function_exists( 'infyp_track_api_call' ) ) {
	/**
	 * Track an AI API call for usage statistics.
	 *
	 * Wraps INFYP_API_Usage_Tracker::track_api_call().
	 *
	 * @since 1.1.0
	 *
	 * @param string   $provider Provider slug ('openai', 'google', 'anthropic').
	 * @param string   $model    Model identifier.
	 * @param string   $status   'success' or 'error'.
	 * @param array    $data     Optional. Extra data (endpoint, tokens_used, response_time, etc.).
	 * @param int|null $image_id Optional. Attachment ID.
	 * @return void
	 */
	function infyp_track_api_call( $provider, $model, $status, $data = [], $image_id = null ) {
		/**
		 * Fires when an API call is tracked.
		 *
		 * @since 1.1.0
		 *
		 * @param string   $provider The provider slug.
		 * @param string   $model    The model identifier.
		 * @param string   $status   The call status.
		 * @param array    $data     Extra tracking data.
		 * @param int|null $image_id The attachment ID.
		 */
		do_action( 'infyp_track_api_usage', $provider, $model, $status, $data, $image_id );

		$plugin = infyp();

		if ( $plugin->api_usage ) {
			$plugin->api_usage->track_api_call( $provider, $model, $status, $data, $image_id );
		}
	}
}

// ─── Cache ───────────────────────────────────────────────────────────────────

if ( ! function_exists( 'infyp_invalidate_cache' ) ) {
	/**
	 * Invalidate plugin caches.
	 *
	 * Wraps INFYP_Cache_Manager methods so extensions never import the singleton.
	 *
	 * @since 1.1.0
	 *
	 * @param string   $type       Cache type: 'image', 'settings', or 'all'.
	 * @param int|null $identifier Optional. Image ID when type is 'image'.
	 * @return void
	 */
	function infyp_invalidate_cache( $type, $identifier = null ) {
		$plugin = infyp();

		if ( ! $plugin->cache ) {
			return;
		}

		switch ( $type ) {
			case 'image':
				if ( $identifier ) {
					$plugin->cache->invalidate_image_cache( $identifier );

					/**
					 * Fires after an image cache is invalidated.
					 *
					 * @since 1.1.0
					 *
					 * @param int $identifier The attachment ID.
					 */
					do_action( 'infyp_invalidate_image_cache', $identifier );
				}
				break;

			case 'settings':
				$plugin->cache->invalidate_settings_cache();
				break;

			case 'all':
				$plugin->cache->clear_all_cache();

				/**
				 * Fires after all caches are invalidated.
				 *
				 * @since 1.1.0
				 */
				do_action( 'infyp_invalidate_all_caches' );
				break;
		}
	}
}
