<?php
/**
 * Plugin Name:       AgenticWP
 * Description:       An agent framework for WordPress.
 * Version:           1.0.0
 * Requires at least: 6.5
 * Requires PHP:      8.0
 * Author:            Brett Swindells
 * License:           GPL-2.0-or-later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       agenticwp
 * Domain Path:       /languages
 *
 * @package AgenticWP
 *
 * Plugin Check Note: The plugin name "AgenticWP" uses "WP" which is acceptable per
 * WordPress.org guidelines as long as the full term "WordPress" is not used in the name.
 *
 * Plugin Data Stored:
 * -------------------
 * Options (21):
 * - agentic_wp_version (plugin version for migrations)
 * - agentic_wp_openai_key, agentic_wp_model, agentic_wp_reasoning_effort
 * - agentic_wp_max_output_tokens, agentic_wp_message_history_limit
 * - agentic_wp_enable_toast_notifications, agentic_wp_enable_web_search
 * - agentic_wp_create_post_directions, agentic_wp_sample_prompts
 * - agentic_wp_default_image_id, agentic_wp_organization_name
 * - agentic_wp_organization_logo, agentic_wp_organization_email
 * - agentic_wp_organization_phone, agentic_wp_actions
 * - agentic_wp_action_categories, agenticwp_jobs
 * - agenticwp_as_test_count, agenticwp_as_test_last_run
 * - agenticwp_usage_stats (usage statistics for gamification dashboard)
 *
 * Post Meta (3):
 * - _agenticwp_meta_description, _agenticwp_schema_headline, _agenticwp_schema_description
 *
 * Transients (3 patterns):
 * - agenticwp_post_session_{session_id}, agenticwp_block_info_{block_hash}
 * - agenticwp_block_cards_v1
 *
 * Action Scheduler Groups (2):
 * - agenticwp_jobs, agenticwp_test
 */

namespace Agentic_WP;

defined( 'ABSPATH' ) || exit;

const VERSION         = '1.0.0';
const MIN_WP_VERSION  = '6.5';
const MIN_PHP_VERSION = '8.0';

/**
 * Determine if the current environment meets plugin requirements.
 */
function meets_environment_requirements(): bool {
	return version_compare( PHP_VERSION, MIN_PHP_VERSION, '>=' ) && version_compare( get_bloginfo( 'version' ), MIN_WP_VERSION, '>=' );
}

/**
 * Build the requirement failure message (translated).
 *
 * Use this for admin notices that run after the 'init' action.
 */
function requirement_notice_message(): string {
	return sprintf(
		/* translators: 1: plugin name, 2: required WordPress version, 3: required PHP version, 4: current WordPress version, 5: current PHP version */
		__( '%1$s requires WordPress %2$s and PHP %3$s or higher. You are running WordPress %4$s and PHP %5$s.', 'agenticwp' ),
		'AgenticWP',
		MIN_WP_VERSION,
		MIN_PHP_VERSION,
		get_bloginfo( 'version' ),
		PHP_VERSION
	);
}

/**
 * Build the requirement failure message (untranslated).
 *
 * Use this for activation hooks that run before the textdomain is loaded.
 */
function requirement_notice_message_untranslated(): string {
	return sprintf(
		'AgenticWP requires WordPress %1$s and PHP %2$s or higher. You are running WordPress %3$s and PHP %4$s.',
		MIN_WP_VERSION,
		MIN_PHP_VERSION,
		get_bloginfo( 'version' ),
		PHP_VERSION
	);
}

/**
 * Deactivate the plugin if requirements are not met.
 */
function maybe_deactivate_self(): void {
	if ( ! current_user_can( 'activate_plugins' ) ) {
		return;
	}

	if ( ! function_exists( 'deactivate_plugins' ) ) {
		require_once ABSPATH . 'wp-admin/includes/plugin.php';
	}

	deactivate_plugins( plugin_basename( __FILE__ ) );
}

/**
 * Render an admin notice when requirements are not met.
 */
function render_requirement_notice(): void {
	if ( ! current_user_can( 'activate_plugins' ) ) {
		return;
	}

	printf(
		'<div class="notice notice-error"><p>%s</p></div>',
		esc_html( requirement_notice_message() )
	);
}

$agentic_wp_environment_is_compatible = meets_environment_requirements();

