<?php
/**
 * CacheLoop Core Bootstrap
 *
 * Singleton class that reads saved settings and conditionally
 * instantiates Free and Pro feature classes.
 *
 * @package CacheLoop
 */

// Security: Prevent direct file access.
defined( 'ABSPATH' ) || exit;

/**
 * Class CACHELOOP_Core
 *
 * Plugin bootstrap singleton. Reads settings and wires up feature classes.
 */
class CACHELOOP_Core {

	/**
	 * Plugin settings read from the database.
	 *
	 * @var array
	 */
	private $settings = array();

	/**
	 * Singleton instance.
	 *
	 * @var CACHELOOP_Core|null
	 */
	private static $instance = null;

	/**
	 * Returns the singleton instance.
	 *
	 * @return CACHELOOP_Core
	 */
	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Constructor: reads settings and loads features.
	 */
	private function __construct() {
		$defaults = array(
			'page_cache'              => 1,
			'browser_cache'           => 1,
			'gzip'                    => 1,
			'lazy_load'               => 1,
			'cdn_enabled'             => 0,
			'cdn_domain'              => '',
			'varnish_enabled'         => 0,
			'varnish_host'            => '',
			'varnish_port'            => 6081,
			'cf_enabled'              => 0,
			'cf_api_token'            => '',
			'cf_zone_id'              => '',
			'unused_css_enabled'      => 0,
			'unused_css_safelist'     => '',
			'bypass_cookies'          => '',
			'lcp_image_count'         => 1,
			'minify'                  => 0,
			'defer_css'               => 0,
			'delay_js'                => 0,
			'cache_ttl'               => 86400,
			'cache_device_split'      => 0,
			'cache_whitelist'         => '',
			'cache_whitelist_enabled' => 0,
			'cache_blacklist'         => '',
			'delay_js_exclusions'     => "jquery.min.js\njquery-migrate.min.js\nbootstrap.min.js\nmodernizr.custom.js\njs_composer_front.min.js\nwaypoints.min.js\nultimate.min.js\nvhparallax.min.js\nrbtools.min.js\nrs6.min.js\nslick.min.js",
			'disable_animations'      => 0,
			'lcp_preload_urls'        => '',
			'db_optimizer'            => 0,
			'preloader'               => 0,
			'heartbeat'               => 0,
			'disable_emojis'          => 0,
			'local_google_fonts'      => 0,
			'instant_page'            => 0,
			'preconnect_domains'      => '',
			'preload_lcp_images'      => 0,
			'object_cache_enabled'    => 0,
			'object_cache_driver'     => 'redis',
			'object_cache_host'       => '127.0.0.1',
			'object_cache_port'       => '6379',
			'object_cache_password'   => '',
			'object_cache_ttl'        => 3600,
			'image_optimize'          => 0,
			'image_optimize_on_upload' => 0,
			'image_optimize_quality'  => 82,
			'image_optimize_method'   => 'auto',
			'bloat_disable_xmlrpc'       => 0,
			'bloat_disable_dashicons'    => 0,
			'bloat_disable_jquery_migrate' => 0,
			'bloat_disable_block_css'    => 0,
			'bloat_disable_cart_fragment' => 0,
			'bloat_disable_woo_assets'   => 0,
			'bloat_disable_rss'          => 0,
			'bloat_disable_oembeds'      => 0,
			'bloat_disable_gutenberg'    => 0,
			'bloat_limit_revisions'      => '',
			'combine_js_footer'          => 0,
			'critical_css_enabled'       => 0,
		);

		$saved          = get_option( 'cacheloop_settings', array() );
		$this->settings = wp_parse_args( $saved, $defaults );

		$this->load_free_features();
		if ( function_exists( 'cacheloop_fs' ) && cacheloop_fs()->can_use_premium_code() ) {
			$this->load_pro_features__premium_only();
		}
		$this->load_admin();
	}

