<?php
/**
 * Migration: create `affilun_embeds` table (schema version 3).
 *
 * Installs the reusable embed-definition table described in
 * `specifications/database-schema.md` §6. The table holds reusable
 * product-display definitions (single-card, grid, future comparison
 * views) that can be invoked from shortcodes, admin-managed reusable
 * references, and future shared-display features. Per §6.1, this table
 * is NOT the canonical storage for Gutenberg block content: the initial
 * Gutenberg block keeps `productId` / `productIds` in the post body
 * directly, and `affilun_embeds` is an auxiliary reusable-definition model.
 *
 * This migration targets {@see SchemaVersion::of(3)} — the third step
 * in affilun's schema pipeline, installed after
 * `affilun_products` (v1) and `affilun_product_meta` (v2).
 *
 * Scope of this migration:
 *
 *   - Creates `{$prefix}affilun_embeds` with the full column set defined
 *     in §6.2 (nine columns: surrogate primary key, externally-visible
 *     prefixed-ULID uuid, optional management name, type discriminator,
 *     JSON configuration blob, created/updated actor references, and
 *     audit timestamps).
 *
 *   - Adds the unique constraint on `uuid` (§6.3) and the three
 *     secondary indexes listed in §6.3 (`idx_type`, `idx_created_by`,
 *     `idx_updated_at`).
 *
 *   - Uses the charset/collation returned by
 *     `$wpdb->get_charset_collate()` (per §17.2) and relies on
 *     `InnoDB` as the storage engine (§17.1).
 *
 * Scope explicitly NOT covered here:
 *
 *   - `CHECK (type IN ('single','grid'))` constraint. §6.2 describes
 *     the allowed type values as the initial-version enum, but
 *     `dbDelta()` does not reliably round-trip `CHECK` constraints
 *     across MySQL / MariaDB versions (per §13.4's "avoid
 *     environment-sensitive clauses" rule). Application-layer
 *     validation (REST, embed write path) is the canonical enforcement
 *     point, matching the approach used for the `items.length`
 *     constraint described in §7.4.
 *
 *   - Foreign keys to `wp_users.ID` for `created_by` / `updated_by`.
 *     Per §11.2 and §13.4, AFFILUN does not declare foreign keys at the
 *     DB level; referential integrity is enforced by the application
 *     layer on embed-write paths.
 *
 *   - `DEFAULT CURRENT_TIMESTAMP` on `created_at` / `updated_at`. Per
 *     §13.4, environment-sensitive default clauses are avoided;
 *     timestamps are supplied by the application layer on insert /
 *     update.
 *
 *   - Any DML. This migration creates the empty table only; seed data
 *     and backfills belong in later migrations or runtime code paths.
 *
 * The shared DDL-assembly and installer-dispatch skeleton lives in
 * {@see AbstractCreateTableMigration}; this subclass only declares the
 * bits that actually differ between tables (target version,
 * description, logical name, column manifest, index manifest). See the
 * base class's file-level docblock for the idempotency and
 * failure-propagation guarantees inherited here.
 *
 * @package Affilun\Infrastructure\Persistence\Migrations
 */

declare(strict_types=1);

namespace Affilun\Infrastructure\Persistence\Migrations;

use Affilun\Infrastructure\Persistence\SchemaVersion;

/**
 * Creates the `affilun_embeds` table at schema version 3.
 *
 * Concrete {@see AbstractCreateTableMigration} subclass. See the
 * file-level docblock for the scope of this migration and the columns
 * and indexes it installs; see the base class for the formatting rules
 * and failure semantics that apply to every AFFILUN table-creation
 * migration.
 */
final class CreateEmbedsTable extends AbstractCreateTableMigration {

	/**
	 * Logical, unprefixed AFFILUN table name installed by this migration.
	 *
	 * Kept as a class-level constant so tests can reference the exact
	 * name without duplicating the string literal, and so a future
	 * rename has a single location to update.
	 */
	public const TABLE_LOGICAL_NAME = 'affilun_embeds';

	/**
	 * Target schema version installed by this migration.
	 *
	 * Returns version 3 — the revision that adds the reusable
	 * embed-definition table on top of `affilun_products` (v1) and
	 * `affilun_product_meta` (v2). See `database-schema.md` §13.2 for the
	 * canonical version numbering.
	 */
	public function targetVersion(): SchemaVersion {
		return SchemaVersion::of( 3 );
	}

	/**
	 * Short, human-readable description of this migration.
	 *
	 * Used by the diagnostics surface and migration logs. Kept terse
	 * and operator-friendly per the
	 * {@see \Affilun\Infrastructure\Persistence\Migration::description()}
	 * contract.
	 */
	public function description(): string {
		return 'create affilun_embeds table';
	}

	/**
	 * Logical, unprefixed AFFILUN table name installed by this migration.
	 *
	 * Consumed by {@see AbstractCreateTableMigration::up()} and
	 * {@see AbstractCreateTableMigration::tableName()} to resolve the
	 * physical, prefix-applied name through the injected
	 * {@see \Affilun\Infrastructure\Persistence\TableNameResolver}.
	 */
	protected function logicalTableName(): string {
		return self::TABLE_LOGICAL_NAME;
	}

	/**
	 * Column definitions for `affilun_embeds`, in the canonical order
	 * defined by `database-schema.md` §6.2.
	 *
	 * The `uuid` column is sized `varchar(32)` to accommodate the
	 * prefixed-ULID format `emb_<26 chars Crockford base32>` defined in
	 * §6.2 (4-character prefix `emb_` + 26 base32 characters = 30
	 * characters, with headroom for format evolution).
	 *
	 * The `type` column is sized `varchar(16)` so the initial enum
	 * (`single` / `grid`) fits comfortably alongside the future
	 * `comparison` extension tracked in §6.2's accompanying note.
	 *
	 * Each entry is a single column definition without its trailing
	 * comma; the base class adds the indent and inter-column commas.
	 *
	 * @return list<string>
	 */
	protected function columnDefinitions(): array {
		return array(
			'id bigint unsigned NOT NULL AUTO_INCREMENT',
			'uuid varchar(32) NOT NULL',
			'name varchar(191) NULL',
			'type varchar(16) NOT NULL',
			'config_json longtext NOT NULL',
			'created_by bigint unsigned NULL',
			'updated_by bigint unsigned NULL',
			'created_at datetime NOT NULL',
			'updated_at datetime NOT NULL',
		);
	}

	/**
	 * Index definitions for `affilun_embeds`, in the canonical order
	 * defined by `database-schema.md` §6.3.
	 *
	 * The `PRIMARY KEY` entry uses the two-space separator that
	 * `dbDelta()` relies on to detect the primary key line — this is
	 * a WordPress-specific formatting quirk, not a typo.
	 *
	 * @return list<string>
	 */
	protected function indexDefinitions(): array {
		return array(
			'PRIMARY KEY  (id)',
			'UNIQUE KEY uq_uuid (uuid)',
			'KEY idx_type (type)',
			'KEY idx_created_by (created_by)',
			'KEY idx_updated_at (updated_at)',
		);
	}
}
