<?php
/**
 * Plugin Name: Opti-Behavior – Self-Hosted Heatmaps, Session Recordings, Funnels & A/B Testing
 * Plugin URI:  https://optiuser.com/
 * Description: Self-hosted heatmaps, click tracking, session recordings & visitor analytics for WordPress. GDPR & CCPA Ready, no session limits, zero data sharing. The privacy-first Hotjar & Google Analytics alternative.
 * Version:     1.3.1
 * Author:      OptiUser
 * Author URI:  https://optiuser.com/
 * License:     GPLv2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: opti-behavior
 * Domain Path: /languages
 * Requires PHP: 7.4
 *
 * @package opti-behavior
 * @copyright 2025-2026 OptiUser
 * @version 1.3.1
 */

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

// Check PHP version compatibility.
if ( version_compare( PHP_VERSION, '7.4', '<' ) ) {
	add_action( 'admin_notices', 'opti_behavior_php_version_notice' );
	/**
	 * Display admin notice for incompatible PHP version.
	 *
	 * Shows an error message when the server is running an incompatible PHP version
	 * and automatically deactivates the plugin.
	 *
	 * @since 1.0.4
	 */
	function opti_behavior_php_version_notice() {
		?>
		<div class="notice notice-error">
			<p>
				<?php
				printf(
					/* translators: 1: Required PHP version, 2: Current PHP version */
					esc_html__( 'Opti-Behavior requires PHP version %1$s or higher. You are running PHP version %2$s. Please upgrade PHP to activate this plugin.', 'opti-behavior' ),
					'7.4',
					esc_html( PHP_VERSION )
				);
				?>
			</p>
		</div>
		<?php
		// Deactivate the plugin.
		if ( function_exists( 'deactivate_plugins' ) ) {
			deactivate_plugins( plugin_basename( __FILE__ ) );
		}
	}
	return;
}

if ( ! function_exists( 'opti_behavior_heatmap_conflict' ) ) {
	/**
	 * Display error message when plugin conflict is detected.
	 *
	 * Terminates execution and displays a user-friendly error message
	 * when another version of the plugin is already active.
	 *
	 * @since 1.0.0
	 */
	function opti_behavior_heatmap_conflict() {
		die( esc_html__( 'Fail to activate. Another version of opti-behavior Heatmap is already active.', 'opti-behavior' ) );
	}
}

// Check for plugin conflicts.
if ( defined( 'OPTI_BEHAVIOR_HEATMAP' ) ) {
	if ( is_admin() ) {
		register_activation_hook( __FILE__, 'opti_behavior_heatmap_conflict' );
	}
	return;
} else {
	define( 'OPTI_BEHAVIOR_HEATMAP', __FILE__ );
}