	/**
	 * Instantiates Free feature classes based on saved settings.
	 *
	 * @return void
	 */
	private function load_free_features() {
		// --- Asset Scanner ---
		require_once CACHELOOP_PLUGIN_DIR . 'includes/class-cl-asset-scanner.php';
		new CACHELOOP_Asset_Scanner();

		// --- Cache Stats (hit/miss/purge counters) + HealthLoop bridge ---
		// Loaded unconditionally, and before Page Cache, so the purge hooks
		// it registers are in place before anything could fire them.
		require_once CACHELOOP_PLUGIN_DIR . 'includes/class-cl-stats.php';
		new CACHELOOP_Stats();

		require_once CACHELOOP_PLUGIN_DIR . 'includes/class-cl-healthloop-bridge.php';
		new CACHELOOP_HealthLoop_Bridge();

		// --- Page Cache ---
		if ( ! empty( $this->settings['page_cache'] ) ) {
			require_once CACHELOOP_PLUGIN_DIR . 'includes/class-cl-page-cache.php';
			new CACHELOOP_Page_Cache( $this->settings );
		}

		// --- REST API Cache (Free) ---
		require_once CACHELOOP_PLUGIN_DIR . 'includes/class-cl-rest-cache.php';
		new CACHELOOP_REST_Cache( $this->settings );

		// --- WP-CLI commands (only loads when WP-CLI is active) ---
		if ( defined( 'WP_CLI' ) && WP_CLI ) {
			require_once CACHELOOP_PLUGIN_DIR . 'includes/class-cl-cli.php';
		}

		// --- Browser Cache (passive – rules written on activation, just keep class available) ---
		require_once CACHELOOP_PLUGIN_DIR . 'includes/class-cl-browser-cache.php';

		// --- Nginx Cache Rules (passive - static rule generator, invoked on demand from the
		// admin-post download handler in CACHELOOP_Admin, just keep class available) ---
		require_once CACHELOOP_PLUGIN_DIR . 'includes/class-cl-nginx-cache.php';

		// --- Lazy Load ---
		if ( ! empty( $this->settings['lazy_load'] ) ) {
			require_once CACHELOOP_PLUGIN_DIR . 'includes/class-cl-lazy-load.php';
			new CACHELOOP_Lazy_Load( $this->settings );
		}

		// --- Disable Emojis ---
		if ( ! empty( $this->settings['disable_emojis'] ) ) {
			require_once CACHELOOP_PLUGIN_DIR . 'includes/class-cl-disable-emojis.php';
			new CACHELOOP_Disable_Emojis();
		}
	}

