<?php
/**
 * Plugin Name: WowRecommend - AI-Powered Product Recommendations for WooCommerce
 * Description: Create smart product recommendations for WooCommerce with AI rule builder, advanced filters, sorting, popup upsells, checkout order bumps, and more.
 * Version:     1.0.5
 * Requires at least: 6.9
 * Requires PHP: 7.4
 * WC requires at least: 6.0
 * WC tested up to: 11.0
 * Author:      WPXPO
 * Author URI:  https://www.wpxpo.com/about
 * Text Domain: wow-ai-product-recommendations
 * Requires Plugins: woocommerce
 * License:     GPLv3
 * License URI: http://www.gnu.org/licenses/gpl-3.0.html
 *
 * @package ProductRecommendations
 */

use PRECO\Includes\Common\Functions;
use PRECO\Includes\Initialization;

defined( 'ABSPATH' ) || exit;

// Define Vars.
define( 'PRECO_VER', '1.0.5' );
define( 'PRECO_URL', plugin_dir_url( __FILE__ ) );
define( 'PRECO_BASE', plugin_basename( __FILE__ ) );
define( 'PRECO_PATH', plugin_dir_path( __FILE__ ) );

// Preview-mode product source for the admin builder's live iframe: 'real'
// (default) evaluates each recommendation list's actual filter rules against
// the store and falls back to placeholder products + a notice when nothing
// matches; 'dummy' forces the old always-placeholder behavior. Flip this to
// compare the two while testing — see PreviewMode::use_real_products().
defined( 'PRECO_PREVIEW_MODE' ) || define( 'PRECO_PREVIEW_MODE', 'real' );

spl_autoload_register( 'preco_autoloader' );

register_activation_hook( __FILE__, 'preco_activate_plugin' );
register_deactivation_hook( __FILE__, 'preco_deactivate_plugin' );

/**
 * Deactivation: unschedule cron events.
 */
function preco_deactivate_plugin() {
	wp_clear_scheduled_hook( 'preco_cleanup_user_events' );
}

/**
 * Declare WooCommerce High-Performance Order Storage (HPOS) compatibility.
 */
add_action(
	'before_woocommerce_init',
	function () {
		if ( class_exists( \Automattic\WooCommerce\Utilities\FeaturesUtil::class ) ) {
			\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true );
		}
	}
);

/**
 * Activation: create plugin tables, bootstrap onboarding, flag for redirect.
 *
 * @return void
 */
function preco_activate_plugin() {
	\PRECO\Includes\Frontend\UserEvents\UserEventsTable::create_table();
	\PRECO\Includes\Analytics\AnalyticsTable::create_table();
	\PRECO\Includes\Admin\Onboarding::maybe_bootstrap();

	// Consumed once by Admin::maybe_activation_redirect() on the next
	// admin_init to send the user to the Overview page.
	set_transient( 'preco_activation_redirect', true, 30 );
}

if ( ! function_exists( 'product_recommend' ) ) {
	/**
	 * Access the plugin's public helper functions.
	 *
	 * @return Functions
	 */
	function product_recommend() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Public helper alias kept unprefixed for API ergonomics; wrapped in function_exists() to avoid collisions.
		return new Functions();
	}
}

add_action( 'plugins_loaded', 'preco_init_plugin', 10 );
/**
 * Bootstrap the plugin: fallback table creation, then core initialization.
 *
 * @return void
 */
function preco_init_plugin() {
	// Fallback table creation in case the activation hook did not fire
	// (e.g. plugin activated via WP-CLI, network activation, or the hook
	// was skipped due to a fatal error at activation time).
	//
	// Two-gate strategy (zero DB cost on normal requests):
	// Gate 1 — get_option(): served from WP object cache, no DB hit.
	// Gate 2 — SHOW TABLES: only runs when the option is absent,
	// confirming the table truly doesn't exist before creating it.
	//
	// Map: version_option_key => [ table_name_without_prefix, FQCN ]
	// To add a new table, append one entry here.
	$tables = array(
		'preco_user_events_table_version'      => array( 'preco_user_events', \PRECO\Includes\Frontend\UserEvents\UserEventsTable::class ),
		'preco_analytics_events_table_version' => array( 'preco_analytics_events', \PRECO\Includes\Analytics\AnalyticsTable::class ),
	);

	global $wpdb;
	foreach ( $tables as $version_key => $config ) {
		// Gate 1: cheap option check (object-cached after first read).
		if ( get_option( $version_key ) ) {
			continue;
		}

		// Gate 2: option missing — verify with a real DB query before creating.
		$full_name = $wpdb->prefix . $config[0];
		$class     = $config[1];

		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
		if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $full_name ) ) !== $full_name ) {
			$class::create_table();
		}
		// phpcs:enable
	}

	new Initialization();
}

/**
 * PSR-4-ish autoloader for the PRECO\ namespace.
 *
 * @param string $class_name Fully-qualified class name being loaded.
 * @return void
 */
function preco_autoloader( $class_name ) {
	$namespace = 'PRECO\\';
	$base_dir  = trailingslashit( PRECO_PATH );

	$len = strlen( $namespace );
	if ( strncmp( $namespace, $class_name, $len ) !== 0 ) {
		return;
	}

	$relative_class = substr( $class_name, $len );
	$segments       = explode( '\\', $relative_class );

	$file_name = array_pop( $segments );
	$subfolder = strtolower(
		implode(
			'/',
			array_map(
				function ( $segment ) {
					// Convert camelCase to kebab-case.
					$segment = preg_replace( '/([a-z])([A-Z])/', '$1-$2', $segment );
					// Convert underscores to dashes.
					return str_replace( '_', '-', $segment );
				},
				$segments
			)
		)
	);

	$prefix    = ( strpos( $subfolder, 'traits' ) !== false ) ? 'trait-' : 'class-';
	$file_name = strtolower(
		preg_replace(
			'/([a-z])([A-Z])/',
			'$1-$2',
			str_replace( '_', '-', $file_name )
		)
	);

	$file = rtrim( $base_dir . $subfolder, '/' ) . '/' . $prefix . $file_name . '.php';

	if ( file_exists( $file ) ) {
		require_once $file;
	}
}
