<?php
/**
 * Promo SDK Main Class
 *
 * @package PromoSDK
 */

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! class_exists( 'Promo_SDK' ) ) {
	/**
	 * Main Promo SDK Class
	 *
	 * Handles SDK initialization, configuration management, and hook registration.
	 *
	 * @since 1.0.0
	 */
	class Promo_SDK {
		/**
		 * SDK instances (one per product)
		 *
		 * @var array
		 */
		private static $instances = array();

		/**
		 * Configuration array
		 *
		 * @var array
		 */
		private $config = array();

		/**
		 * API Client instance
		 *
		 * @var API_Client|null
		 */
		private $api_client = null;

		/**
		 * Modal Renderer instance
		 *
		 * @var Modal_Renderer|null
		 */
		private $modal_renderer = null;

		/**
		 * Notice Renderer instance
		 *
		 * @var Notice_Renderer|null
		 */
		private $notice_renderer = null;

		/**
		 * Countdown Handler instance
		 *
		 * @var Countdown_Handler|null
		 */
		private $countdown_handler = null;

		/**
		 * Private constructor to prevent direct instantiation
		 *
		 * @param array $config Configuration array.
		 */
		private function __construct( $config ) {
			$this->config = $this->sanitize_config( $config );
			$this->load_dependencies();
			$this->init_components();
		}

		/**
		 * Initialize the SDK
		 *
		 * @param array $config Configuration array.
		 * @return Promo_SDK|null SDK instance or null on failure.
		 */
		public static function init( $config ) {
			// Validate required configuration.
			if ( ! self::validate_config( $config ) ) {
				return null;
			}

			$product_slug = $config['product_slug'];

			// Create instance per product if not exists.
			if ( ! isset( self::$instances[ $product_slug ] ) ) {
				self::$instances[ $product_slug ] = new self( $config );
			}

			return self::$instances[ $product_slug ];
		}

		/**
		 * Get SDK instance for a specific product
		 *
		 * @param string $product_slug Product slug.
		 * @return Promo_SDK|null Instance or null.
		 */
		public static function get_instance( $product_slug = '' ) {
			if ( empty( $product_slug ) ) {
				// Return first instance if no slug provided (backward compatibility).
				return ! empty( self::$instances ) ? reset( self::$instances ) : null;
			}

			return isset( self::$instances[ $product_slug ] ) ? self::$instances[ $product_slug ] : null;
		}

		/**
		 * Validate configuration array
		 *
		 * @param array $config Configuration array.
		 * @return bool True if valid, false otherwise.
		 */
		private static function validate_config( $config ) {
			if ( ! is_array( $config ) ) {
				return false;
			}

			// Check required fields.
			$required_fields = array( 'product_slug', 'plugin_page_slug' );

			foreach ( $required_fields as $field ) {
				if ( ! isset( $config[ $field ] ) || empty( $config[ $field ] ) ) {
					return false;
				}
			}

			return true;
		}

		/**
		 * Sanitize configuration array
		 *
		 * @param array $config Configuration array.
		 * @return array Sanitized configuration.
		 */
		private function sanitize_config( $config ) {
			$defaults = array(
				'product_slug'         => '',
				'plugin_page_slug'     => '',
				'api_endpoint'         => '',
				'cache_duration'       => 3600,
				'dismiss_duration'     => 0, // 0 means use campaign end date.
				'text_domain'          => 'promo-sdk',
				'prefix'               => 'ps',
				'specific_pages'       => '',
				'hide_modal_demo_link' => false,
				'is_pro'               => false,
			);

			$config = wp_parse_args( $config, $defaults );

			// Sanitize each field.
			$config['product_slug']     = sanitize_key( $config['product_slug'] );
			$config['plugin_page_slug'] = sanitize_key( $config['plugin_page_slug'] );
			$config['api_endpoint']     = ! empty( $config['api_endpoint'] ) ? esc_url_raw( $config['api_endpoint'] ) : '';
			$config['cache_duration']   = absint( $config['cache_duration'] );
			// Allow 0 for dismiss_duration (means use campaign end date).
			$config['dismiss_duration']     = isset( $config['dismiss_duration'] ) ? absint( $config['dismiss_duration'] ) : 0;
			$config['text_domain']          = sanitize_key( $config['text_domain'] );
			$config['prefix']               = sanitize_key( $config['prefix'] );
			$config['specific_pages']       = sanitize_text_field( $config['specific_pages'] );
			$config['hide_modal_demo_link'] = (bool) $config['hide_modal_demo_link'];
			$config['is_pro']               = (bool) $config['is_pro'];

			return $config;
		}

		/**
		 * Load SDK dependencies
		 *
		 * @return void
		 */
		private function load_dependencies() {
			$sdk_path = __DIR__;

			require_once $sdk_path . '/class-api-client.php';
			require_once $sdk_path . '/class-countdown-handler.php';
			require_once $sdk_path . '/class-modal-renderer.php';
			require_once $sdk_path . '/class-notice-renderer.php';
		}

		/**
		 * Initialize SDK components
		 *
		 * @return void
		 */
		private function init_components() {
			$this->api_client        = new API_Client( $this->config );
			$this->countdown_handler = new Countdown_Handler();
			$this->modal_renderer    = new Modal_Renderer( $this->config, $this->countdown_handler );
			$this->notice_renderer   = new Notice_Renderer( $this->config, $this->countdown_handler );
		}



		/**
		 * Initialize SDK and register hooks (called from outside)
		 *
		 * @param array $config Configuration array.
		 * @return void
		 */
		public static function init_sdk( $config ) {
			// Initialize the SDK instance.
			$instance = self::init( $config );

			if ( null === $instance ) {
				return;
			}

			// Register hooks directly.
			add_action( 'admin_enqueue_scripts', array( $instance, 'enqueue_assets' ) );
			// Use admin_print_footer_scripts with priority 1 to render before React app loads.
			add_action( 'admin_print_footer_scripts', array( $instance, 'render_modal_template' ), 1 );
			add_action( 'admin_footer', array( $instance, 'render_notice' ) );
			add_action( 'wp_ajax_dismiss_promo_notice', array( $instance, 'handle_dismiss_notice' ) );
		}

		/**
		 * Enqueue SDK assets
		 *
		 * @return void
		 */
		public function enqueue_assets() {
			// Only load on admin pages.
			if ( ! is_admin() ) {
				return;
			}

			$sdk_url      = plugin_dir_url( __FILE__ );
			$sdk_version  = '1.0.0';
			$product_slug = $this->config['product_slug'];

			// Enqueue CSS (shared across all instances).
			if ( ! wp_style_is( 'promo-sdk-styles', 'enqueued' ) ) {
				wp_enqueue_style(
					'promo-sdk-styles',
					$sdk_url . 'assets/css/promo-sdk.css',
					array(),
					$sdk_version
				);

				// Add inline critical CSS (only once).
				$this->add_inline_css();
			}

			// Enqueue JavaScript (shared across all instances).
			if ( ! wp_script_is( 'promo-sdk-script', 'registered' ) ) {
				wp_register_script(
					'promo-sdk-script',
					$sdk_url . 'assets/js/promo-sdk.js',
					array( 'jquery' ),
					$sdk_version,
					true
				);
			}

			// Get promo data for localization.
			$promo_data = $this->api_client->fetch_promo_data( $product_slug );

			// Add countdown end time to promo data.
			if ( null !== $promo_data ) {
				$countdown_end_time = $this->countdown_handler->get_countdown_end_time( $promo_data );
				if ( $countdown_end_time ) {
					$promo_data['countdown_end_time'] = $countdown_end_time;
				}
			}

			// Localize script data with product-specific variable name.
			// IMPORTANT: wp_localize_script works even if script is already enqueued!
			// Each plugin can add its own data variable.
			$localize_var = 'PromoSDKData_' . $product_slug;
			wp_localize_script(
				'promo-sdk-script',
				$localize_var,
				array(
					'ajaxUrl'         => admin_url( 'admin-ajax.php' ),
					'nonce'           => wp_create_nonce( 'promo_sdk_dismiss' ),
					'dismissDuration' => $this->config['dismiss_duration'],
					'promoData'       => $promo_data,
					'productSlug'     => $product_slug,
				)
			);

			// Enqueue the script (if not already enqueued).
			// This must come AFTER wp_localize_script.
			if ( ! wp_script_is( 'promo-sdk-script', 'enqueued' ) ) {
				wp_enqueue_script( 'promo-sdk-script' );
			}
		}

		/**
		 * Add inline critical CSS
		 *
		 * @return void
		 */
		private function add_inline_css() {
			$css = '
			.ps-modal {
				position: fixed;
				top: 0;
				left: 0;
				width: 100%;
				height: 100%;
				z-index: 999999;
				display: none;
			}
			.ps-modal-overlay {
				position: absolute;
				top: 0;
				left: 0;
				width: 100%;
				height: 100%;
				background: rgba(0, 0, 0, 0.5);
			}
			';

			wp_add_inline_style( 'promo-sdk-styles', $css );
		}

		/**
		 * Render modal template in footer (always rendered, hidden by default)
		 *
		 * @return void
		 */
		public function render_modal_template() {
			// Only render in admin.
			if ( ! is_admin() ) {
				return;
			}

			// Check if modal already rendered by another SDK instance.
			$modal_id = 'promo-sdk-modal-' . $this->config['product_slug'];
			if ( did_action( 'goodmeet_promo_sdk_modal_rendered_' . $this->config['product_slug'] ) ) {
				return;
			}

			// Always render the modal template so it's available for Pro badge clicks.
			$this->modal_renderer->render_template();

			// Mark as rendered.
			do_action( 'goodmeet_promo_sdk_modal_rendered_' . $this->config['product_slug'] ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- promo-sdk library's own public action API.
		}

		/**
		 * Render admin notice
		 *
		 * @return void
		 */
		public function render_notice() {
			$product_slug = $this->config['product_slug'];

			$promo_data = $this->api_client->fetch_promo_data( $product_slug );
			if ( null !== $promo_data ) {
				$this->notice_renderer->render( $promo_data );
			}
		}

		/**
		 * Handle AJAX dismiss notice request
		 *
		 * @return void
		 */
		public function handle_dismiss_notice() {
			// Verify nonce.
			if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['_wpnonce'] ), 'promo_sdk_dismiss' ) ) {
				wp_send_json_error( array( 'message' => 'Invalid nonce' ) );
			}

			// Check user capability.
			if ( ! current_user_can( 'read' ) ) {
				wp_send_json_error( array( 'message' => 'Insufficient permissions' ) );
			}

			// Save dismiss state with product slug for isolation.
			$user_id      = get_current_user_id();
			$product_slug = $this->config['product_slug'];
			$meta_key     = "promo_sdk_dismissed_notice_{$product_slug}";

			update_user_meta( $user_id, $meta_key, time() );

			wp_send_json_success( array( 'message' => 'Notice dismissed' ) );
		}
	}
}
