<?php
/**
 * CacheRepository class.
 *
 * Group-aware transient-based cache wrapper.
 *
 * @package Ilabs\Firevert\Core\Repository\Cache
 */

declare( strict_types=1 );

namespace Ilabs\Firevert\Core\Repository\Cache;

/**
 * Class CacheRepository
 */
class CacheRepository {

	/**
	 * Stores cached data and tracks it under a group.
	 *
	 * @param string $key   Cache key.
	 * @param mixed  $value Cached value.
	 * @param int    $ttl   Time to live (in seconds).
	 * @param string $group Optional group name.
	 *
	 * @return void
	 */
	public function set( string $key, $value, int $ttl = HOUR_IN_SECONDS, string $group = '' ): void {
		$cache_key = $this->prefix( $key );
		set_transient( $cache_key, $value, $ttl );

		if ( '' !== $group ) {
			$this->track_group_key( $group, $cache_key );
		}
	}

	/**
	 * Retrieves cached data.
	 *
	 * @param string $key Cache key.
	 *
	 * @return mixed|false Cached value or false if not found.
	 */
	public function get( string $key ) {
		return get_transient( $this->prefix( $key ) );
	}

	/**
	 * Deletes a specific cache key.
	 *
	 * @param string $key Cache key.
	 *
	 * @return void
	 */
	public function delete( string $key ): void {
		delete_transient( $this->prefix( $key ) );
	}

	/**
	 * Clears all cache items under a given group.
	 *
	 * @param string $group Group identifier.
	 *
	 * @return void
	 */
	public function flush_group( string $group ): void {
		$group_option = $this->group_key( $group );
		$keys         = get_option( $group_option, array() );

		foreach ( $keys as $cache_key ) {
			delete_transient( $cache_key );
		}

		delete_option( $group_option );
	}

	/**
	 * Tracks a cache key under a named group.
	 *
	 * @param string $group     Group name.
	 * @param string $cache_key Actual transient key.
	 *
	 * @return void
	 */
	private function track_group_key( string $group, string $cache_key ): void {
		$group_option = $this->group_key( $group );
		$keys         = get_option( $group_option, array() );

		if ( ! in_array( $cache_key, $keys, true ) ) {
			$keys[] = $cache_key;
			update_option( $group_option, $keys );
		}
	}

	/**
	 * Returns a consistent prefixed cache key.
	 *
	 * @param string $key Raw key.
	 *
	 * @return string Prefixed key.
	 */
	private function prefix( string $key ): string {
		return 'firevert_cache_' . $key;
	}

	/**
	 * Returns a consistent group option key.
	 *
	 * @param string $group Group name.
	 *
	 * @return string Group storage key.
	 */
	private function group_key( string $group ): string {
		return 'firevert_cache_group_' . sanitize_key( $group );
	}
}
