<?php
/**
 * Stats Manager Class.
 *
 * @package automation-web-platform
 */

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

/**
 * Class WAWP_Stats_Manager.
 * Uses Object Cache (if persistent) or transients to batch stat updates to prevent DB locks.
 */
class WAWP_Stats_Manager {
	use WAWP_Settings_Handler;

	/**
	 * Pending stats to commit on shutdown.
	 *
	 * @var array
	 */
	private $pending_stats = array();

	/**
	 * WAWP_Stats_Manager constructor.
	 */
	public function __construct() {
		add_action( 'shutdown', array( $this, 'commit_memory_to_cache' ) );
		add_action( 'wawp_sync_hourly_stats', array( $this, 'sync_cache_to_db' ) );

		if ( ! wp_next_scheduled( 'wawp_sync_hourly_stats' ) ) {
			wp_schedule_event( time(), 'hourly', 'wawp_sync_hourly_stats' );
		}
	}

	/**
	 * Increment a simple option stat.
	 *
	 * @param string $option_name Option name.
	 * @param int    $amount      Amount to increment.
	 */
	public function increment_stat( $option_name, $amount = 1 ) {
		if ( ! isset( $this->pending_stats[ $option_name ] ) ) {
			$this->pending_stats[ $option_name ] = 0;
		}
		$this->pending_stats[ $option_name ] += $amount;
	}

	/**
	 * Increment a stat inside an array option.
	 *
	 * @param string $option_name Option name.
	 * @param string $key         Array key.
	 * @param int    $amount      Amount to increment.
	 */
	public function increment_array_stat( $option_name, $key, $amount = 1 ) {
		if ( empty( $key ) ) {
			$key = 'unknown';
		}
		$hash = $option_name . '|||' . $key;
		if ( ! isset( $this->pending_stats[ $hash ] ) ) {
			$this->pending_stats[ $hash ] = 0;
		}
		$this->pending_stats[ $hash ] += $amount;
	}

	/**
	 * Increment a stat inside a 2D array option.
	 *
	 * @param string $option_name Option name.
	 * @param string $key1        First array key.
	 * @param string $key2        Second array key.
	 * @param int    $amount      Amount to increment.
	 */
	public function increment_multi_array_stat( $option_name, $key1, $key2, $amount = 1 ) {
		if ( empty( $key1 ) ) {
			$key1 = 'unknown';
		}
		if ( empty( $key2 ) ) {
			$key2 = 'unknown';
		}
		$hash = $option_name . '||MULTI||' . $key1 . '||MULTI||' . $key2;
		if ( ! isset( $this->pending_stats[ $hash ] ) ) {
			$this->pending_stats[ $hash ] = 0;
		}
		$this->pending_stats[ $hash ] += $amount;
	}

	/**
	 * Commit memory stats to object cache/transients.
	 */
	public function commit_memory_to_cache() {
		if ( empty( $this->pending_stats ) ) {
			return;
		}

		// Use persistent object caching if available, fallback to transients.
		$is_persistent = wp_using_ext_object_cache();

		$keys_to_sync = $is_persistent ? wp_cache_get( 'wawp_stats_sync_keys', 'wawp_stats' ) : get_transient( 'wawp_stats_sync_keys' );
		if ( ! is_array( $keys_to_sync ) ) {
			$keys_to_sync = array();
		}

		$keys_updated = false;

		foreach ( $this->pending_stats as $hash => $amount ) {
			if ( $amount <= 0 ) {
				continue;
			}

			$cache_key = 'wawp_stat_' . md5( $hash );

			if ( $is_persistent ) {
				if ( ! wp_cache_add( $cache_key, $amount, 'wawp_stats', 2 * HOUR_IN_SECONDS ) ) {
					wp_cache_incr( $cache_key, $amount, 'wawp_stats' );
				}
			} else {
				$current = (int) get_transient( $cache_key );
				set_transient( $cache_key, $current + $amount, 2 * HOUR_IN_SECONDS );
			}

			if ( ! in_array( $hash, $keys_to_sync, true ) ) {
				$keys_to_sync[] = $hash;
				$keys_updated   = true;
			}
		}

		if ( $keys_updated ) {
			if ( $is_persistent ) {
				wp_cache_set( 'wawp_stats_sync_keys', $keys_to_sync, 'wawp_stats', 2 * HOUR_IN_SECONDS );
			} else {
				set_transient( 'wawp_stats_sync_keys', $keys_to_sync, 2 * HOUR_IN_SECONDS );
			}
		}
	}

	/**
	 * Sync cached stats to database.
	 */
	public function sync_cache_to_db() {
		$is_persistent = wp_using_ext_object_cache();
		$keys_to_sync  = $is_persistent ? wp_cache_get( 'wawp_stats_sync_keys', 'wawp_stats' ) : get_transient( 'wawp_stats_sync_keys' );

		if ( empty( $keys_to_sync ) || ! is_array( $keys_to_sync ) ) {
			return;
		}

		foreach ( $keys_to_sync as $hash ) {
			$cache_key = 'wawp_stat_' . md5( $hash );
			$amount    = $is_persistent ? (int) wp_cache_get( $cache_key, 'wawp_stats' ) : (int) get_transient( $cache_key );

			if ( $amount > 0 ) {
				if ( strpos( $hash, '||MULTI||' ) !== false ) {
					list( $option_name, $key1, $key2 ) = explode( '||MULTI||', $hash, 3 );
					$stats                             = $this->get_wawp_setting( $option_name, array() );
					if ( ! isset( $stats[ $key1 ] ) ) {
						$stats[ $key1 ] = array();
					}
					$stats[ $key1 ][ $key2 ] = (int) ( $stats[ $key1 ][ $key2 ] ?? 0 ) + $amount;
					$this->update_wawp_setting( $option_name, $stats );
				} elseif ( strpos( $hash, '|||' ) !== false ) {
					list( $option_name, $key ) = explode( '|||', $hash, 2 );
					$stats                     = $this->get_wawp_setting( $option_name, array() );
					$stats[ $key ]             = (int) ( $stats[ $key ] ?? 0 ) + $amount;

					// Special limit for location stats.
					if ( WAWP_Settings_Registry::CHAT_LOCATION_STATS === $option_name && count( $stats ) > 500 ) {
						array_shift( $stats );
					}

					$this->update_wawp_setting( $option_name, $stats );
				} else {
					$option_name = $hash;
					$current     = (int) $this->get_wawp_setting( $option_name, 0 );
					$this->update_wawp_setting( $option_name, $current + $amount );
				}
			}

			if ( $is_persistent ) {
				wp_cache_delete( $cache_key, 'wawp_stats' );
			} else {
				delete_transient( $cache_key );
			}
		}

		if ( $is_persistent ) {
			wp_cache_delete( 'wawp_stats_sync_keys', 'wawp_stats' );
		} else {
			delete_transient( 'wawp_stats_sync_keys' );
		}
	}
}
