<?php
/**
 * BricksExtras License Management
 *
 * Handles license activation, deactivation, and validation.
 * Easy Digital Downloads (EDD) Software Licensing.
 *
 * @package BricksExtras
 */

namespace BricksExtras;

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

/**
 * License management class.
 *
 * Handles all license-related functionality including activation,
 * deactivation, validation, and auto-activation via wp-config constant.
 */
class BricksExtrasLicense {

	/**
	 * License option prefix.
	 *
	 * @var string
	 */
	public static $prefix = '';

	/**
	 * Product title.
	 *
	 * @var string
	 */
	public static $title = '';

	/**
	 * EDD store URL.
	 *
	 * @var string
	 */
	public static $store_url = '';

	/**
	 * EDD product item ID.
	 *
	 * @var int|null
	 */
	public static $item_id = null;

	/**
	 * Admin menu slug.
	 *
	 * @var string
	 */
	public static $menu_slug = '';

	/**
	 * Initialize license system.
	 *
	 * @param string   $prefix    License option prefix.
	 * @param string   $title     Product title.
	 * @param string   $store_url EDD store URL.
	 * @param int|null $item_id   EDD product item ID.
	 * @return void
	 */
	public static function init( $prefix, $title, $store_url, $item_id ) {

		self::$prefix    = $prefix;
		self::$title     = $title;
		self::$store_url = $store_url;
		self::$item_id   = $item_id;
		self::$menu_slug = $prefix . 'menu';

		add_action( 'admin_init', array( __CLASS__, 'register_option' ) );
		add_action( 'admin_init', array( __CLASS__, 'maybe_auto_activate_constant' ) );
		add_action( 'admin_action_update', array( __CLASS__, 'activate_license' ) );
		add_action( 'admin_action_update', array( __CLASS__, 'revalidate_license' ) );
		add_action( 'admin_action_update', array( __CLASS__, 'deactivate_license' ) );
		add_action( 'admin_notices', array( __CLASS__, 'admin_notices' ) );
	}

	/**
	 * Check if license is activated.
	 *
	 * @return bool True if license is valid, false otherwise.
	 */
	public static function is_activated_license() {

		$status = get_option( self::$prefix . 'license_status' );

		if ( $status && 'valid' === $status ) {
			return true;
		}

		return false;
	}

	/**
	 * Get license key from wp-config.php constant or database.
	 *
	 * @return string License key or empty string.
	 */
	public static function get_license_key() {
		// Check for wp-config.php constant first.
		if ( defined( 'BRICKSEXTRAS_LICENSE_KEY' ) && ! empty( BRICKSEXTRAS_LICENSE_KEY ) ) {
			return trim( BRICKSEXTRAS_LICENSE_KEY );
		}

		// Fallback to database.
		return trim( get_option( self::$prefix . 'license_key' ) );
	}

	/**
	 * Get MD5 hash of license key for tracking auto-activation attempts.
	 *
	 * @param string $license_key License key to hash.
	 * @return string MD5 hash of license key.
	 */
	private static function get_license_key_hash( $license_key ) {
		return md5( $license_key );
	}

	/**
	 * Auto-activate license when BRICKSEXTRAS_LICENSE_KEY constant is defined
	 * Uses hash to ensure activation only runs once per unique license key
	 */
	public static function maybe_auto_activate_constant() {
		// Only run for admin users.
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		// Check if constant is defined.
		if ( ! defined( 'BRICKSEXTRAS_LICENSE_KEY' ) || empty( BRICKSEXTRAS_LICENSE_KEY ) ) {
			return;
		}

		$license_key      = trim( BRICKSEXTRAS_LICENSE_KEY );
		$license_key_hash = self::get_license_key_hash( $license_key );
		$stored_hash      = get_option( self::$prefix . 'license_key_hash' );

		// If hash matches, we've already tried activating this key.
		if ( $stored_hash === $license_key_hash ) {
			return;
		}

		// Store the hash so we only try once.
		update_option( self::$prefix . 'license_key_hash', $license_key_hash );

		// Attempt to activate the license.
		$api_params = array(
			'edd_action' => 'activate_license',
			'license'    => $license_key,
			'item_name'  => rawurlencode( self::$title ),
			'url'        => home_url(),
		);

		$response = wp_remote_post(
			self::$store_url,
			array(
				'timeout'   => 15,
				'sslverify' => false,
				'body'      => $api_params,
			)
		);

		// Check response and update status.
		if ( ! is_wp_error( $response ) && 200 === wp_remote_retrieve_response_code( $response ) ) {
			$license_data = json_decode( wp_remote_retrieve_body( $response ) );

			if ( isset( $license_data->license ) ) {
				update_option( self::$prefix . 'license_status', $license_data->license );

				if ( 'valid' === $license_data->license ) {
					update_option( self::$prefix . 'license_url', md5( home_url() ) );
				}
			}
		}
	}

