<?php
/**
 * Freemium overlay — premium PHP lives in the Pro add-on, not in Lite.
 *
 * Secure design (rafter-secure-design / auth):
 * - Identity: WordPress site admin. No new auth primitive.
 * - AuthZ: Premium implementation files are physically absent from the
 *   wordpress.org Lite zip. Presence of the Pro overlay + a valid license
 *   unlocks them. A filter flip without those files cannot run missing PHP.
 * - Full (commercial) edition still ships the files in modules/ and uses
 *   the existing license check. Full is not submitted to wordpress.org.
 *
 * @package WP_PowerSuite\Core
 * @since 1.0.9
 */

namespace WP_PowerSuite\Core;

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

/**
 * Resolve and unlock freemium premium files.
 */
final class Freemium {

	/**
	 * Whether premium implementations for a freemium module may run.
	 */
	public static function unlocked( string $module_id ): bool {
		$module_id = sanitize_key( $module_id );
		if ( $module_id === '' ) {
			return false;
		}

		$lite = function_exists( 'wp_powersuite_is_lite_edition' ) && wp_powersuite_is_lite_edition();
		if ( $lite ) {
			$on = function_exists( 'wp_powersuite_is_pro_addon_active' )
				&& wp_powersuite_is_pro_addon_active()
				&& function_exists( 'wp_powersuite_is_license_valid' )
				&& wp_powersuite_is_license_valid();

			/**
			 * Filter Lite freemium unlock. Pro sets this via license; default is deny.
			 *
			 * @since 1.0.9
			 * @param bool   $on        Whether the Pro add-on is licensed.
			 * @param string $module_id Freemium module id.
			 */
			return (bool) apply_filters( 'wp_powersuite_freemium_unlocked', $on, $module_id );
		}

		$licensed = function_exists( 'wp_powersuite_is_license_valid' ) && wp_powersuite_is_license_valid();

		/**
		 * Filter Full-edition freemium unlock (existing license contract).
		 *
		 * @since 1.0.9
		 * @param bool   $licensed  Whether the site license is valid.
		 * @param string $module_id Freemium module id.
		 */
		return (bool) apply_filters( 'wp_powersuite_freemium_unlocked', $licensed, $module_id );
	}

	/**
	 * Absolute path to a premium file, or empty when it is not shipped here.
	 *
	 * Looks at the Pro overlay first, then the core module directory (Full).
	 *
	 * @param string $module_id Freemium module id.
	 * @param string $relative  Path relative to the module root. No parent segments.
	 */
	public static function locateFile( string $module_id, string $relative ): string {
		$module_id = sanitize_key( $module_id );
		$relative  = ltrim( str_replace( '\\', '/', $relative ), '/' );
		if ( $module_id === '' || $relative === '' || str_contains( $relative, '..' ) ) {
			return '';
		}

		$roots = [];
		if ( defined( 'WP_POWERSUITE_PRO_FREEMIUM_DIR' ) && is_string( WP_POWERSUITE_PRO_FREEMIUM_DIR ) && WP_POWERSUITE_PRO_FREEMIUM_DIR !== '' ) {
			$roots[] = (string) WP_POWERSUITE_PRO_FREEMIUM_DIR;
		}

		/**
		 * Additional directories that contain `{module-id}/{relative}` premium files.
		 *
		 * @since 1.0.9
		 * @param list<string> $roots
		 * @param string       $module_id
		 */
		$extra = apply_filters( 'wp_powersuite_freemium_file_roots', [], $module_id );
		if ( is_array( $extra ) ) {
			foreach ( $extra as $root ) {
				if ( is_string( $root ) && $root !== '' ) {
					$roots[] = $root;
				}
			}
		}

		if ( defined( 'WP_POWERSUITE_MODULES_DIR' ) ) {
			$roots[] = WP_POWERSUITE_MODULES_DIR;
		}

		foreach ( $roots as $root ) {
			$base = rtrim( str_replace( '\\', '/', (string) $root ), '/' );
			if ( $base === '' ) {
				continue;
			}
			$path = $base . '/' . $module_id . '/' . $relative;
			$real = realpath( $path );
			if ( ! is_string( $real ) || $real === '' || ! is_readable( $real ) ) {
				continue;
			}
			$root_real = realpath( $base );
			if ( ! is_string( $root_real ) || $root_real === '' ) {
				continue;
			}
			$real_n      = function_exists( 'wp_normalize_path' ) ? wp_normalize_path( $real ) : str_replace( '\\', '/', $real );
			$root_n      = function_exists( 'wp_normalize_path' ) ? wp_normalize_path( $root_real ) : str_replace( '\\', '/', $root_real );
			$root_prefix = $root_n . '/';
			if ( ! str_starts_with( $real_n, $root_prefix ) && $real_n !== $root_n ) {
				continue;
			}

			return $real;
		}

		return '';
	}

	/**
	 * Load a premium file when it exists in the Pro overlay or Full module tree.
	 */
	public static function requireFile( string $module_id, string $relative ): bool {
		$path = self::locateFile( $module_id, $relative );
		if ( $path === '' ) {
			return false;
		}

		require_once $path;

		return true;
	}
}