if ( $agentic_wp_environment_is_compatible ) {
	require_once plugin_dir_path( __FILE__ ) . 'libraries/action-scheduler/action-scheduler.php';
	require_once plugin_dir_path( __FILE__ ) . 'includes/class-error-handler.php';
	require_once plugin_dir_path( __FILE__ ) . 'includes/class-background-jobs.php';
	require_once plugin_dir_path( __FILE__ ) . 'includes/class-job-health-monitor.php';

	add_action( 'init', __NAMESPACE__ . '\\load_textdomain' );
	add_action( 'plugins_loaded', __NAMESPACE__ . '\\init' );
	add_action( 'plugins_loaded', __NAMESPACE__ . '\\check_version' );
	add_action( 'plugins_loaded', __NAMESPACE__ . '\\maybe_enable_rest_schema_debug' );

	require_once plugin_dir_path( __FILE__ ) . 'includes/class-as-test.php';
	\Agentic_WP\AS_Test::register();
} else {
	add_action( 'admin_init', __NAMESPACE__ . '\\maybe_deactivate_self' );
	add_action( 'admin_notices', __NAMESPACE__ . '\\render_requirement_notice' );
	add_action( 'network_admin_notices', __NAMESPACE__ . '\\render_requirement_notice' );
}

/**
 * Load plugin textdomain for translations.
 */
function load_textdomain(): void {
	load_plugin_textdomain( 'agenticwp', false, dirname( \plugin_basename( __FILE__ ) ) . '/languages' );
}

/**
 * Output meta description to wp_head if available.
 */
function output_meta_description(): void {
	if ( ! is_singular() ) {
		return;
	}

	$meta_desc = get_post_meta( get_the_ID(), '_agenticwp_meta_description', true );
	if ( ! empty( $meta_desc ) ) {
		echo '<meta name="description" content="' . esc_attr( $meta_desc ) . '">' . "\n";
	}
}

/**
 * Initialize plugin components.
 *
 * Loads required classes and initializes core functionality.
 */
function init(): void {
	require_once plugin_dir_path( __FILE__ ) . 'includes/class-settings.php';
	require_once plugin_dir_path( __FILE__ ) . 'includes/class-openai-client.php';
	require_once plugin_dir_path( __FILE__ ) . 'includes/class-tools.php';
	require_once plugin_dir_path( __FILE__ ) . 'includes/class-agents.php';
	require_once plugin_dir_path( __FILE__ ) . 'includes/class-action-manager.php';
	require_once plugin_dir_path( __FILE__ ) . 'includes/class-schema-manager.php';
	require_once plugin_dir_path( __FILE__ ) . 'includes/class-usage-stats.php';
	require_once plugin_dir_path( __FILE__ ) . 'includes/class-achievements.php';
	require_once plugin_dir_path( __FILE__ ) . 'includes/class-settings-dashboard.php';
	require_once plugin_dir_path( __FILE__ ) . 'includes/class-image-generator.php';
	require_once plugin_dir_path( __FILE__ ) . 'includes/class-settings-images.php';

	\Agentic_WP\Background_Jobs::register();
	\Agentic_WP\Job_Health_Monitor::register();
	\Agentic_WP\Usage_Stats::get_instance();
	\Agentic_WP\Achievements::get_instance();

	add_action( 'wp_head', __NAMESPACE__ . '\\output_meta_description', 1 );

	new \Agentic_WP\Action_Manager();
	new \Agentic_WP\Schema_Manager();

	if ( is_admin() ) {
		require_once plugin_dir_path( __FILE__ ) . 'includes/class-chat-ajax.php';
		require_once plugin_dir_path( __FILE__ ) . 'includes/class-chat-interface.php';
		require_once plugin_dir_path( __FILE__ ) . 'includes/class-image-ajax.php';

		new \Agentic_WP\Settings_Dashboard();
		new \Agentic_WP\Settings();
		new \Agentic_WP\Chat_Ajax();
		new \Agentic_WP\Chat_Interface();
		new \Agentic_WP\Image_Ajax();
		new \Agentic_WP\Settings_Images();
	}
}

/**
 * Check plugin version and run migrations if needed.
 *
 * This function runs on every page load (via plugins_loaded hook) to detect
 * version changes and run necessary upgrade routines. Per WordPress best practices,
 * migrations should NOT run on activation hook due to multisite limitations.
 *
 * @link https://developer.wordpress.org/plugins/plugin-basics/activation-deactivation-hooks/#activation-hooks-on-multisite
 */
function check_version(): void {
	$stored_version = get_option( 'agentic_wp_version', '0.0.0' );

	// No upgrade needed if versions match.
	if ( version_compare( $stored_version, VERSION, '==' ) ) {
		return;
	}

	/*
	 * Run upgrade routines based on version comparison.
	 * Example for future migrations:
	 * if ( version_compare( $stored_version, '0.2.0', '<' ) ) {
	 *     agenticwp_migrate_to_0_2_0();
	 * }
	 */

	// Update stored version after successful migration.
	update_option( 'agentic_wp_version', VERSION );
}