	/**
	 * Verify license is valid for current domain
	 * Makes API call to check license status for current URL
	 */
	private static function verify_license_for_current_domain() {
		$license_key = self::get_license_key();

		if ( empty( $license_key ) ) {
			return;
		}

		// Make EDD check_license API call.
		$api_params = array(
			'edd_action' => 'check_license',
			'license'    => $license_key,
			'item_name'  => rawurlencode( self::$title ),
			'url'        => home_url(),
		);

		$response = wp_remote_post(
			self::$store_url,
			array(
				'timeout'   => 15,
				'sslverify' => false,
				'body'      => $api_params,
			)
		);

		// Check response and update status.
		if ( ! is_wp_error( $response ) && 200 === wp_remote_retrieve_response_code( $response ) ) {
			$license_data = json_decode( wp_remote_retrieve_body( $response ) );

			if ( isset( $license_data->license ) ) {
				// Update status based on current domain.
				update_option( self::$prefix . 'license_status', $license_data->license );

				// Always store URL hash to prevent repeated verification attempts.
				update_option( self::$prefix . 'license_url', md5( home_url() ) );
			}
		}
	}

	/**
	 * Render the license settings page.
	 *
	 * @return void
	 */
	public static function license_page() {
		$status           = get_option( self::$prefix . 'license_status' );
		$license_key      = self::get_license_key();
		$constant_defined = defined( 'BRICKSEXTRAS_LICENSE_KEY' ) && ! empty( BRICKSEXTRAS_LICENSE_KEY );
		$stored_url       = get_option( self::$prefix . 'license_url' );
		$current_url      = home_url();

		// If status is valid but no license key exists, treat as inactive.
		if ( 'valid' === $status && empty( $license_key ) ) {
			$status = false;
		}

		// Verify license for current domain if URL hash doesn't match or is missing.
		// This handles existing users upgrading to the new version.
		$current_url_hash = md5( $current_url );

		$should_verify = $license_key && 'valid' === $status && (
			! $stored_url || // No stored URL hash (legacy users).
			$stored_url !== $current_url_hash // URL hash changed (migration).
		);

		// Store for debug output.
		$did_verify = $should_verify;

		if ( $should_verify ) {
			self::verify_license_for_current_domain();
			// Re-fetch status after verification.
			$status     = get_option( self::$prefix . 'license_status' );
			$stored_url = get_option( self::$prefix . 'license_url' );
		}
		?>

		<h2><?php echo esc_html__( 'License', 'bricksextras' ); ?></h2>

		<div style="background-color: #fff; padding: 15px 20px; border: 1px solid #ddd">
		<?php if ( ! $constant_defined ) : ?>
			<p><?php echo esc_html__( 'Follow the steps below to license the plugin:', 'bricksextras' ); ?></p>

			<ol>
				<li><?php echo esc_html__( 'Paste your key in the License Key field', 'bricksextras' ); ?></li>
				<li><?php echo esc_html__( 'Click "Activate License" button', 'bricksextras' ); ?></li>
			</ol>
		<?php endif; ?>

		<form method="post" action="options.php">

				<?php settings_fields( self::$prefix . 'license' ); ?>

				<table class="form-table">
					<tbody>
						<tr valign="top">
							<th scope="row" valign="top">
								<?php esc_html_e( 'License Key', 'bricksextras' ); ?>
							</th>
							<td>
								<input id="<?php echo esc_attr( self::$prefix ); ?>license_key" name="<?php echo esc_attr( self::$prefix ); ?>license_key" type="text" class="regular-text" placeholder="<?php echo ( $license_key || $constant_defined ) ? '********************************' : ''; ?>" value="" <?php echo $constant_defined ? 'readonly' : ''; ?> />
								<?php if ( ! $license_key && ! $constant_defined ) { ?>
									<label class="description" for="<?php echo esc_attr( self::$prefix ); ?>license_key"><?php esc_html_e( 'Enter your license key', 'bricksextras' ); ?></label>
								<?php } ?>
							</td>
						</tr>
						
						
					</tbody>
			</table>
			<?php if ( $constant_defined ) : ?>
				<?php wp_nonce_field( self::$prefix . 'nonce', self::$prefix . 'nonce' ); ?>
				<input type="submit" class="button-primary" name="<?php echo esc_attr( self::$prefix ); ?>license_revalidate" value="<?php esc_attr_e( 'Re-validate license', 'bricks' ); ?>" style="margin-right: 10px;"/>
				<?php if ( false !== $status && 'valid' === $status ) : ?>
					<span class="bricksextras-license-active"><?php esc_html_e( 'Active', 'bricks' ); ?></span>
				<?php endif; ?>
			<?php elseif ( false !== $status && 'valid' === $status ) : ?>
				<?php wp_nonce_field( self::$prefix . 'nonce', self::$prefix . 'nonce' ); ?>
				<input type="submit" class="button-primary" name="<?php echo esc_attr( self::$prefix ); ?>license_revalidate" value="<?php esc_attr_e( 'Re-validate license', 'bricks' ); ?>" style="margin-right: 10px;"/>
				<input type="submit" class="button-secondary" name="<?php echo esc_attr( self::$prefix ); ?>license_deactivate" value="<?php esc_attr_e( 'Deactivate license', 'bricks' ); ?>"/>
				<span class="bricksextras-license-active"><?php esc_html_e( 'Active', 'bricks' ); ?></span>
			<?php elseif ( $license_key && false !== $status ) : ?>
				<?php wp_nonce_field( self::$prefix . 'nonce', self::$prefix . 'nonce' ); ?>
				<input type="submit" class="button-primary" name="<?php echo esc_attr( self::$prefix ); ?>license_revalidate" value="<?php esc_attr_e( 'Re-validate license', 'bricks' ); ?>"/>
			<?php else : ?>
				<?php wp_nonce_field( self::$prefix . 'nonce', self::$prefix . 'nonce' ); ?>
				<input type="submit" class="button button-primary button-large" name="<?php echo esc_attr( self::$prefix ); ?>license_activate" value="<?php esc_attr_e( 'Activate License', 'bricksextras' ); ?>"/>
			<?php endif; ?>
				

			</form>

				

			<?php

			echo '<hr style="margin: 30px 0 20px 0;" /><p style="margin-top: 2.5em;">';
				echo esc_html__( 'NOTE: If your site has changed to a new location (migration, staging), click "Re-validate license" to license the new domain and receive updates.', 'bricksextras' );
			echo '</p>';

			echo '<hr style="margin: 30px 0 20px 0;" /><p>';

				echo esc_html__( 'The selected elements can be found inside the Bricks editor in the elements list under EXTRAS section near the bottom.', 'bricksextras' );

			echo '</p>';

			printf( '<img src="%s" alt="%s" width="300" />', esc_url( plugins_url( 'img/bricksextras-in-add-panel.png', __FILE__ ) ), esc_attr( 'BricksExtras in Add panel' ) );
			echo '</div>';
	}

