<?php
// phpcs:disable WordPress.WP.I18n.TextDomainMismatch
// Text domain 'activetrail-for-woocommerce' is correct per WordPress review requirements.
/**
 * Main ActiveTrail Plugin Class
 *
 * @package ActiveTrail_WooCommerce
 * @since 1.0.0
 */

// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Main ActiveTrail Plugin Class
 */
class ActiveTrail_Plugin {

	/**
	 * Plugin instance
	 *
	 * @var ActiveTrail_Plugin
	 */
	private static $instance = null;

	/**
	 * Plugin settings
	 *
	 * @var array
	 */
	private $settings;

	/**
	 * API Client instance
	 *
	 * @var ActiveTrail_API_Client
	 */
	private $api_client;

	/**
	 * Order Handler instance
	 *
	 * @var ActiveTrail_Order_Handler
	 */
	private $order_handler;

	/**
	 * Cart Handler instance
	 *
	 * @var ActiveTrail_Cart_Handler
	 */
	private $cart_handler;

	/**
	 * Coupon Handler instance
	 *
	 * @var ActiveTrail_Coupon_Handler
	 */
	private $coupon_handler;

	/**
	 * Event Handler instance
	 *
	 * @var ActiveTrail_Event_Handler
	 */
	private $event_handler;

	/**
	 * User Registration Handler instance
	 *
	 * @var ActiveTrail_User_Registration_Handler
	 */
	private $user_registration_handler;

	/**
	 * Historical Sync Handler instance
	 *
	 * @var ActiveTrail_Historical_Sync_Handler
	 */
	private $historical_sync_handler;

	/**
	 * Get plugin instance
	 *
	 * @return ActiveTrail_Plugin
	 */
	public static function get_instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Constructor
	 */
	private function __construct() {
		$this->load_dependencies();
		$this->load_settings(); // Load settings first
		$this->init_hooks();
		$this->init_components();
	}

	/**
	 * Load plugin dependencies
	 */
	private function load_dependencies() {
		// Load API client.
		require_once ACTIVETRAIL_WC_PLUGIN_DIR . 'includes/api/class-activetrail-api-client.php';

		// Load helpers (before services that use them).
		require_once ACTIVETRAIL_WC_PLUGIN_DIR . 'includes/helpers/class-activetrail-consent-helper.php';

		// Load service handlers.
		require_once ACTIVETRAIL_WC_PLUGIN_DIR . 'includes/services/class-order-handler.php';
		require_once ACTIVETRAIL_WC_PLUGIN_DIR . 'includes/services/class-cart-handler.php';
		require_once ACTIVETRAIL_WC_PLUGIN_DIR . 'includes/services/class-coupon-handler.php';
		require_once ACTIVETRAIL_WC_PLUGIN_DIR . 'includes/services/class-event-handler.php';
		require_once ACTIVETRAIL_WC_PLUGIN_DIR . 'includes/services/class-user-registration-handler.php';
		require_once ACTIVETRAIL_WC_PLUGIN_DIR . 'includes/services/class-catalog-handler.php';
		require_once ACTIVETRAIL_WC_PLUGIN_DIR . 'includes/services/class-historical-sync-handler.php';

		// Load settings.
		require_once ACTIVETRAIL_WC_PLUGIN_DIR . 'includes/settings/class-settings.php';

		// Always load admin components (needed for WooCommerce settings hooks).
		require_once ACTIVETRAIL_WC_PLUGIN_DIR . 'admin/class-admin-page.php';
	}

