<?php
/**
 * Tracks online users via WordPress transients and Heartbeat API.
 * Updates and cleans user activity status, and provides retrieval methods.
 *
 * @package AuthorKit
 * @since 1.0.0
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}
/**
 * Class Author_Kit_Online_User
 *
 * Handles tracking of online users using WordPress transients and Heartbeat API.
 * This class keeps track of active users, determines their online status,
 * and provides methods for retrieving online user information.
 *
 * Features:
 * - Uses WordPress transients to store online users.
 * - Updates online status on page load and via Heartbeat API.
 * - Cleans up inactive users who haven't sent a heartbeat within the threshold.
 * - Provides utility methods to check user online status and retrieve data.
 */
class Author_Kit_Online_User {


	/**
	 * The transient key for storing online users.
	 *
	 * @var string
	 */
	private $transient_key = 'author_kit_online_users';

	/**
	 * Time (in seconds) after which transient expires.
	 *
	 * @var int
	 */
	private $transient_expiration = 60; // 1 minute expiration

	/**
	 * Time (in seconds) threshold for marking a user offline.
	 *
	 * @var int
	 */
	private $offline_threshold = 15; // Users are considered offline after 15 seconds.


	/**
	 * Constructor - Hooks necessary actions and filters.
	 */
	public function __construct() {
		// Update user online status when WordPress initializes.
		add_action( 'init', array( $this, 'update_user_status' ) );
		add_action( 'admin_init', array( $this, 'update_user_status' ) );
		add_action( 'author_kit_plugin_activate', array( $this, 'update_user_status' ) );

		// Modify Heartbeat API settings.
		add_filter( 'heartbeat_settings', array( $this, 'modify_heartbeat_interval' ) );

		// Process Heartbeat API responses to update user status.
		add_filter( 'heartbeat_received', array( $this, 'handle_heartbeat_update' ), 10, 2 );

		// Enqueue Heartbeat API script in the admin panel.
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_heartbeat_script' ) );
	}

	/**
	 * Enqueue WordPress Heartbeat API script.
	 */
	public function enqueue_heartbeat_script() {
		wp_enqueue_script( 'heartbeat' );
		wp_enqueue_script(
			'author-kit-heartbeat-global',
			AUTHOR_KIT_PLUGIN_URL . 'admin/assets/js/author-kit-heartbeat-api.js',
			array( 'jquery', 'heartbeat' ),
			AUTHOR_KIT_VERSION,
			true
		);

		// Pass AJAX URL and nonce to JavaScript.
		wp_localize_script(
			'author-kit-heartbeat-global',
			'author_kit_heartbeat_vars',
			array(
				'ajax_url' => admin_url( 'admin-ajax.php' ),
				'nonce'    => wp_create_nonce( 'heartbeat_nonce' ),
			)
		);
	}

	/**
	 * Modify WordPress Heartbeat API interval to 5 seconds.
	 *
	 * @param array $settings The existing Heartbeat settings.
	 * @return array Modified settings with adjusted interval.
	 */
	public function modify_heartbeat_interval( $settings ) {
		$settings['interval'] = 5; // Default is 60 seconds, reducing to 5.
		return $settings;
	}

	/**
	 * Handle Heartbeat API response and update user status.
	 *
	 * @param array $response The Heartbeat response array.
	 * @param array $data The data sent via Heartbeat.
	 * @return array Updated response with online users list.
	 */
	public function handle_heartbeat_update( $response, $data ) {
		if ( isset( $data['check_online_status'] ) ) {
			$user_id = get_current_user_id();
			if ( ! $user_id ) {
				return $response; // Skip if user is not logged in.
			}

			// Get the current list of online users.
			$online_users = $this->get_online_users();

			// Update the current user's last active timestamp.
			$online_users[ $user_id ] = time();
			$this->save_online_users( $online_users );

			// Remove inactive users who haven't sent a heartbeat recently.
			$this->cleanup_inactive_users();

			// Return updated online users list.
			$response['user_online'] = array(
				'online_users' => $this->get_online_users_array(),
			);
		}
		return $response;
	}

	/**
	 * Update the current user's online status when a page is loaded.
	 */
	public function update_user_status() {
		$user_id = get_current_user_id();
		if ( ! $user_id ) {
			return; // Skip if user is not logged in.
		}

		// Get the current list of online users.
		$online_users = $this->get_online_users();

		// Update the user's last active timestamp.
		$online_users[ $user_id ] = time();
		$this->save_online_users( $online_users );

		// Remove inactive users.
		$this->cleanup_inactive_users();
	}

	/**
	 * Check if a user is currently online.
	 *
	 * @param int $user_id The user ID to check.
	 * @return bool True if the user is online, false otherwise.
	 */
	public function is_user_online( $user_id ) {
		$online_users = $this->get_online_users();
		return isset( $online_users[ $user_id ] ) && ( time() - $online_users[ $user_id ] < $this->offline_threshold );
	}

	/**
	 * Get the last active timestamp of a user.
	 *
	 * @param int $user_id The user ID to check.
	 * @return int|false The timestamp if found, or false if not available.
	 */
	public function get_user_last_online( $user_id ) {
		$online_users = $this->get_online_users();
		return $online_users[ $user_id ] ?? false;
	}

	/**
	 * Get the count of currently online users.
	 *
	 * @return int The number of online users.
	 */
	public function get_online_user_count() {
		return count( $this->get_online_users() );
	}

	/**
	 * Get an array of online user IDs.
	 *
	 * @return array The list of online user IDs.
	 */
	public function get_online_users_array() {
		return array_keys( $this->get_online_users() );
	}

	/**
	 * Retrieve online users from the transient storage.
	 *
	 * @return array Associative array of user IDs and last active timestamps.
	 */
	private function get_online_users() {
		$users = get_transient( $this->transient_key );
		return ( false === $users ) ? array() : $users;
	}

	/**
	 * Save the online users list to transient storage.
	 *
	 * @param array $online_users The list of online users.
	 */
	private function save_online_users( $online_users ) {
		set_transient( $this->transient_key, $online_users, $this->transient_expiration );
	}

	/**
	 * Remove users who haven't sent a heartbeat within the offline threshold.
	 */
	private function cleanup_inactive_users() {
		$online_users = $this->get_online_users();
		$current_time = time();

		foreach ( $online_users as $user_id => $last_active ) {
			if ( ( $current_time - $last_active ) > $this->offline_threshold ) {
				unset( $online_users[ $user_id ] ); // Remove inactive users.
			}
		}
		$this->save_online_users( $online_users );
	}
}


// Instantiate the class so that hooks are registered.
if ( class_exists( 'Author_Kit_Online_User' ) ) {
	$GLOBALS['author_kit_online_user'] = new Author_Kit_Online_User();
}