	/**
	 * Register license key setting with WordPress Settings API.
	 *
	 * @return void
	 */
	public static function register_option() {
		// Creates our settings in the options table.
		register_setting( self::$prefix . 'license', self::$prefix . 'license_key', array( __CLASS__, 'license_key_change_callback' ) );
	}

	/**
	 * License key change callback.
	 *
	 * @param string $new_value New license key value.
	 * @return string New license key value.
	 */
	public static function license_key_change_callback( $new_value ) {
		$old       = get_option( self::$prefix . 'license_key' );
		$new_value = sanitize_text_field( $new_value );
		if ( $old && $old !== $new_value ) {
			delete_option( self::$prefix . 'license_status' ); // New license has been entered, so must reactivate.
		}
		return $new_value;
	}

	/**
	 * Process license activation with EDD API.
	 *
	 * @param string $license License key to activate.
	 * @return void
	 */
	private static function process_license_activation( $license ) {
		ob_start();

		// Data to send in our API request.
		$api_params = array(
			'edd_action' => 'activate_license',
			'license'    => $license,
			'item_name'  => rawurlencode( self::$title ),
			'url'        => home_url(),
		);

		// Call the custom API.
		$response = wp_remote_post(
			self::$store_url,
			array(
				'timeout'   => 15,
				'sslverify' => false,
				'body'      => $api_params,
			)
		);

		// Make sure the response came back okay.
		if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {

			if ( is_wp_error( $response ) ) {
				$message = $response->get_error_message();
			} else {
				$message = esc_html__( 'An error occurred, please try again.', 'bricksextras' );
			}
		} else {

			$license_data = json_decode( wp_remote_retrieve_body( $response ) );

			if ( false === $license_data->success ) {

				switch ( $license_data->error ) {

					case 'expired':
						$message = esc_html(
							sprintf(
								/* translators: %s: expiration date */
								__( 'Your license key expired on %s.', 'bricksextras' ),
								date_i18n( get_option( 'date_format' ), strtotime( $license_data->expires, current_time( 'timestamp' ) ) )
							)
						);
						break;

					case 'disabled':
					case 'revoked':
						$message = esc_html__( 'Your license key has been disabled.', 'bricksextras' );
						break;

					case 'missing':
						$message = esc_html__( 'Invalid license.', 'bricksextras' );
						break;

					case 'invalid':
					case 'site_inactive':
						$message = esc_html__( 'Your license is not active for this URL.', 'bricksextras' );
						break;

					case 'item_name_mismatch':
						/* translators: %s: product title */
						$message = esc_html( sprintf( __( 'This appears to be an invalid license key for %s.', 'bricksextras' ), self::$title ) );
						break;

					case 'no_activations_left':
						$message = esc_html__( 'Your license key has reached its activation limit.', 'bricksextras' );
						break;

					default:
						$message = esc_html__( 'An error occurred, please try again.', 'bricksextras' );
						break;
				}
			}
		}

		// Check if anything passed on a message constituting a failure.
		if ( ! empty( $message ) ) {
			$base_url = add_query_arg( 'tab', 'license', menu_page_url( self::$menu_slug ) );
			$redirect = add_query_arg(
				array(
					'sl_activation' => 'false',
					'message'       => rawurlencode( $message ),
					'nonce'         => wp_create_nonce( self::$prefix . 'license_nonce' ),
				),
				$base_url
			);

			wp_safe_redirect( $redirect );
			exit();
		}

		// $license_data->license will be either "valid" or "invalid"
		update_option( self::$prefix . 'license_status', $license_data->license );

		// Store the URL for auto-revalidation on domain change.
		if ( 'valid' === $license_data->license ) {
			update_option( self::$prefix . 'license_url', md5( home_url() ) );
		}

		wp_safe_redirect( add_query_arg( 'tab', 'license', menu_page_url( self::$menu_slug ) ) );
		exit();
	}