	/**
	 * Instantiates Pro feature classes only when a valid Pro license is active.
	 *
	 * Each class is wrapped in a Freemius plan check. When the Free ZIP is
	 * generated by Freemius, code inside @fs_premium_only blocks is stripped.
	 *
	 * @return void
	 */
	private function load_pro_features__premium_only() {
		// Guard: Freemius must be initialized before we can check the plan.
		if ( ! function_exists( 'cacheloop_fs' ) ) {
			return;
		}

		// Helper: load a premium class file only if it actually exists on disk.
		// This prevents fatal errors when the free version is installed
		// but Freemius reports premium access (e.g. unregistered trial).
		$load_class = function ( $relative_path, $condition ) {
			if ( ! $condition ) {
				return;
			}
			$full_path = CACHELOOP_PLUGIN_DIR . $relative_path;
			if ( ! file_exists( $full_path ) ) {
				return;
			}
			require_once $full_path;
		};

		// --- Minification (Pro) ---
		$load_class( 'includes/class-cl-minifier__premium_only.php', ! empty( $this->settings['minify'] ) || ! empty( $this->settings['combine_js_footer'] ) );
		if ( class_exists( 'CACHELOOP_Minifier' ) ) {
			new CACHELOOP_Minifier( $this->settings );
		}

		// --- Unused CSS Removal (Pro) ---
		// Always loaded for Pro, same reasoning as Image Optimization above:
		// hooks into the Minifier's combined-CSS filter, which only ever
		// fires when Combine CSS is actually producing output — a no-op
		// otherwise, so there's no cost to always registering it.
		$load_class( 'includes/class-cl-unused-css__premium_only.php', true );
		if ( class_exists( 'CACHELOOP_Unused_CSS' ) ) {
			new CACHELOOP_Unused_CSS( $this->settings );
		}

		// --- Delay JS Execution (Pro) ---
		$load_class( 'includes/class-cl-delay-js__premium_only.php', ! empty( $this->settings['delay_js'] ) );
		if ( class_exists( 'CACHELOOP_Delay_JS' ) ) {
			new CACHELOOP_Delay_JS( $this->settings );
		}

		// --- Database Optimizer (Pro) ---
		$load_class( 'includes/class-cl-db-optimizer__premium_only.php', ! empty( $this->settings['db_optimizer'] ) );
		if ( class_exists( 'CACHELOOP_DB_Optimizer' ) ) {
			new CACHELOOP_DB_Optimizer();
		}

		// --- Cache Preloader (Pro) ---
		$load_class( 'includes/class-cl-preloader__premium_only.php', true );
		if ( class_exists( 'CACHELOOP_Preloader' ) ) {
			new CACHELOOP_Preloader();
		}

		// --- Extended Media Optimization (Pro) ---
		$load_class( 'includes/class-cl-media__premium_only.php', ! empty( $this->settings['lazy_load'] ) );
		if ( class_exists( 'CACHELOOP_Media' ) ) {
			new CACHELOOP_Media();
		}

		// --- Advanced Rules / Heartbeat Control (Pro) ---
		$load_class( 'includes/class-cl-advanced-rules__premium_only.php', true );
		if ( class_exists( 'CACHELOOP_Advanced_Rules' ) ) {
			new CACHELOOP_Advanced_Rules( $this->settings );
		}

		// --- Local Google Fonts (Pro) ---
		$load_class( 'includes/class-cl-google-fonts__premium_only.php', ! empty( $this->settings['local_google_fonts'] ) );
		if ( class_exists( 'CACHELOOP_Google_Fonts' ) ) {
			new CACHELOOP_Google_Fonts();
		}

		// --- Instant Page / Link Prefetch on Hover (Pro) ---
		$load_class( 'includes/class-cl-instant-page__premium_only.php', ! empty( $this->settings['instant_page'] ) );
		if ( class_exists( 'CACHELOOP_Instant_Page' ) ) {
			new CACHELOOP_Instant_Page();
		}

		// --- Critical CSS (Pro) ---
		$load_class( 'includes/class-cl-critical-css__premium_only.php', ! empty( $this->settings['critical_css_enabled'] ) );
		if ( class_exists( 'CACHELOOP_Critical_CSS' ) ) {
			new CACHELOOP_Critical_CSS( $this->settings );
		}

		// --- Object Cache: Redis / Memcached (Pro) ---
		$load_class( 'includes/class-cl-object-cache__premium_only.php', true );
		if ( class_exists( 'CACHELOOP_Object_Cache' ) ) {
			new CACHELOOP_Object_Cache( $this->settings );
		}

		// --- Image Optimization: WebP conversion (Pro) ---
		// Always loaded for Pro (not gated on the 'image_optimize' toggle):
		// its admin markup (stats widget, per-image table) is shown to every
		// Pro user regardless of the toggle, so the AJAX handlers backing it
		// must exist too — otherwise those requests hit WordPress core's own
		// "unknown action" 400, which looks exactly like a server problem.
		$load_class( 'includes/class-cl-image-optimizer__premium_only.php', true );
		if ( class_exists( 'CACHELOOP_Image_Optimizer' ) ) {
			new CACHELOOP_Image_Optimizer( $this->settings );
		}

		// --- Varnish Cache Purge (Pro) ---
		$load_class( 'includes/class-cl-varnish__premium_only.php', true );
		if ( class_exists( 'CACHELOOP_Varnish' ) ) {
			new CACHELOOP_Varnish( $this->settings );
		}

		// --- Cloudflare Cache Purge (Pro) ---
		$load_class( 'includes/class-cl-cloudflare__premium_only.php', true );
		if ( class_exists( 'CACHELOOP_Cloudflare' ) ) {
			new CACHELOOP_Cloudflare( $this->settings );
		}

		// --- Bloat Remover (Pro) ---
		$load_class( 'includes/class-cl-bloat-remover__premium_only.php', true );
		if ( class_exists( 'CACHELOOP_Bloat_Remover' ) ) {
			new CACHELOOP_Bloat_Remover( $this->settings );
		}

		// Disable Animations Fix and LCP Preload URLs are wired up by
		// CACHELOOP_Advanced_Rules itself (see includes/class-cl-advanced-rules__premium_only.php)
		// so that no Pro-gated logic has to live in this always-shipped file.
	}

	/**
	 * Loads the admin settings page (back-end only).
	 *
	 * @return void
	 */
	private function load_admin() {
		if ( is_admin() ) {
			require_once CACHELOOP_PLUGIN_DIR . 'admin/class-cl-admin.php';
			new CACHELOOP_Admin( $this->settings );
		}
	}

	/**
	 * Returns the current plugin settings array.
	 *
	 * @return array
	 */
	public function get_settings() {
		return $this->settings;
	}
}