	/**
	 * Initialize WordPress hooks
	 */
	private function init_hooks() {
		// Text domain loading is handled in the main plugin file on 'init' hook.
		// to avoid triggering WooCommerce translations too early.

		// Admin hooks.
		if ( is_admin() ) {
			add_action( 'admin_init', array( $this, 'init_admin' ) );
		}

		// Frontend hooks.
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_scripts' ) );
		add_action( 'wp_footer', array( $this, 'output_checkout_inline_styles' ), 999 );

		// AJAX hooks.
		add_action( 'wp_ajax_activetrail_test_api', array( $this, 'ajax_test_api' ) );
		add_action( 'wp_ajax_activetrail_get_groups', array( $this, 'ajax_get_groups' ) );
		add_action( 'wp_ajax_activetrail_save_group', array( $this, 'ajax_save_group' ) );
		add_action( 'wp_ajax_activetrail_get_debug_info', array( $this, 'ajax_get_debug_info' ) );

		// Product feed endpoint.
		// 1) מוסיפים rewrite rules ל-/activetrail-feed.xml ו-/activetrail-feed.json
		// 2) רושמים query var בשם activetrail_feed כדי ש-WordPress לא יזרוק אותו
		// 3) ב-template_redirect בודקים את ה-query var ומחזירים XML/JSON בפועל.
		add_action( 'init', array( $this, 'add_feed_endpoint' ) );
		add_filter( 'query_vars', array( $this, 'add_feed_query_var' ) );
		add_action( 'template_redirect', array( $this, 'handle_feed_request' ) );

		// Product sync hooks.
		add_action( 'activetrail_sync_products', array( $this, 'handle_scheduled_product_sync' ) );

		// Checkout hooks.
		add_action( 'woocommerce_checkout_fields', array( $this, 'add_checkout_consent_field' ) );
		add_action( 'woocommerce_checkout_process', array( $this, 'validate_checkout_consent' ) );
		add_action( 'woocommerce_checkout_update_order_meta', array( $this, 'save_checkout_consent' ) );
		add_filter( 'woocommerce_form_field', array( $this, 'remove_optional_text_from_consent_field' ), 9999, 4 );
	}

	/**
	 * Initialize plugin components
	 */
	private function init_components() {
		// Initialize API client.
		$this->api_client = new ActiveTrail_API_Client( $this->get_setting( 'api_key' ) );

		// Initialize admin page (needed for WooCommerce settings hooks).
		$admin_page = new ActiveTrail_Admin_Page( $this->api_client );

		// Initialize handlers.
		$this->order_handler  = new ActiveTrail_Order_Handler( $this->api_client, $this->settings );
		$this->cart_handler   = new ActiveTrail_Cart_Handler( $this->api_client, $this->settings );
		$this->coupon_handler = new ActiveTrail_Coupon_Handler( $this->api_client, $this->settings );
		$this->event_handler  = new ActiveTrail_Event_Handler( $this->api_client, $this->settings );

		// Initialize user registration handler.
		$this->user_registration_handler = new ActiveTrail_User_Registration_Handler( $this->api_client, $this->settings );

		// Initialize historical sync handler.
		$this->historical_sync_handler = new ActiveTrail_Historical_Sync_Handler( $this->api_client, $this->settings );

		// Initialize catalog handler.
		new ActiveTrail_Catalog_Handler( $this->api_client, $this->settings );
	}

	/**
	 * Load plugin text domain
	 *
	 * Note: Text domain loading is now handled in the main plugin file (activetrail-for-woocommerce.php)
	 * on the 'init' hook to avoid triggering WooCommerce translations too early.
	 * This method is kept for backward compatibility but does nothing.
	 */
	public function load_textdomain() {
		// Text domain is loaded in activetrail_wc_load_textdomain() on 'init' hook.
		// No action needed here to prevent duplicate loading.
	}

	/**
	 * Load plugin settings
	 */
	public function load_settings() {
		$this->settings = get_option( 'activetrail_wc_settings', array() );

		// Merge with defaults (without translations for now).
		$defaults = array(
			'api_key'                     => '',
			'group_id'                    => '',
			'order_statuses'              => array( 'completed' ),
			'enable_checkout_consent'     => true,
			'consent_text'                => 'I agree to receive marketing emails', // Will be translated later
			'enable_registration_consent' => false,
			'sync_without_consent'        => false,
		);

		$this->settings = wp_parse_args( $this->settings, $defaults );
	}

	/**
	 * Initialize admin components
	 */
	public function init_admin() {
		// Admin page is already initialized in init_components().
		// This method is kept for compatibility but does nothing.
	}

