<?php
/**
 * Table name resolver abstraction.
 *
 * affilun writes to a fixed set of plugin-owned tables
 * (`affilun_products`, `affilun_product_meta`, `affilun_embeds`, ...) whose
 * physical names depend on the WordPress site's table prefix. The
 * prefix is read from `$wpdb->prefix` at runtime and is not known at
 * compile time, so every DDL and DML call site that needs a physical
 * table name routes the resolution through this interface.
 *
 * Decoupling logical from physical names gives us three practical
 * benefits:
 *
 *   1. Migration classes can be unit-tested against an in-memory fake
 *      that maps logical names to deterministic test-only strings
 *      (for example `test_affilun_products`), without standing up a
 *      `$wpdb` instance or a real database connection.
 *
 *   2. Multisite installations that vary the prefix per site ID
 *      (`wp_2_`, `wp_3_`, ...) can inject a resolver that reads the
 *      active site's prefix on each call, rather than caching a value
 *      that was correct only at plugin-load time.
 *
 *   3. Future refactors that want to migrate a table to a new name
 *      have one seam to update, instead of every call site that
 *      concatenates `$wpdb->prefix` with a string literal.
 *
 * Naming contract:
 *
 *   - Logical names are the bare, unprefixed identifiers used in
 *     `specifications/database-schema.md` — for example
 *     `affilun_products`, `affilun_embed_items`, `affilun_sync_jobs`. They are
 *     ASCII, lowercase, and already include the `affilun_` plugin prefix
 *     that distinguishes AFFILUN tables from WordPress core and other
 *     plugins' tables.
 *
 *   - Physical names are whatever the resolver produces after applying
 *     the site's table prefix — typically `{$wpdb->prefix}affilun_products`
 *     in production (`wp_affilun_products` on a default install).
 *
 * Implementations MUST:
 *
 *   - Return a non-empty string for every well-known logical name.
 *     Resolvers are not expected to validate the logical name against
 *     a whitelist; callers pass the literal names they own, and a
 *     typo is a programming error that will surface as a missing-
 *     table SQL error, not as a silent empty string.
 *
 *   - Be pure and side-effect-free. Resolving a name MUST NOT issue
 *     SQL, emit logs, or mutate shared state. The method is called on
 *     the hot path (once per query) and must stay cheap.
 *
 *   - Be stable within a single request. Repeat calls with the same
 *     logical name MUST return the same physical name so that a
 *     migration that resolves a table name for its `CREATE TABLE` and
 *     then again for an index statement does not accidentally target
 *     two different physical tables.
 *
 * Implementations MAY cache resolved names internally and MAY apply
 * additional normalization (trimming, lowercasing) as long as the
 * stability contract above is preserved.
 *
 * @package Affilun\Infrastructure\Persistence
 */

declare(strict_types=1);

namespace Affilun\Infrastructure\Persistence;

/**
 * Maps logical AFFILUN table names to their physical, prefix-applied form.
 *
 * See the file-level docblock for the logical/physical naming contract
 * and the purity / stability requirements implementations must honor.
 */
interface TableNameResolver {

	/**
	 * Resolve a logical AFFILUN table name into its physical name.
	 *
	 * The logical name is the bare identifier used in the database
	 * schema specification (for example `affilun_products`). The returned
	 * physical name is whatever the host site uses after applying its
	 * table prefix (typically `{$wpdb->prefix}affilun_products`).
	 *
	 * Implementations MUST be pure and MUST return the same physical
	 * name for repeated calls with the same logical name within a
	 * single request; see the file-level docblock for the full
	 * contract.
	 *
	 * @param string $logicalName Logical, unprefixed AFFILUN table name
	 *                            (for example `affilun_products`).
	 *
	 * @return string Physical, prefix-applied table name suitable for
	 *                direct interpolation into SQL.
	 */
	public function resolve( string $logicalName ): string;
}