	/**
	 * Handle license activation form submission.
	 *
	 * @return void
	 */
	public static function activate_license() {

		// Listen for our activate button to be clicked.
		if ( isset( $_POST[ self::$prefix . 'license_activate' ] ) ) {
			// Run a quick security check.
			if ( ! check_admin_referer( self::$prefix . 'nonce', self::$prefix . 'nonce' ) ) {
				return; // Get out if we didn't click the Activate button.
			}

			// Retrieve the license from the database.
			$license = Helpers::get_post_value( self::$prefix . 'license_key' );
			$license = $license ? $license : false;

			update_option( self::$prefix . 'license_key', $license );

			self::process_license_activation( $license );
		}
	}

	/**
	 * Handle license revalidation form submission.
	 *
	 * @return void
	 */
	public static function revalidate_license() {

		// Listen for our revalidate button to be clicked.
		if ( isset( $_POST[ self::$prefix . 'license_revalidate' ] ) ) {
			// Run a quick security check.
			if ( ! check_admin_referer( self::$prefix . 'nonce', self::$prefix . 'nonce' ) ) {
				return; // Get out if we didn't click the Re-validate button.
			}

			// Check if a new license key was entered in the form.
			$posted_license = Helpers::get_post_value( self::$prefix . 'license_key' );

			// If a new key was entered, update it in the database.
			if ( ! empty( $posted_license ) ) {
				update_option( self::$prefix . 'license_key', $posted_license );
				$license = $posted_license;
			} else {
				// Otherwise, retrieve the license from constant or database.
				$license = self::get_license_key();
			}

			if ( ! $license ) {
				$message  = __( 'No license key found. Please enter your license key and activate.', 'bricksextras' );
				$base_url = add_query_arg( 'tab', 'license', menu_page_url( self::$menu_slug ) );
				$redirect = add_query_arg(
					array(
						'sl_activation' => 'false',
						'message'       => rawurlencode( $message ),
						'nonce'         => wp_create_nonce( self::$prefix . 'license_nonce' ),
					),
					$base_url
				);
				wp_safe_redirect( $redirect );
				exit();
			}

			self::process_license_activation( $license );
		}
	}