/**
 * Enable REST schema debugging in development environments.
 *
 * Hooks into doing_it_wrong to capture REST schema validation issues.
 */
function maybe_enable_rest_schema_debug(): void {
	$enabled = apply_filters( 'agentic_wp_debug_rest_schema', false );
	if ( function_exists( 'wp_get_environment_type' ) && wp_get_environment_type() === 'development' ) {
		$enabled = true;
	}
	if ( $enabled ) {
		add_filter( 'doing_it_wrong_run', __NAMESPACE__ . '\\tap_doing_it_wrong', 10, 4 );
	}
}

/**
 * Log a concise stack for REST schema doing_it_wrong messages.
 *
 * @param mixed  $unused_value    Unused value.
 * @param string $function_name   Function name.
 * @param string $message         Message (may include HTML tags).
 * @param string $version         Version string.
 * @return mixed                  Always returns original unused value.
 */
function tap_doing_it_wrong( $unused_value, $function_name, $message, $version ) {
	try {
		$raw = wp_strip_all_tags( (string) $message );
		if ( 'rest_validate_value_from_schema' === $function_name || ( is_string( $raw ) && str_contains( $raw, 'schema keyword' ) ) ) {
			// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_wp_debug_backtrace_summary -- Intentional debug logging.
			$trace = function_exists( 'wp_debug_backtrace_summary' ) ? wp_debug_backtrace_summary( null, 0, false ) : '';
			$log   = sprintf( '[AgenticWP] doing_it_wrong %s: %s | since %s | trace: %s', (string) $function_name, (string) $raw, (string) $version, (string) $trace );
			// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional debug logging.
			error_log( $log );
		}
		// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
	} catch ( \Throwable $e ) {
		// Intentionally empty: silences any exceptions during debug logging.
	}
	return $unused_value;
}

/**
 * Plugin activation hook.
 *
 * Initializes default options and stores version number for migration tracking.
 * Uses add_option() which won't overwrite existing values on reactivation.
 *
 * @link https://developer.wordpress.org/plugins/plugin-basics/activation-deactivation-hooks/
 */
function activate(): void {
	if ( ! meets_environment_requirements() ) {
		maybe_deactivate_self();
		// Use untranslated strings here because activation hooks run before
		// the textdomain is loaded at the 'init' action.
		wp_die(
			esc_html( requirement_notice_message_untranslated() ),
			'Plugin activation failed',
			array( 'back_link' => true )
		);
	}

	// Store plugin version for migration tracking.
	add_option( 'agentic_wp_version', VERSION );

	// Initialize core settings with defaults (won't overwrite existing).
	add_option( 'agentic_wp_model', 'gpt-5-mini' );
	add_option( 'agentic_wp_reasoning_effort', 'medium' );
	add_option( 'agentic_wp_max_output_tokens', 32000 );
	add_option( 'agentic_wp_message_history_limit', 50 );
	add_option( 'agentic_wp_enable_toast_notifications', true );
	add_option( 'agentic_wp_enable_web_search', false );

	// Clean up deprecated background delegation option (removed in 0.1.0 migration).
	delete_option( 'agentic_wp_background_delegation' );

	// Initialize dev/test mode options if AS_Test class exists.
	if ( class_exists( 'Agentic_WP\AS_Test' ) ) {
		add_option( 'agenticwp_as_test_count', 0 );
		add_option( 'agenticwp_as_test_last_run', 0 );
	}
}

/**
 * Plugin deactivation hook.
 *
 * Cleans up scheduled actions and transients. Preserves user data (options, post meta)
 * per WordPress best practices, as the plugin may be reactivated.
 *
 * @link https://developer.wordpress.org/plugins/plugin-basics/activation-deactivation-hooks/
 */
function deactivate(): void {
	// Unschedule all Action Scheduler jobs.
	if ( function_exists( 'as_unschedule_all_actions' ) ) {
		as_unschedule_all_actions( '', array(), 'agenticwp_jobs' );
		as_unschedule_all_actions( '', array(), 'agenticwp_test' );
	}

	// Clear all plugin transients (WordPress has no native prefix deletion).
	global $wpdb;
	// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
	$wpdb->query(
		$wpdb->prepare(
			"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s",
			$wpdb->esc_like( '_transient_agenticwp_' ) . '%',
			$wpdb->esc_like( '_transient_timeout_agenticwp_' ) . '%'
		)
	);

	// Note: User data (options, post meta, content) is intentionally preserved.
	// Users may reactivate the plugin and expect their settings to remain intact.
}
register_activation_hook( __FILE__, __NAMESPACE__ . '\\activate' );
register_deactivation_hook( __FILE__, __NAMESPACE__ . '\\deactivate' );