	/**
	 * Enqueue frontend scripts
	 */
	public function enqueue_frontend_scripts() {
		// Load on checkout and registration pages.
		if ( is_checkout() || is_account_page() || is_page( 'my-account' ) ) {
			// Define ajaxurl for frontend.
			wp_enqueue_script(
				'activetrail-ajax',
				ACTIVETRAIL_WC_PLUGIN_URL . 'assets/js/ajax-handler.js',
				array( 'jquery' ),
				ACTIVETRAIL_WC_VERSION,
				true
			);

			// Localize script to provide ajaxurl and consent validation params.
			wp_localize_script(
				'activetrail-ajax',
				'activetrail_params',
				array(
					'ajaxurl'                 => admin_url( 'admin-ajax.php' ),
					'nonce'                   => wp_create_nonce( 'activetrail_nonce' ),
					'consent_required'         => false,
					'consent_required_message' => __( 'You must approve marketing emails in order to continue.', 'activetrail-for-woocommerce' ),
				)
			);

			wp_enqueue_script(
				'activetrail-checkout',
				ACTIVETRAIL_WC_PLUGIN_URL . 'assets/js/checkout.js',
				array( 'jquery', 'activetrail-ajax' ),
				ACTIVETRAIL_WC_VERSION,
				true
			);

			wp_enqueue_style(
				'activetrail-checkout',
				ACTIVETRAIL_WC_PLUGIN_URL . 'assets/css/checkout.css',
				array(),
				ACTIVETRAIL_WC_VERSION
			);
		}
	}

	/**
	 * Output late inline styles + JS fix for the checkout consent checkbox.
	 * Runs at wp_footer priority 999 — after Elementor's dynamic CSS injection —
	 * so our rules are the last in the cascade. The JS fallback sets inline styles
	 * directly, which beats any CSS rule regardless of load order.
	 */
	public function output_checkout_inline_styles() {
		// No custom overrides — consent checkbox uses theme/WooCommerce default styling.
	}

	/**
	 * AJAX handler for testing API connection
	 */
	public function ajax_test_api() {
		check_ajax_referer( 'activetrail_admin_nonce', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Insufficient permissions', 'activetrail-for-woocommerce' ) );
		}

		$api_key     = isset( $_POST['api_key'] ) ? sanitize_text_field( wp_unslash( $_POST['api_key'] ) ) : '';
		$test_client = new ActiveTrail_API_Client( $api_key );

		$result = $test_client->test_connection();

		// Update connection status in settings.
		ActiveTrail_Settings::update_connection_status( $result['success'], $result['message'] );

		wp_send_json( $result );
	}

	/**
	 * AJAX handler for getting groups
	 */
	public function ajax_get_groups() {
		check_ajax_referer( 'activetrail_admin_nonce', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Insufficient permissions', 'activetrail-for-woocommerce' ) );
		}

		$api_key = isset( $_POST['api_key'] ) ? sanitize_text_field( wp_unslash( $_POST['api_key'] ) ) : '';

		$force_refresh = isset( $_POST['force_refresh'] ) && sanitize_text_field( wp_unslash( $_POST['force_refresh'] ) );

		// Page number for pagination (default 1).
		$page  = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
		if ( $page < 1 ) {
			$page = 1;
		}
		$limit = 20;

		// If force refresh is requested, clear cache first.
		if ( $force_refresh ) {
			ActiveTrail_Settings::clear_groups_cache();
			if ( function_exists( 'activetrail_logger' ) ) {
				activetrail_logger()->info( 'Force refresh requested - cache cleared', 'GENERAL' );
			}
		}

		// Always call the API directly with Page + Limit (same as Refresh Groups but paginated).
		ActiveTrail_Settings::update( 'api_key', $api_key );
		require_once ACTIVETRAIL_WC_PLUGIN_DIR . 'includes/api/class-activetrail-api-client.php';
		$api_client = new ActiveTrail_API_Client( $api_key );
		$result     = $api_client->get_groups( array( 'Page' => $page, 'Limit' => $limit ) );

		if ( function_exists( 'activetrail_logger' ) ) {
			activetrail_logger()->info( 'Groups fetched from API - Page: ' . $page . ', Count: ' . ( isset( $result['data'] ) ? count( $result['data'] ) : 0 ), 'GENERAL' );
		}

		if ( ! $result['success'] ) {
			wp_send_json_error( $result['message'] );
			return;
		}

		$formatted_groups = array();
		foreach ( $result['data'] as $group ) {
			$id   = isset( $group['Id'] ) ? $group['Id'] : ( isset( $group['id'] ) ? $group['id'] : '' );
			$name = isset( $group['Name'] ) ? $group['Name'] : ( isset( $group['name'] ) ? $group['name'] : '' );
			if ( ! empty( $id ) && ! empty( $name ) ) {
				$formatted_groups[] = array( 'id' => $id, 'name' => $name );
			}
		}

		wp_send_json_success(
			array(
				'groups'   => $formatted_groups,
				'has_more' => count( $formatted_groups ) >= $limit,
				'page'     => $page,
			)
		);
	}

