<?php
// phpcs:disable WordPress.DB.PreparedSQL,PluginCheck.Security.DirectDB.UnescapedDBParameter,WordPress.NamingConventions.PrefixAllGlobals -- Internal identifiers and public legacy extension hooks are retained.
/**
 * Extension dependency handling for popup types.
 *
 * When a popup type is provided by an extension plugin, we track that dependency
 * and: deactivate popups when the extension is deactivated, prevent rendering
 * when the extension is missing, and disable the active toggle in admin when
 * the extension is inactive.
 *
 * @package    Instant_Popup_Builder
 * @subpackage Instant_Popup_Builder/includes
 */

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

/**
 * Class Instant_Popup_Builder_Extension_Dependency
 */
class Instant_Popup_Builder_Extension_Dependency {

	/**
	 * Cached map of popup type => extension info (plugin path, display name).
	 *
	 * @var array|null
	 */
	private static $type_map = null;

	/**
	 * Core popup types that are always available (no extension required).
	 *
	 * @var array
	 */
	private static $core_always_types = array( 'text', 'image', 'html' );

	/**
	 * Default extension-type display names (used when extension is not registered via filter).
	 *
	 * @var array
	 */
	private static $default_extension_names = array(
		'video'             => 'Video Popup',
		'image_gallery'     => 'Image Gallery',
		'subscription'       => 'Subscription Pro',
		'contact'            => 'Contact Form',
		'contact_form'       => 'Contact Form',
		'social_share'       => 'Social Share Popup',
		'login_signup'       => 'Sign Up / Login Popup',
		'spin_to_win'        => 'Spin-to-Win Popup',
		'announcement_bar'   => 'Announcement Bar',
		'pdf'                => 'PDF Popup',
		'age_verification'  => 'Age Verification',
		'recent_orders'      => 'Recent Orders',
		'feedback'           => 'Feedback Popup',
	);

	/**
	 * Get the map of popup types that require an extension.
	 *
	 * Built from default names + filter ipb_popup_type_extension_map.
	 * Each entry: type => [ 'plugin' => 'plugin-dir/plugin-file.php' (optional), 'name' => 'Display Name' ].
	 *
	 * @return array
	 */
	public static function get_type_extension_map() {
		if ( self::$type_map !== null ) {
			return self::$type_map;
		}
		$defaults = array();
		foreach ( self::$default_extension_names as $type => $name ) {
			$defaults[ $type ] = array(
				'plugin' => self::get_default_plugin_path_for_type( $type ),
				'name'   => $name,
			);
		}
		self::$type_map = apply_filters( 'ipb_popup_type_extension_map', $defaults );
		return self::$type_map;
	}

	/**
	 * Get default plugin main-file path for an extension type.
	 *
	 * @param string $type Popup type.
	 * @return string Plugin path used by is_plugin_active(), empty when unknown.
	 */
	private static function get_default_plugin_path_for_type( $type ) {
		$plugin_paths = array(
			'age_verification' => 'instant-popup-age-verification/instant-popup-age-verification.php',
			'pdf'              => 'instant-popup-pdf/instant-popup-pdf.php',
			'contact'          => 'instant-popup-contact-form/instant-popup-contact-form.php',
			'contact_form'     => 'instant-popup-contact-form/instant-popup-contact-form.php',
			'social_share'     => 'instant-popup-social-share/instant-popup-social-share.php',
			'login_signup'     => 'instant-popup-login-signup/instant-popup-login-signup.php',
			'spin_to_win'      => 'instant-popup-spin-to-win/instant-popup-spin-to-win.php',
			'announcement_bar' => 'instant-popup-announcement-bar/instant-popup-announcement-bar.php',
			'recent_orders'    => 'instant-popup-recent-orders/instant-popup-recent-orders.php',
			'feedback'         => 'instant-popup-feedback/instant-popup-feedback.php',
			'subscription'     => 'instant-popup-subscription/instant-popup-subscription.php',
		);
		return isset( $plugin_paths[ $type ] ) ? $plugin_paths[ $type ] : '';
	}

	/**
	 * Check if a popup type requires an extension (not a core-always type).
	 *
	 * @param string       $type          Popup type (e.g. 'feedback', 'video', 'subscription').
	 * @param string|array $popup_advance Popup advance payload (JSON string or decoded array) when available.
	 * @return bool
	 */
	public static function is_extension_required_for_type( $type, $popup_advance = null ) {
		if ( $type === '' || in_array( $type, self::$core_always_types, true ) ) {
			return false;
		}
		// Subscription "basic" template is available in core and should not depend on Subscription Pro.
		if ( $type === 'subscription' && self::is_core_subscription_template( $popup_advance ) ) {
			return false;
		}
		$map = self::get_type_extension_map();
		return isset( $map[ $type ] );
	}