// Define plugin constants.
define( 'OPTI_BEHAVIOR_HEATMAP_VERSION', '1.3.1' );
define( 'OPTI_BEHAVIOR_HEATMAP_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'OPTI_BEHAVIOR_HEATMAP_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
define( 'OPTI_BEHAVIOR_HEATMAP_INCLUDES_DIR', OPTI_BEHAVIOR_HEATMAP_PLUGIN_DIR . 'includes/' );
define( 'OPTI_BEHAVIOR_HEATMAP_ADMIN_DIR', OPTI_BEHAVIOR_HEATMAP_PLUGIN_DIR . 'admin/' );
define( 'OPTI_BEHAVIOR_HEATMAP_PUBLIC_DIR', OPTI_BEHAVIOR_HEATMAP_PLUGIN_DIR . 'public/' );
define( 'OPTI_BEHAVIOR_HEATMAP_ASSETS_URL', OPTI_BEHAVIOR_HEATMAP_PLUGIN_URL . 'assets/' );

/**
 * API Environment Configuration
 * Set the environment for API connections:
 * - 'local'  => Uses http://localhost/API/ for local development
 * - 'live'   => Uses https://api.optiuser.com/ for production (default)
 *
 * Change this value to switch between local and live API servers.
 */
if ( ! defined( 'OPTI_BEHAVIOR_ENVIRONMENT' ) ) {
	define( 'OPTI_BEHAVIOR_ENVIRONMENT', 'live' ); // Options: 'local' or 'live'
}

// Initialize autoloader.
require_once __DIR__ . '/includes/class-autoloader.php';
Opti_Behavior_Heatmap_Autoloader::init( __DIR__ );

// Load tooltip helper functions.
require_once __DIR__ . '/includes/tooltip-helper.php';

// Load dashboard cache helpers (TTL + invalidation).
require_once __DIR__ . '/includes/opti-behavior-dashboard-cache.php';

// Load welcome/consent class early so its activation hook fires on plugin activation.
require_once __DIR__ . '/includes/class-opti-behavior-welcome.php';

// Load onboarding popup class (shown on dashboard after first activation with no data).
require_once __DIR__ . '/includes/class-opti-behavior-onboarding.php';

// Load delayed WordPress.org review reminder banner.
require_once __DIR__ . '/includes/class-opti-behavior-review-banner.php';

// Register plugin hooks.
register_activation_hook( __FILE__, 'Opti_Behavior_Heatmap_Core::activation' );
register_activation_hook( __FILE__, array( 'Opti_Behavior_Welcome', 'on_activation' ) );
register_activation_hook( __FILE__, array( 'Opti_Behavior_Review_Banner', 'on_activation' ) );
register_deactivation_hook( __FILE__, 'Opti_Behavior_Heatmap_Core::deactivation' );

/**
 * Override text domain loading to use custom locale for Opti-Behavior pages.
 *
 * @since 1.0.0
 */
add_filter(
	'override_load_textdomain',
	function( $override, $domain, $mofile ) {
		// Only apply to opti-behavior and opti-behavior-pro text domains
		if ( $domain !== 'opti-behavior' && $domain !== 'opti-behavior-pro' ) {
			return $override;
		}

		// Only apply on admin pages
		if ( ! is_admin() ) {
			return $override;
		}

		// Check if we're on an Opti-Behavior admin page
		// phpcs:disable WordPress.Security.NonceVerification.Recommended -- GET parameter used for page identification (read-only operation)
		$current_page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		$opti_behavior_pages = array(
			'opti-behavior-analytics',
			'opti-behavior-heatmaps',
			'opti-behavior-heatmap-detail',
			'opti-behavior-settings',
			'opti-behavior-ai-insights',
			'opti-behavior-funnels',
			'opti-behavior-ab-testing',
		);

		// Add PRO pages if PRO version is active
		if ( opti_behavior_pro_active() ) {
			$opti_behavior_pages[] = 'opti-behavior-recordings';
			$opti_behavior_pages[] = 'opti-behavior-errors';
			$opti_behavior_pages[] = 'opti-behavior-user-journey';
		}

		// Check if we're doing an AJAX request for Opti-Behavior
		$is_opti_behavior_ajax = false;
		if ( wp_doing_ajax() ) {
			// phpcs:disable WordPress.Security.NonceVerification.Missing -- POST parameter used for action identification only (read-only operation, nonce verified in actual AJAX handlers)
			$ajax_action = isset( $_POST['action'] ) ? sanitize_text_field( wp_unslash( $_POST['action'] ) ) : '';
			// phpcs:enable WordPress.Security.NonceVerification.Missing
			if ( strpos( $ajax_action, 'opti_behavior' ) === 0 || strpos( $ajax_action, 'optibehavior' ) === 0 ) {
				$is_opti_behavior_ajax = true;
			}
		}

		if ( ! in_array( $current_page, $opti_behavior_pages, true ) && ! $is_opti_behavior_ajax ) {
			return $override; // Return original for non-plugin pages
		}

		// Get the saved language preference
		$selected_language = get_option( 'opti_behavior_admin_language', 'en_US' );

		// Whitelist of allowed languages
		$allowed_languages = array( 'en_US', 'fr_FR', 'de_DE', 'es_ES', 'pt_BR', 'it_IT' );

		// Validate against whitelist
		if ( ! in_array( $selected_language, $allowed_languages, true ) ) {
			$selected_language = 'en_US'; // Default to English if invalid
		}

		// If English is selected, prevent loading any translation file
		if ( $selected_language === 'en_US' ) {
			// Get debug manager if available
			if ( class_exists( 'Opti_Behavior_Heatmap_Core' ) ) {
				$core = Opti_Behavior_Heatmap_Core::get_instance();
				$debug_manager = $core->get_debug_manager();
				$debug_manager->log( 'English selected - preventing translation file load', 'debug', 'i18n' );
			}
			return true; // Tell WordPress we handled it (by not loading any translations)
		}

		// If a non-English language is selected, load the custom .mo file
		// Determine the plugin directory based on the domain
		if ( $domain === 'opti-behavior-pro' ) {
			$plugin_dir = dirname( __FILE__ ) . '/../opti-behavior-pro';
		} else {
			$plugin_dir = dirname( __FILE__ );
		}

		$custom_mofile = $plugin_dir . '/languages/' . $domain . '-' . $selected_language . '.mo';

		// Get debug manager if available
		if ( class_exists( 'Opti_Behavior_Heatmap_Core' ) ) {
			$core = Opti_Behavior_Heatmap_Core::get_instance();
			$debug_manager = $core->get_debug_manager();
			$debug_manager->log( 'Override load textdomain. Domain: ' . $domain . ', Original: ' . $mofile . ', Custom: ' . $custom_mofile . ' (exists: ' . ( file_exists( $custom_mofile ) ? 'yes' : 'no' ) . ')', 'debug', 'i18n' );
		}

		if ( file_exists( $custom_mofile ) ) {
			// Use WordPress's MO class to load the custom .mo file
			global $l10n;

			// Create a new MO object and load the custom .mo file
			$mo = new MO();
			if ( $mo->import_from_file( $custom_mofile ) ) {
				$l10n[ $domain ] = $mo;

				// Log success
				if ( class_exists( 'Opti_Behavior_Heatmap_Core' ) ) {
					$core = Opti_Behavior_Heatmap_Core::get_instance();
					$debug_manager = $core->get_debug_manager();
					$debug_manager->log( 'Successfully loaded custom .mo file for domain "' . $domain . '" with ' . count( $mo->entries ) . ' translations', 'info', 'i18n' );
				}

				return true; // Tell WordPress we handled the loading
			} else {
				// Log failure
				if ( class_exists( 'Opti_Behavior_Heatmap_Core' ) ) {
					$core = Opti_Behavior_Heatmap_Core::get_instance();
					$debug_manager = $core->get_debug_manager();
					$debug_manager->log( 'Failed to import .mo file for domain "' . $domain . '": ' . $custom_mofile, 'error', 'i18n' );
				}
			}
		}

		return $override; // Let WordPress handle the default loading
	},
	10,
	3
);

/**
 * Force reload translations BEFORE admin menus are registered.
 * This must run on admin_menu with priority 1 (before menus at priority 10+).
 *
 * @since 2.3.6
 */
add_action(
	'admin_menu',
	function() {
		// Get the saved language preference
		$selected_language = get_option( 'opti_behavior_admin_language', 'en_US' );

		// If English, no need to reload
		if ( $selected_language === 'en_US' ) {
			return;
		}

		// Whitelist of allowed languages
		$allowed_languages = array( 'en_US', 'fr_FR', 'de_DE', 'es_ES', 'pt_BR', 'it_IT' );
		if ( ! in_array( $selected_language, $allowed_languages, true ) ) {
			return;
		}

		// Force reload translations for both domains
		global $l10n;

		// Reload opti-behavior translations
		$free_mofile = dirname( __FILE__ ) . '/languages/opti-behavior-' . $selected_language . '.mo';
		if ( file_exists( $free_mofile ) ) {
			$mo = new MO();
			if ( $mo->import_from_file( $free_mofile ) ) {
				$l10n['opti-behavior'] = $mo;
			}
		}

		// Reload opti-behavior-pro translations if PRO is active
		if ( opti_behavior_pro_active() ) {
			$pro_mofile = dirname( __FILE__ ) . '/../opti-behavior-pro/languages/opti-behavior-pro-' . $selected_language . '.mo';
			if ( file_exists( $pro_mofile ) ) {
				$mo = new MO();
				if ( $mo->import_from_file( $pro_mofile ) ) {
					$l10n['opti-behavior-pro'] = $mo;
				}
			}
		}
	},
	1 // Run BEFORE menus are registered (priority 10+)
);

/**
 * Initialize plugin core and performance optimizer.
 *
 * @since 1.0.0
 */
add_action(
	'init',
	function() {
		$core = Opti_Behavior_Heatmap_Core::get_instance();

		// Initialize performance optimizer
		require_once OPTI_BEHAVIOR_HEATMAP_INCLUDES_DIR . 'class-opti-behavior-performance-optimizer.php';

		// License manager is now in Pro plugin (opti-behavior-pro)
		// It will be loaded by the Pro plugin if active

		// Manifest manager is now in Pro plugin (opti-behavior-pro)
		// It will be loaded by the Pro plugin if active
		// Free plugin has unlimited features - no need for limit checking

		// Initialize file storage
		require_once OPTI_BEHAVIOR_HEATMAP_INCLUDES_DIR . 'class-opti-behavior-heatmap-file-storage.php';

		// Initialize welcome/consent flow (must run before tracker).
		Opti_Behavior_Welcome::init();

		// Initialize onboarding popup (shown on dashboard when no data exists).
		Opti_Behavior_Onboarding::init();

		// Initialize delayed WordPress.org review reminder banner.
		Opti_Behavior_Review_Banner::init();

		// Initialize plugin tracker (works for both Free-only and Free+Pro setups)
		// Sends installation data with 24h heartbeat, auto-detects plugin type
		require_once OPTI_BEHAVIOR_HEATMAP_INCLUDES_DIR . 'class-opti-behavior-free-tracker.php';
		Opti_Behavior_Free_Tracker::init();

		// Initialize broadcast banner manager (API-driven in-plugin messages)
		require_once OPTI_BEHAVIOR_HEATMAP_INCLUDES_DIR . 'class-opti-behavior-broadcast.php';
		Opti_Behavior_Broadcast::init();

		// Session recording is now a PRO feature
		// It will be initialized by opti-behavior-pro plugin if active
	}
);

/**
 * Check if Pro plugin files are present.
 * This checks if the Pro plugin code exists, but features are gated by the signed manifest.
 *
 * @since 1.0.0
 * @return bool True if Pro plugin is active, false otherwise.
 */
if ( ! function_exists( 'opti_behavior_pro_active' ) ) {
	function opti_behavior_pro_active() {
		return defined( 'OPTI_BEHAVIOR_PRO_VERSION' );
	}
}

/**
 * Add custom cron intervals for scheduled reports.
 *
 * @since 1.1.0
 * @param array $schedules Existing schedules.
 * @return array Modified schedules.
 */
add_filter(
	'cron_schedules',
	function( $schedules ) {
		if ( ! isset( $schedules['every_fifteen_minutes'] ) ) {
			$schedules['every_fifteen_minutes'] = array(
				'interval' => 15 * MINUTE_IN_SECONDS,
				'display'  => __( 'Every 15 Minutes', 'opti-behavior' ),
			);
		}
		return $schedules;
	}
);
