<?php
/**
 * Plugin Name: SmartyPress AI Engine
 * Plugin URI: https://github.com/alexkovalevv/smartypress-ai-engine
 * Description: AI-powered content generation engine for WordPress. Generate posts, pages, comments, WooCommerce products, and more using various AI providers.
 * Version: 1.0.23
 * Requires at least: 6.2
 * Tested up to: 7.0
 * Requires PHP: 7.4
 * Author: Alex Kovalev
 * Author URI: https://github.com/alexkovalevv
 * License: GPL v2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: smartypress-ai-engine
 * Domain Path: /languages
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Main plugin constants
 */
define( 'SMARTYPRESS_AI_VERSION', '1.0.23' );
define( 'SMARTYPRESS_AI_PLUGIN_FILE', __FILE__ );
define( 'SMARTYPRESS_AI_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'SMARTYPRESS_AI_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
define( 'SMARTYPRESS_AI_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
define( 'SMARTYPRESS_AI_DOCUMENTATION_URL', 'https://wp-aifactory.com/step-by-step-guide-to-smartypress-free-ai-engine/' );

/**
 * Review notice debug: when true, the review notice shows immediately without waiting 7 days.
 */
if ( ! defined( 'SMARTYPRESS_AI_REVIEW_NOTICE_DEBUG' ) ) {
	define( 'SMARTYPRESS_AI_REVIEW_NOTICE_DEBUG', false );
}

/**
 * Load Composer autoloader (for Parsedown and other dependencies)
 */
$smartypress_ai_composer_autoload = SMARTYPRESS_AI_PLUGIN_DIR . 'vendor/autoload.php';
if ( file_exists( $smartypress_ai_composer_autoload ) ) {
	require_once $smartypress_ai_composer_autoload;
}

/**
 * Autoloader for plugin classes
 *
 * @param string $class_name The class name to load.
 */
function smartypress_ai_autoloader( $class_name ) {
	// Check if class belongs to our plugin
	if ( strpos( $class_name, 'SmartyPress_AI_' ) !== 0 ) {
		return;
	}

	// Convert class name to file name
	$class_file = str_replace( 'SmartyPress_AI_', '', $class_name );
	$class_file = strtolower( str_replace( '_', '-', $class_file ) );
	$class_file = 'class-' . $class_file . '.php';

	// Check in includes/admin directory
	$admin_path = SMARTYPRESS_AI_PLUGIN_DIR . 'includes/admin/' . $class_file;
	if ( file_exists( $admin_path ) ) {
		require_once $admin_path;
		return;
	}

	// Check in includes/core directory
	$core_path = SMARTYPRESS_AI_PLUGIN_DIR . 'includes/core/' . $class_file;
	if ( file_exists( $core_path ) ) {
		require_once $core_path;
		return;
	}

	// Check in includes/integrations directory
	$integrations_path = SMARTYPRESS_AI_PLUGIN_DIR . 'includes/integrations/' . $class_file;
	if ( file_exists( $integrations_path ) ) {
		require_once $integrations_path;
		return;
	}

	// Check in includes/providers directory
	$providers_path = SMARTYPRESS_AI_PLUGIN_DIR . 'includes/providers/' . $class_file;
	if ( file_exists( $providers_path ) ) {
		require_once $providers_path;
		return;
	}

	// Check in includes/providers/yandex-gpt directory
	$yandex_gpt_path = SMARTYPRESS_AI_PLUGIN_DIR . 'includes/providers/yandex-gpt/' . $class_file;
	if ( file_exists( $yandex_gpt_path ) ) {
		require_once $yandex_gpt_path;
		return;
	}

	// Check in includes/providers/gigachat directory
	$gigachat_path = SMARTYPRESS_AI_PLUGIN_DIR . 'includes/providers/gigachat/' . $class_file;
	if ( file_exists( $gigachat_path ) ) {
		require_once $gigachat_path;
		return;
	}

	// Check in includes/modules/{module_name}/ directory
	$modules_dir = SMARTYPRESS_AI_PLUGIN_DIR . 'includes/modules/';
	if ( is_dir( $modules_dir ) ) {
		$modules = glob( $modules_dir . '*/', GLOB_ONLYDIR );
		foreach ( $modules as $module_dir ) {
			$module_path = $module_dir . $class_file;
			if ( file_exists( $module_path ) ) {
				require_once $module_path;
				return;
			}
		}
	}

	// Check in includes/modules/{module_name}/admin/ directory
	if ( is_dir( $modules_dir ) ) {
		$modules = glob( $modules_dir . '*/admin/', GLOB_ONLYDIR );
		foreach ( $modules as $module_admin_dir ) {
			$module_admin_path = $module_admin_dir . $class_file;
			if ( file_exists( $module_admin_path ) ) {
				require_once $module_admin_path;
				return;
			}
		}
	}
}
spl_autoload_register( 'smartypress_ai_autoloader' );

/**
 * Add plugin action links on the Plugins screen.
 *
 * @param array $links Existing action links.
 * @return array
 */
function smartypress_ai_plugin_action_links( $links ) {
	$settings_link = sprintf(
		'<a href="%1$s">%2$s</a>',
		esc_url( admin_url( 'admin.php?page=smartypress-ai#/settings' ) ),
		esc_html__( 'Settings', 'smartypress-ai-engine' )
	);

	array_unshift( $links, $settings_link );

	return $links;
}
add_filter( 'plugin_action_links_' . SMARTYPRESS_AI_PLUGIN_BASENAME, 'smartypress_ai_plugin_action_links' );

/**
 * Add plugin row meta links on the Plugins screen.
 *
 * @param array  $links Existing row meta links.
 * @param string $plugin_file Current plugin file basename.
 * @return array
 */
function smartypress_ai_plugin_row_meta( $links, $plugin_file ) {
	if ( SMARTYPRESS_AI_PLUGIN_BASENAME !== $plugin_file ) {
		return $links;
	}

	$links[] = sprintf(
		'<a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>',
		esc_url( SMARTYPRESS_AI_DOCUMENTATION_URL ),
		esc_html__( 'Documentation', 'smartypress-ai-engine' )
	);

	return $links;
}
add_filter( 'plugin_row_meta', 'smartypress_ai_plugin_row_meta', 10, 2 );

// Load core classes early (before autoloader-dependent modules).
require_once SMARTYPRESS_AI_PLUGIN_DIR . 'includes/core/class-logger.php';
require_once SMARTYPRESS_AI_PLUGIN_DIR . 'includes/core/class-model-pricing.php';
require_once SMARTYPRESS_AI_PLUGIN_DIR . 'includes/core/class-token-tracker.php';

/**
 * Global plugin instance
 *
 * @var SmartyPress_AI_Plugin_Loader
 */
global $smartypress_ai_plugin;

/**
 * Check if WooCommerce products are available as an editable post type.
 *
 * @return bool True when WooCommerce product content can use AI features.
 */
function smartypress_ai_is_woocommerce_product_post_type_available() {
	return class_exists( 'WooCommerce' ) || ( function_exists( 'post_type_exists' ) && post_type_exists( 'product' ) );
}

/**
 * Get default post types with AI features enabled.
 *
 * @return array Default post type names.
 */
function smartypress_ai_get_default_enabled_post_types() {
	$post_types = array( 'post', 'page' );

	if ( smartypress_ai_is_woocommerce_product_post_type_available() ) {
		$post_types[] = 'product';
	}

	return $post_types;
}

/**
 * Migrate settings: ensure modules key exists with defaults
 *
 * For upgraded installations that may not have the modules structure.
 * Also converts scalar module values to array format for consistency.
 */
function smartypress_ai_migrate_modules_settings() {
	$settings = get_option( 'smartypress_ai_settings', array() );
	$modules  = $settings['modules'] ?? array();
	$needs_update = false;

	// If modules is empty or not an array, set defaults
	if ( empty( $modules ) || ! is_array( $modules ) ) {
		$modules = array(
			'content_generator' => true,
			'image_generator'   => true,
			'image_alt_generator' => true,
			'seo_analysis'      => true,
			'seo_optimization'  => true,
		);
		$needs_update = true;
	}

	// Convert scalar values to array format for consistency
	foreach ( $modules as $module_id => $module_value ) {
		if ( ! is_array( $module_value ) ) {
			$modules[ $module_id ] = array( 'enabled' => (bool) $module_value );
			$needs_update = true;
		}
	}

	if ( ! isset( $modules['seo_analysis'] ) && isset( $modules['web_search'] ) ) {
		$modules['seo_analysis'] = $modules['web_search'];
		unset( $modules['web_search'] );
		$needs_update = true;
	}

	if ( ! isset( $modules['seo_analysis'] ) ) {
		$modules['seo_analysis'] = array( 'enabled' => true );
		$needs_update = true;
	}

	if ( ! isset( $modules['image_alt_generator'] ) ) {
		$modules['image_alt_generator'] = array( 'enabled' => true );
		$needs_update = true;
	}

	if ( ! isset( $modules['seo_optimization'] ) ) {
		$modules['seo_optimization'] = array(
			'enabled'                 => true,
			'enable_rank_math_fixes'  => true,
			'auto_apply'              => false,
			'allow_image_alt_updates' => false,
		);
		$needs_update = true;
	}

	$enabled_post_types = $settings['enabled_post_types'] ?? array();
	if ( smartypress_ai_is_woocommerce_product_post_type_available() && is_array( $enabled_post_types ) ) {
		$normalized_enabled_types = array_values( array_unique( array_map( 'sanitize_key', $enabled_post_types ) ) );
		$old_default_types        = array( 'page', 'post' );
		$sorted_enabled_types     = $normalized_enabled_types;

		sort( $sorted_enabled_types );

		if ( $sorted_enabled_types === $old_default_types && ! in_array( 'product', $normalized_enabled_types, true ) ) {
			$settings['enabled_post_types'] = array_merge( $normalized_enabled_types, array( 'product' ) );
			$needs_update = true;
		}
	}

	if ( $needs_update ) {
		$settings['modules'] = $modules;
		update_option( 'smartypress_ai_settings', $settings );
	}
}

/**
 * Migrate Yandex settings: handle the OAuth token -> service account API key transition.
 *
 * Older versions (<= 1.0.15) stored a Yandex OAuth token under the `yandex_oauth_token`
 * key and exchanged it for an IAM token. Since 1.0.16 the integration uses a service
 * account API key stored under `yandex_api_key`. The old token cannot be reused, so we
 * clean up the orphaned key and, when no new API key is configured yet, flag a one-time
 * admin notice asking the user to re-enter their Yandex API key.
 */
function smartypress_ai_migrate_yandex_settings() {
	$settings = get_option( 'smartypress_ai_settings', array() );

	if ( ! is_array( $settings ) || ! array_key_exists( 'yandex_oauth_token', $settings ) ) {
		return;
	}

	$had_oauth_token = ! empty( $settings['yandex_oauth_token'] );
	$has_api_key     = ! empty( $settings['yandex_api_key'] );

	// Flag the re-authentication notice only when an OAuth token was configured but no
	// new service account API key has been entered yet.
	if ( $had_oauth_token && ! $has_api_key ) {
		update_option( 'smartypress_ai_yandex_reauth_required', 1 );
	}

	// Remove the orphaned OAuth token key (it is no longer used).
	unset( $settings['yandex_oauth_token'] );
	update_option( 'smartypress_ai_settings', $settings );
}

/**
 * Initialize the plugin
 */
function smartypress_ai_init() {
	global $smartypress_ai_plugin;

	smartypress_ai_migrate_modules_settings();
	smartypress_ai_migrate_yandex_settings();

	// Ensure token usage table is up to date (handles plugin updates without reactivation).
	SmartyPress_AI_Token_Tracker::maybe_create_table();
	SmartyPress_AI_Token_Tracker::schedule_cleanup();

	// Initialize plugin loader
	if ( class_exists( 'SmartyPress_AI_Plugin_Loader' ) ) {
		$smartypress_ai_plugin = new SmartyPress_AI_Plugin_Loader( smartypress_ai_get_modules() );
		$smartypress_ai_plugin->run();
	}
}
add_action( 'init', 'smartypress_ai_init', 0 );

// Cron: clean up old token usage records.
add_action( SmartyPress_AI_Token_Tracker::CLEANUP_CRON_HOOK, array( 'SmartyPress_AI_Token_Tracker', 'cleanup' ) );

/**
 * Get available modules configuration.
 *
 * Module metadata (name, description, icon) is stored here so it is available
 * on the Components page even when the module is not active. Otherwise metadata
 * would only be available after the module's smartypress.php is loaded.
 * Called on init or later to avoid loading translations too early (WordPress 6.7+).
 *
 * @return array Modules configuration.
 */
function smartypress_ai_get_modules() {
	return array(
		'content_generator' => array(
			'autoload'      => 'includes/modules/content-generator/smartypress.php',
			'module_prefix' => 'SPAI_CG_',
			'name'          => __( 'Content Generator', 'smartypress-ai-engine' ),
			'description'   => __( 'Generate single posts and bulk content using AI. Includes Gutenberg Magic Wand integration.', 'smartypress-ai-engine' ),
			'icon'          => SMARTYPRESS_AI_PLUGIN_URL . 'assets/images/content-generator-icon.svg',
			'type'          => 'internal',
			'build'         => 'free',
			'admin_routes'  => array(
				array(
					'path'        => '/content-generation',
					'component'   => 'ContentGenerationPage',
					'title'       => __( 'Content Generation', 'smartypress-ai-engine' ),
					'menu_title'  => __( 'Content Generation', 'smartypress-ai-engine' ),
					'description' => __( 'Generate single posts or bulk content using AI', 'smartypress-ai-engine' ),
					'module'      => 'content_generator',
					'icon'        => 'admin-generic',
				),
			),
		),
		'image_generator'   => array(
			'autoload'      => 'includes/modules/image-generator/smartypress.php',
			'module_prefix' => 'SPAI_IG_',
			'name'          => __( 'Image Generator', 'smartypress-ai-engine' ),
			'description'   => __( 'Create images from text prompts. Saves to Media Library with auto-generated title, alt, and description. Regenerate any image with a correction prompt.', 'smartypress-ai-engine' ),
			'icon'          => SMARTYPRESS_AI_PLUGIN_URL . 'assets/images/image-generator-icon.svg',
			'type'          => 'internal',
			'build'         => 'free',
			'admin_routes'  => array(
				array(
					'path'        => '/image-generation',
					'component'   => 'ImageGenerationPage',
					'title'       => __( 'Image Generation', 'smartypress-ai-engine' ),
					'menu_title'  => __( 'Image Generation', 'smartypress-ai-engine' ),
					'description' => __( 'Generate images and thumbnails using AI', 'smartypress-ai-engine' ),
					'module'      => 'image_generator',
					'icon'        => 'image',
				),
			),
		),
		'image_alt_generator' => array(
			'autoload'      => 'includes/modules/image-alt-generator/smartypress.php',
			'module_prefix' => 'SPAI_IAG_',
			'name'          => __( 'Image ALT Generation', 'smartypress-ai-engine' ),
			'description'   => __( 'Generate SEO-friendly ALT text and captions for Media Library images in bulk or on upload.', 'smartypress-ai-engine' ),
			'icon'          => SMARTYPRESS_AI_PLUGIN_URL . 'assets/images/image-generator-icon.svg',
			'type'          => 'internal',
			'build'         => 'free',
			'admin_routes'  => array(
				array(
					'path'        => '/image-alt-generation',
					'component'   => 'ImageALTGenerationPage',
					'title'       => __( 'Image ALT Generation', 'smartypress-ai-engine' ),
					'menu_title'  => __( 'Image ALT generation', 'smartypress-ai-engine' ),
					'description' => __( 'Generate ALT text and captions for Media Library images', 'smartypress-ai-engine' ),
					'module'      => 'image_alt_generator',
					'icon'        => 'format-image',
				),
			),
		),
		'seo_analysis'      => array(
			'autoload'      => 'includes/modules/seo-analysis/smartypress.php',
			'module_prefix' => 'SPAI_SA_',
			'name'          => __( 'SEO Analysis', 'smartypress-ai-engine' ),
			'description'   => __( 'Adds competitor SEO analysis and research hooks for AI content plans.', 'smartypress-ai-engine' ),
			'icon'          => SMARTYPRESS_AI_PLUGIN_URL . 'assets/images/seo-analysis-icon.svg',
			'type'          => 'internal',
			'build'         => 'free',
			'admin_routes'  => array(),
		),
		'seo_optimization'  => array(
			'autoload'      => 'includes/modules/seo-optimization/smartypress.php',
			'module_prefix' => 'SPAI_SO_',
			'name'          => __( 'SEO Optimization', 'smartypress-ai-engine' ),
			'description'   => __( 'Fix SEO recommendations in supported SEO plugins using AI.', 'smartypress-ai-engine' ),
			'icon'          => SMARTYPRESS_AI_PLUGIN_URL . 'assets/images/seo-optimization-icon.svg',
			'type'          => 'internal',
			'build'         => 'free',
			'admin_routes'  => array(),
		),
	);
}

/**
 * Get language name by WordPress locale.
 * Used for default writing language when user hasn't overridden in settings.
 *
 * @param string|null $locale WordPress locale (e.g. ru_RU, en_US). Default: get_locale().
 * @return string Language name (e.g. Russian, English).
 */
function smartypress_ai_get_language_by_locale( $locale = null ) {
	if ( null === $locale ) {
		$locale = get_locale();
	}
	$languages = array(
		'ru_RU'  => 'Russian',
		'en_US'  => 'English',
		'en_GB'  => 'English',
		'de_DE'  => 'German',
		'fr_FR'  => 'French',
		'es_ES'  => 'Spanish',
		'it_IT'  => 'Italian',
		'pt_BR'  => 'Portuguese',
		'pt_PT'  => 'Portuguese',
		'zh_CN'  => 'Chinese',
		'ja'     => 'Japanese',
		'ko_KR'  => 'Korean',
		'ar'     => 'Arabic',
		'nl_NL'  => 'Dutch',
		'pl_PL'  => 'Polish',
		'tr_TR'  => 'Turkish',
		'uk'     => 'Ukrainian',
		'hi_IN'  => 'Hindi',
		'id_ID'  => 'Indonesian',
		'vi'     => 'Vietnamese',
	);
	return isset( $languages[ $locale ] ) ? $languages[ $locale ] : 'English';
}

/**
 * Activation hook
 */
function smartypress_ai_activate() {
	// Set default options
	$default_options = array(
		'openai_api_key'       => '',
		'openai_model'         => 'gpt-4o',
		'deepseek_api_key'     => '',
		'deepseek_model'       => 'deepseek-v4-flash',
		'anthropic_api_key'    => '',
		'anthropic_model'      => 'claude-sonnet-4-5',
		'openrouter_api_key'   => '',
		'openrouter_model'     => 'openai/gpt-4o-mini',
		'openrouter_image_model' => 'google/gemini-2.5-flash-image',
		'openrouter_limit_text_models' => false,
		'openrouter_enabled_text_models' => array(),
		'openrouter_limit_image_models' => false,
		'openrouter_enabled_image_models' => array(),
		'yandex_api_key'       => '',
		'yandex_folder_id'     => '',
		'yandex_model'         => 'yandexgpt-lite',
		'gigachat_auth_key'    => '',
		'gigachat_scope'       => 'GIGACHAT_API_PERS',
		'gigachat_base_url'    => 'https://gigachat.devices.sberbank.ru/api/v1',
		'gigachat_model'       => 'GigaChat-2',
		'gigachat_verify_ssl'  => false,
		'provider_connection_status' => array(),
		'default_provider'     => 'openai',
		'default_language'     => '', // Empty = use site locale
		'temperature'          => 0.7,
		'max_tokens'           => 2000,
		'prompt_variables'     => array(
			'writing_tone'           => 'neutral',
			'writing_style'          => 'informative',
			'number_of_sections'     => '3',
			'paragraphs_per_section' => '3',
		),
		'enabled_post_types'   => smartypress_ai_get_default_enabled_post_types(),
		'modules'              => array(
			'content_generator' => true, // Enabled by default
			'image_generator'   => true, // Enabled by default
			'seo_analysis'      => true, // Enabled by default
			'seo_optimization'  => array(
				'enabled'                 => true,
				'enable_rank_math_fixes'  => true,
				'auto_apply'              => false,
				'allow_image_alt_updates' => false,
			),
		),
	);

	if ( ! get_option( 'smartypress_ai_settings' ) ) {
		add_option( 'smartypress_ai_settings', $default_options );
	}

	if ( ! get_option( 'smartypress_ai_activated_at' ) ) {
		add_option( 'smartypress_ai_activated_at', time() );
	}

	// Create token usage table.
	SmartyPress_AI_Token_Tracker::create_table();
	SmartyPress_AI_Token_Tracker::schedule_cleanup();

	$image_alt_index_manager = SMARTYPRESS_AI_PLUGIN_DIR . 'includes/modules/image-alt-generator/class-image-alt-index-manager.php';
	if ( file_exists( $image_alt_index_manager ) ) {
		require_once $image_alt_index_manager;
		if ( class_exists( 'SmartyPress_AI_Image_ALT_Index_Manager' ) ) {
			SmartyPress_AI_Image_ALT_Index_Manager::create_table();
		}
	}
}
register_activation_hook( __FILE__, 'smartypress_ai_activate' );

/**
 * Deactivation hook
 */
function smartypress_ai_deactivate() {
	SmartyPress_AI_Token_Tracker::unschedule_cleanup();
}
register_deactivation_hook( __FILE__, 'smartypress_ai_deactivate' );
