<?php
/**
 * Provider discovery cache.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Provider;

use ScheduledChanges\Field\FieldCollection;

/**
 * Caches discovery by context, provider version, site schema, and generation.
 */
final class ProviderDiscoveryCache {
	private const GROUP             = 'scheduled_changes_provider_discovery';
	private const GENERATION_OPTION = 'scheduled_changes_provider_cache_generation';
	private const TTL               = HOUR_IN_SECONDS;

	/**
	 * @param callable():FieldCollection $discover Discovery callback.
	 */
	public function remember(
		FieldProvider $provider,
		ObjectContext $context,
		callable $discover
	): FieldCollection {
		$key    = $this->key( $provider, $context );
		$cached = wp_cache_get( $key, self::GROUP );

		if ( is_array( $cached ) ) {
			return FieldCollection::fromArray( $cached );
		}

		$fields = $discover();

		wp_cache_set( $key, $fields->toArray(), self::GROUP, self::TTL );

		return $fields;
	}

	public function invalidate(): void {
		$generation = (int) get_option( self::GENERATION_OPTION, 1 );
		update_option( self::GENERATION_OPTION, $generation + 1, false );
	}

	private function key( FieldProvider $provider, ObjectContext $context ): string {
		$generation = (int) get_option( self::GENERATION_OPTION, 1 );

		return hash(
			'sha256',
			implode(
				'|',
				array(
					$provider->id(),
					$provider->version(),
					$context->cacheKey(),
					defined( 'SCHEDULED_CHANGES_SCHEMA_VERSION' ) ? SCHEDULED_CHANGES_SCHEMA_VERSION : '0',
					(string) $generation,
				)
			)
		);
	}
}