	/**
	 * Handle license deactivation form submission.
	 *
	 * @return void
	 */
	public static function deactivate_license() {

		// Listen for our deactivate button to be clicked.
		if ( isset( $_POST[ self::$prefix . 'license_deactivate' ] ) ) {
			ob_start();
			// Run a quick security check.
			if ( ! check_admin_referer( self::$prefix . 'nonce', self::$prefix . 'nonce' ) ) {
				return; // Get out if we didn't click the Activate button.
			}

			// Retrieve the license from the database.
			$license      = trim( get_option( self::$prefix . 'license_key' ) );
			$post_license = Helpers::get_post_value( self::$prefix . 'license_key' );
			$license      = $post_license && strlen( $post_license ) > 8 ? $post_license : $license;

			// Data to send in our API request.
			$api_params = array(
				'edd_action' => 'deactivate_license',
				'license'    => $license,
				'item_id'    => self::$item_id,
				'item_name'  => rawurlencode( self::$title ), // The name of our product in EDD.
				'url'        => home_url(),
			);

			// Call the custom API.
			$response = wp_remote_post(
				self::$store_url,
				array(
					'timeout'   => 15,
					'sslverify' => false,
					'body'      => $api_params,
				)
			);

			// Make sure the response came back okay.
			if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {

				if ( is_wp_error( $response ) ) {
					$message = $response->get_error_message();
				} else {
					$message = esc_html__( 'An error occurred, please try again.', 'bricksextras' );
				}

				$base_url = add_query_arg( 'tab', 'license', menu_page_url( self::$menu_slug ) );
				$redirect = add_query_arg(
					array(
						'sl_activation' => 'false',
						'message'       => rawurlencode( $message ),
						'nonce'         => wp_create_nonce( self::$prefix . 'license_nonce' ),
					),
					$base_url
				);

				wp_safe_redirect( $redirect );
				exit();
			}

			// Decode the license data.
			$license_data = json_decode( wp_remote_retrieve_body( $response ) );

			delete_option( self::$prefix . 'license_status' );
			delete_option( self::$prefix . 'license_key' );
			delete_option( self::$prefix . 'license_key_hash' );

			wp_safe_redirect( add_query_arg( 'tab', 'license', menu_page_url( self::$menu_slug ) ) );
			exit();

		}
	}

	/**
	 * Display admin notices for license activation/deactivation results.
	 *
	 * @return void
	 */
	public static function admin_notices() {
		$nonce         = Helpers::get_get_value( 'nonce' );
		$sl_activation = Helpers::get_get_value( 'sl_activation' );
		$message_param = Helpers::get_get_value( 'message' );

		if ( $sl_activation && $message_param && $nonce && wp_verify_nonce( $nonce, self::$prefix . 'license_nonce' ) ) {

			switch ( $sl_activation ) {

				case 'false':
					$message = urldecode( $message_param );
					?>
					<div class="error">
						<p><?php echo esc_html( $message ); ?></p>
					</div>
					<?php
					break;

				case 'true':
				default:
					// Developers can put a custom success message here for when activation is successful if they way.
					break;

			}
		}
	}
}