	/**
	 * AJAX handler for saving group
	 */
	public function ajax_save_group() {
		check_ajax_referer( 'activetrail_admin_nonce', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Insufficient permissions', 'activetrail-for-woocommerce' ) );
		}

        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized on next line
		$group_id_raw = isset( $_POST['group_id'] ) ? wp_unslash( $_POST['group_id'] ) : '';
		$group_id     = sanitize_text_field( $group_id_raw );

		if ( empty( $group_id ) ) {
			wp_send_json_error( esc_html__( 'Group ID is required', 'activetrail-for-woocommerce' ) );
		}

		// Try to save to both systems with error trapping.
		$wc_result      = false;
		$unified_result = false;

		try {
			$wc_result = update_option( 'activetrail_group_id', $group_id );
			// Note: update_option returns false if value hasn't changed, so verify by checking saved value.
			if ( $wc_result === false ) {
				$saved_wc_value = get_option( 'activetrail_group_id', '' );
				// If the saved value matches what we tried to save, it's actually a success.
				if ( $saved_wc_value === $group_id ) {
					$wc_result = true;
				} elseif ( function_exists( 'activetrail_logger' ) ) {
						$error = error_get_last();
                        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- Debug only, error data needed
						$error_string = is_array( $error ) ? wp_json_encode( $error ) : (string) $error;
						activetrail_logger()->warning( 'update_option returned false. Last PHP error: ' . $error_string, 'GENERAL' );
				}
			}
		} catch ( Exception $e ) {
			if ( function_exists( 'activetrail_logger' ) ) {
				activetrail_logger()->error( 'Exception saving group_id to option: ' . $e->getMessage(), 'GENERAL' );
			}
		}

		try {
			$unified_result = ActiveTrail_Settings::update( 'group_id', $group_id );
			// Note: update_option returns false if value hasn't changed, so verify by checking saved value.
			if ( $unified_result === false ) {
				$saved_unified_value = ActiveTrail_Settings::get( 'group_id', '' );
				// If the saved value matches what we tried to save, it's actually a success.
				if ( $saved_unified_value === $group_id ) {
					$unified_result = true;
				} elseif ( function_exists( 'activetrail_logger' ) ) {
						activetrail_logger()->warning( 'ActiveTrail_Settings::update returned false for group_id.', 'GENERAL' );
				}
			}
		} catch ( Exception $e ) {
			if ( function_exists( 'activetrail_logger' ) ) {
				activetrail_logger()->error( 'Exception updating group_id in settings: ' . $e->getMessage(), 'GENERAL' );
			}
		}

		// Debug logging always enabled here for better tracing.
		if ( function_exists( 'activetrail_logger' ) ) {
			$logger = activetrail_logger();
			$logger->debug( 'AJAX Save Group - Received Group ID: ' . $group_id_raw, 'GENERAL' );
			$logger->debug( 'AJAX Save Group - Sanitized Group ID: ' . $group_id, 'GENERAL' );
			$logger->debug( 'AJAX Save Group - WC Result: ' . ( $wc_result ? 'success' : 'failed' ), 'GENERAL' );
			$logger->debug( 'AJAX Save Group - Unified Result: ' . ( $unified_result ? 'success' : 'failed' ), 'GENERAL' );
		}

		if ( $wc_result && $unified_result ) {
			wp_send_json_success(
				array(
					'message'   => esc_html__( 'Group saved successfully', 'activetrail-for-woocommerce' ),
					'group_id'  => $group_id,
					'timestamp' => current_time( 'mysql' ),
				)
			);
		} else {
			wp_send_json_error( esc_html__( 'Failed to save group', 'activetrail-for-woocommerce' ) );
		}
	}