	/**
	 * Check if the extension required for the given popup type is active.
	 *
	 * If the type does not require an extension (core type), returns true.
	 * Otherwise: if a plugin is registered for the type, checks is_plugin_active();
	 * else checks whether the type is in get_active_popup() (license/extension available).
	 *
	 * @param string       $type          Popup type.
	 * @param string|array $popup_advance Popup advance payload (JSON string or decoded array) when available.
	 * @return bool
	 */
	public static function is_extension_active_for_type( $type, $popup_advance = null ) {
		if ( ! self::is_extension_required_for_type( $type, $popup_advance ) ) {
			return true;
		}
		$map = self::get_type_extension_map();
		if ( ! empty( $map[ $type ]['plugin'] ) ) {
			if ( ! function_exists( 'is_plugin_active' ) ) {
				require_once ABSPATH . 'wp-admin/includes/plugin.php';
			}
			if ( is_plugin_active( $map[ $type ]['plugin'] ) ) {
				return true;
			}

			// Subscription Pro may be installed in a versioned or renamed directory.
			// Its bootstrap marker is a more reliable signal than a fixed basename.
			if ( 'subscription' === $type && ( defined( 'Instant_Popup_Subscription_VERSION' ) || class_exists( 'Instant_Popup_Subscription', false ) ) ) {
				return true;
			}

			if ( 'social_share' === $type && ( defined( 'INSTANT_POPUP_SOCIAL_SHARE_VERSION' ) || class_exists( 'Instant_Popup_Social_Share', false ) ) ) {
				return true;
			}

			$extension_markers = array(
				'login_signup'    => array( 'INSTANT_POPUP_LOGIN_SIGNUP_VERSION', 'Instant_Popup_Login_Signup' ),
				'spin_to_win'     => array( 'INSTANT_POPUP_SPIN_TO_WIN_VERSION', 'Instant_Popup_Spin_To_Win' ),
				'announcement_bar'=> array( 'INSTANT_POPUP_ANNOUNCEMENT_BAR_VERSION', 'Instant_Popup_Announcement_Bar' ),
				'recent_orders'   => array( 'INSTANT_POPUP_RECENT_ORDERS_VERSION', 'Instant_Popup_Recent_Orders' ),
				'feedback'        => array( 'INSTANT_POPUP_FEEDBACK_VERSION', 'IPB_Feedback_Popup' ),
			);
			if ( isset( $extension_markers[ $type ] ) ) {
				$marker = $extension_markers[ $type ];
				if ( defined( $marker[0] ) || class_exists( $marker[1], false ) ) {
					return true;
				}
			}

			return false;
		}
		// No plugin registered: type is active only if it is currently in the active popup list (license/extension).
		if ( ! class_exists( 'Class_instant_popup_builder_manager', false ) ) {
			return false;
		}
		$active = Class_instant_popup_builder_manager::get_active_popup();
		return is_array( $active ) && in_array( $type, $active, true );
	}

	/**
	 * Determine if a subscription popup is the core template (basic) and should stay independent from Pro.
	 *
	 * @param string|array|null $popup_advance Popup advance payload.
	 * @return bool
	 */
	private static function is_core_subscription_template( $popup_advance ) {
		$template_style = '';
		if ( is_string( $popup_advance ) && $popup_advance !== '' ) {
			$decoded = json_decode( $popup_advance, true );
			if ( is_array( $decoded ) && isset( $decoded['template_style'] ) ) {
				$template_style = (string) $decoded['template_style'];
			}
		} elseif ( is_array( $popup_advance ) && isset( $popup_advance['template_style'] ) ) {
			$template_style = (string) $popup_advance['template_style'];
		} elseif ( is_object( $popup_advance ) && isset( $popup_advance->template_style ) ) {
			$template_style = (string) $popup_advance->template_style;
		}
		return ( $template_style === '' || $template_style === 'basic' );
	}

	/**
	 * Get the display name of the extension required for a popup type.
	 *
	 * @param string $type Popup type.
	 * @return string Empty if no extension or name not set.
	 */
	public static function get_extension_display_name_for_type( $type ) {
		$map = self::get_type_extension_map();
		if ( isset( $map[ $type ]['name'] ) && $map[ $type ]['name'] !== '' ) {
			return $map[ $type ]['name'];
		}
		return isset( self::$default_extension_names[ $type ] ) ? self::$default_extension_names[ $type ] : '';
	}

	/**
	 * Deactivate all popups that depend on the given type (set class to inactive).
	 *
	 * Call this from an extension's deactivation hook so that when the extension
	 * is deactivated or deleted, its popups are set to inactive immediately.
	 *
	 * @param string $type Popup type (e.g. 'feedback').
	 * @return int|false Number of rows updated, or false on failure.
	 */
	public static function deactivate_popups_for_type( $type ) {
		if ( ! is_string( $type ) || $type === '' ) {
			return false;
		}
		if ( ! current_user_can( 'manage_options' ) && ! self::is_running_during_plugin_deactivation() ) {
			return false;
		}

		global $wpdb;
		$table = $wpdb->prefix . 'instant_popup_builder';

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$updated = $wpdb->update(
			$table,
			array( 'class' => '' ),
			array( 'type' => $type ),
			array( '%s' ),
			array( '%s' )
		);

		if ( $updated > 0 ) {
			self::clear_popup_class_transients_for_type( $type );
		}

		return $updated;
	}

	/**
	 * Clear transients for popup class for all popups of the given type.
	 *
	 * @param string $type Popup type.
	 */
	private static function clear_popup_class_transients_for_type( $type ) {
		global $wpdb;
		$table = $wpdb->prefix . 'instant_popup_builder';
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$ids = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM {$table} WHERE type = %s", $type ) );
		if ( ! is_array( $ids ) ) {
			return;
		}
		foreach ( $ids as $id ) {
			delete_transient( 'instant_popup_builder_popup_class' . $id );
		}
	}

	/**
	 * True while WordPress is processing plugin deactivation (core fires `deactivate_plugin` before `deactivate_{$plugin}`).
	 * Allows deactivate_popups_for_type() to run from extension deactivation hooks when no user/capabilities exist (e.g. some CLI flows).
	 *
	 * @return bool
	 */
	private static function is_running_during_plugin_deactivation() {
		return did_action( 'deactivate_plugin' ) > 0;
	}
}
