<?php
/**
 * Cache key factory and invalidation helper for plugin repositories.
 *
 * @since   1.0.0
 * @package DonationRouter
 */

declare( strict_types=1 );
namespace DonationRouter;

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

/**
 * Centralises cache key generation and group-level invalidation.
 *
 * All repositories obtain their keys from this class so that key schemas
 * remain consistent and changes are made in one place.
 *
 * @since 1.0.0
 */
class Cache_Manager {

	/**
	 * WordPress object cache group for all plugin data.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	public const GROUP = 'ador';

	/**
	 * TTL for individual record cache entries (one hour).
	 *
	 * @since 1.0.0
	 *
	 * @var int
	 */
	public const TTL_RECORD = 3_600;

	/**
	 * TTL for list query cache entries (ten minutes).
	 *
	 * @since 1.0.0
	 *
	 * @var int
	 */
	public const TTL_LIST = 600;

	/**
	 * Return the cache key for a PayPal account looked up by primary key.
	 *
	 * @since 1.0.0
	 *
	 * @param  int $id  Database row ID.
	 *
	 * @return string
	 */
	public function get_account_by_id_key( int $id ): string {
		return 'account_id_' . $id;
	}

	/**
	 * Return the cache key for a PayPal account looked up by merchant ID.
	 *
	 * @since 1.0.0
	 *
	 * @param  string $merchant_id  PayPal merchant identifier.
	 *
	 * @return string
	 */
	public function get_account_by_merchant_id_key( string $merchant_id ): string {
		return 'account_mid_' . md5( $merchant_id ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_md5
	}

	/**
	 * Return the cache key for a routing rule looked up by country code.
	 *
	 * @since 1.0.0
	 *
	 * @param  string $code  ISO 3166-1 alpha-2 country code.
	 *
	 * @return string
	 */
	public function get_country_routing_by_country_key( string $code ): string {
		return 'routing_cc_' . strtoupper( $code );
	}

	/**
	 * Return the cache key for a routing rule looked up by form ID.
	 *
	 * @since 1.0.0
	 *
	 * @param  int $form_id  GiveWP donation form post ID.
	 *
	 * @return string
	 */
	public function get_country_routing_by_form_key( int $form_id ): string {
		return 'routing_fid_' . $form_id;
	}

	/**
	 * Return the cache key for the list of all accounts (active and inactive).
	 *
	 * @since 1.0.0
	 *
	 * @return string
	 */
	public function get_all_accounts_key(): string {
		return 'all_accounts';
	}

	/**
	 * Return the cache key for the list of all active accounts.
	 *
	 * @since 1.0.0
	 *
	 * @return string
	 */
	public function get_all_active_accounts_key(): string {
		return 'all_active_accounts';
	}

	/**
	 * Return the cache key for the list of all active routing rules.
	 *
	 * @since 1.0.0
	 *
	 * @return string
	 */
	public function get_all_active_routings_key(): string {
		return 'all_active_routings';
	}

	/**
	 * Return the cache key for the list of all routing rules (active and inactive).
	 *
	 * @since 1.0.0
	 *
	 * @return string
	 */
	public function get_all_routings_key(): string {
		return 'all_routings';
	}

	/**
	 * Remove all cache entries related to the given account.
	 *
	 * @since 1.0.0
	 *
	 * @param  PayPal_Account $account  The account whose entries should be purged.
	 *
	 * @return void
	 */
	public function invalidate_account( PayPal_Account $account ): void {
		wp_cache_delete( $this->get_all_accounts_key(), self::GROUP );
		wp_cache_delete( $this->get_all_active_accounts_key(), self::GROUP );
		wp_cache_delete( $this->get_account_by_merchant_id_key( $account->merchant_id ), self::GROUP );

		if ( null !== $account->id ) {
			wp_cache_delete( $this->get_account_by_id_key( $account->id ), self::GROUP );
		}
	}

	/**
	 * Remove all cache entries related to the given routing rule.
	 *
	 * @since 1.0.0
	 *
	 * @param  Country_Routing $routing  The routing rule whose entries should be purged.
	 *
	 * @return void
	 */
	public function invalidate_country_routing( Country_Routing $routing ): void {
		wp_cache_delete( $this->get_all_routings_key(), self::GROUP );
		wp_cache_delete( $this->get_all_active_routings_key(), self::GROUP );
		wp_cache_delete( $this->get_country_routing_by_country_key( $routing->country_code ), self::GROUP );
		wp_cache_delete( $this->get_country_routing_by_form_key( $routing->form_id ), self::GROUP );

		if ( null !== $routing->id ) {
			wp_cache_delete( 'routing_id_' . $routing->id, self::GROUP );
		}
	}

	/**
	 * Flush the entire plugin cache group.
	 *
	 * Requires WP 6.1+ for group-level flushing.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function invalidate_all(): void {
		wp_cache_flush_group( self::GROUP );
	}
}