	/**
	 * AJAX handler for getting debug info
	 */
	public function ajax_get_debug_info() {
		check_ajax_referer( 'activetrail_admin_nonce', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Insufficient permissions', 'activetrail-for-woocommerce' ) );
		}

		$wc_option       = get_option( 'activetrail_group_id', '' );
		$unified_setting = ActiveTrail_Settings::get( 'group_id', '' );

		$sync_status = 'synchronized';
		if ( $wc_option !== $unified_setting ) {
			$sync_status = 'not_synchronized';
		} elseif ( empty( $wc_option ) && empty( $unified_setting ) ) {
			$sync_status = 'both_empty';
		}

		wp_send_json_success(
			array(
				'wc_option'       => $wc_option ?: 'empty',
				'unified_setting' => $unified_setting ?: 'empty',
				'sync_status'     => $sync_status,
				'timestamp'       => current_time( 'mysql' ),
			)
		);
	}

	/**
	 * Register custom query var for feed endpoint
	 *
	 * Without this, WordPress מתעלם מ-activetrail_feed וה-URL /activetrail-feed.xml
	 * פשוט יטען את עמוד הבית במקום את הקטלוג.
	 *
	 * @param array $vars Existing public query vars.
	 * @return array
	 */
	public function add_feed_query_var( $vars ) {
		$vars[] = 'activetrail_feed';
		return $vars;
	}

	/**
	 * Add product feed endpoint
	 */
	public function add_feed_endpoint() {
		add_rewrite_rule(
			'^activetrail-feed\.xml$',
			'index.php?activetrail_feed=xml',
			'top'
		);

		add_rewrite_rule(
			'^activetrail-feed\.json$',
			'index.php?activetrail_feed=json',
			'top'
		);
	}

	/**
	 * Handle feed request
	 */
	public function handle_feed_request() {
		$feed_type = get_query_var( 'activetrail_feed' );

		if ( ! $feed_type ) {
			return;
		}

		// Use the unified Product Feed Generator directly for this pretty URL endpoint.
		// כאן אנחנו לא משתמשים במפתח גישה (key), זה feed "גלוי" שמיועד בעיקר לחיבור מול ActiveTrail.
		require_once ACTIVETRAIL_WC_PLUGIN_DIR . 'includes/class-product-feed-generator.php';

		$generator = new ActiveTrail_Product_Feed_Generator();

		if ( $feed_type === 'xml' ) {
			$xml = $generator->generate_google_xml();

			// כותרות מתאימות לקטלוג XML.
			header( 'Content-Type: application/xml; charset=utf-8' );
			header( 'Cache-Control: no-cache, must-revalidate' );
			header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' );

			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- XML feed content must be output as-is.
			echo $xml;
			exit;
		}

		if ( $feed_type === 'json' ) {
			$json = $generator->generate_facebook_json();

			header( 'Content-Type: application/json; charset=utf-8' );
			header( 'Cache-Control: no-cache, must-revalidate' );
			header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' );

			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JSON feed content must be output as-is.
			echo $json;
			exit;
		}
	}

	/**
	 * Add consent field to checkout
	 */
	public function add_checkout_consent_field( $fields ) {
		// Get settings from ActiveTrail_Settings class.
		$settings = ActiveTrail_Settings::get_all();

		if ( ! isset( $settings['enable_checkout_consent'] ) || ! $settings['enable_checkout_consent'] ) {
			return $fields;
		}

		// Use custom consent text from settings, or fall back to translated default.
		$consent_text = ! empty( $settings['consent_text'] )
			? $settings['consent_text']
			: esc_html__( 'I agree to receive marketing emails', 'activetrail-for-woocommerce' );

		// Default checked when "Marketing consent checked by default" is enabled.
		$default_checked = ! empty( $settings['consent_checked_by_default'] ) ? 1 : 0;

		$fields['billing']['activetrail_consent'] = array(
			'type'     => 'checkbox',
			'label'    => $consent_text,
			'required' => false,
			'class'    => array( 'form-row-wide' ),
			'priority' => 120,
			'default'  => $default_checked,
		);

		return $fields;
	}

	/**
	 * Validate checkout consent (consent is optional – no blocking).
	 */
	public function validate_checkout_consent() {
		// Consent is not required for checkout; no validation.
		return;
	}

	/**
	 * Remove optional text from consent field
	 */
	public function remove_optional_text_from_consent_field( $field, $key, $args, $value ) {
		// Only modify the consent field (key may be activetrail_consent or billing_activetrail_consent).
		if ( $key === 'activetrail_consent' || $key === 'billing_activetrail_consent' || strpos( $key, 'activetrail_consent' ) !== false ) {
			// Remove the optional text span and any surrounding spaces/nbsp (works for any language).
			$field = preg_replace( '/&nbsp;?\s*<span class="optional">.*?<\/span>/', '', $field );

			// Clean leftover multiple spaces.
			$field = preg_replace( '/\s+/', ' ', $field );
		}
		return $field;
	}

	/**
	 * Save checkout consent
	 */
	public function save_checkout_consent( $order_id ) {
		// Get the order object.
		$order = wc_get_order( $order_id );
		if ( ! $order ) {
			return;
		}

		// Check if consent checkbox was checked (supports activetrail_consent and billing_activetrail_consent).
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- WooCommerce checkout form handles nonce verification
		if ( ActiveTrail_Consent_Helper::has_consent_from_data( $_POST ) ) {
			// Store consent in order meta.
			update_post_meta( $order_id, '_activetrail_consent', 'yes' );

			// If user is logged in, also store in user meta.
			$customer_id = $order->get_customer_id();
			if ( $customer_id ) {
				update_user_meta( $customer_id, '_activetrail_consent', 'yes' );
				update_user_meta( $customer_id, '_activetrail_consent_date', current_time( 'mysql' ) );
			}
		} else {
			// Always store a value for _activetrail_consent, even when not checked.
			// This ensures we have an explicit value for all orders.
			update_post_meta( $order_id, '_activetrail_consent', 'no' );

			// We don't update user meta when consent is not given.
			// This preserves any previous consent the user might have given.
		}
	}

	/**
	 * Handle scheduled product sync
	 */
	public function handle_scheduled_product_sync() {
		require_once ACTIVETRAIL_WC_PLUGIN_DIR . 'templates/product-feed.php';
		$feed = new ActiveTrail_Product_Feed();
		$feed->handle_scheduled_sync();
	}

	/**
	 * Get plugin setting
	 *
	 * @param string $key Setting key
	 * @param mixed  $default Default value
	 * @return mixed
	 */
	public function get_setting( $key, $default = null ) {
		// Use ActiveTrail_Settings class for consistency.
		return ActiveTrail_Settings::get( $key, $default );
	}

	/**
	 * Update plugin setting
	 *
	 * @param string $key Setting key
	 * @param mixed  $value Setting value
	 */
	public function update_setting( $key, $value ) {
		// Use ActiveTrail_Settings class for consistency.
		ActiveTrail_Settings::update( $key, $value );
	}

	/**
	 * Get API client instance
	 *
	 * @return ActiveTrail_API_Client
	 */
	public function get_api_client() {
		return $this->api_client;
	}

	/**
	 * Get order handler instance
	 *
	 * @return ActiveTrail_Order_Handler
	 */
	public function get_order_handler() {
		return $this->order_handler;
	}

	/**
	 * Get cart handler instance
	 *
	 * @return ActiveTrail_Cart_Handler
	 */
	public function get_cart_handler() {
		return $this->cart_handler;
	}

	/**
	 * Get coupon handler instance
	 *
	 * @return ActiveTrail_Coupon_Handler
	 */
	public function get_coupon_handler() {
		return $this->coupon_handler;
	}

	/**
	 * Get event handler instance
	 *
	 * @return ActiveTrail_Event_Handler
	 */
	public function get_event_handler() {
		return $this->event_handler;
	}

	/**
	 * Get user registration handler instance
	 *
	 * @return ActiveTrail_User_Registration_Handler
	 */
	public function get_user_registration_handler() {
		return $this->user_registration_handler;
	}

	/**
	 * Get historical sync handler instance
	 *
	 * @return ActiveTrail_Historical_Sync_Handler
	 */
	public function get_historical_sync_handler() {
		return $this->historical_sync_handler;
	}

	/**
	 * Log message
	 *
	 * @param string $message Log message
	 * @param string $level Log level (info, warning, error)
	 */
	public function log( $message, $level = 'info' ) {
		if ( function_exists( 'activetrail_logger' ) ) {
			$level_map    = array(
				'info'    => 'INFO',
				'debug'   => 'DEBUG',
				'warning' => 'WARNING',
				'error'   => 'ERROR',
			);
			$mapped_level = isset( $level_map[ $level ] ) ? $level_map[ $level ] : 'INFO';
			activetrail_logger()->log( $message, $mapped_level, 'GENERAL' );
		}
	}
}
