<?php

namespace Formatrica\Setup;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}
/**
 * Database Schema Version Manager
 *
 * Manages database schema versioning and migrations for safe upgrades.
 * Records the current schema version to enable future migrations without data loss.
 */
final class Schema_Manager
{
    private const SCHEMA_VERSION_KEY = 'formatrica_db_version';
    private const CURRENT_VERSION = 4;

    /**
     * Get the currently installed database schema version
     *
     * @return int Version number (0 if not installed)
     */
    public function get_installed_version(): int
    {
        return (int) get_option(self::SCHEMA_VERSION_KEY, 0);
    }

    /**
     * Get the target schema version (defined in code)
     *
     * @return int Current version number
     */
    public function get_current_version(): int
    {
        return self::CURRENT_VERSION;
    }

    /**
     * Check if database needs upgrading
     *
     * @return bool True if migration is needed
     */
    public function needs_upgrade(): bool
    {
        return $this->get_installed_version() < self::CURRENT_VERSION;
    }

    /**
     * Run all pending migrations
     *
     * Executes migrations sequentially from installed version to current version.
     * Each migration is idempotent and can be safely re-run.
     *
     * @return void
     */
    public function run_migrations(): void
    {
        $installed = $this->get_installed_version();

        // Migration v1: Initial schema (already handled by Activator::create_tables)
        if ($installed < 1) {
            $this->migrate_to_v1();
        }

        // Migration v2: Save & Resume drafts (P6) — drafts + rate-bucket tables.
        if ($installed < 2) {
            $this->migrate_to_v2();
        }

        // Migration v3: Payments (P9) — order + event-ledger tables.
        if ($installed < 3) {
            $this->migrate_to_v3();
        }

        // Migration v4: rate-bucket table for the Free submission limiter (F-02).
        if ($installed < 4) {
            $this->migrate_to_v4();
        }

        // Record the reached version — but do NOT claim v4 unless its table
        // actually exists. A transient DB/permission failure during dbDelta must
        // retry on the next load rather than be permanently marked done (which
        // would leave the rate limiter failing open with no table forever).
        $reached = self::CURRENT_VERSION;
        if (!$this->rate_bucket_table_exists()) {
            $reached = min($reached, 3);
        }

        update_option(self::SCHEMA_VERSION_KEY, $reached, false);
    }

    /**
     * Whether the rate-bucket table (migration v4) actually exists.
     *
     * @return bool
     */
    private function rate_bucket_table_exists(): bool
    {
        global $wpdb;

        $table = $wpdb->prefix . 'formatrica_rate_buckets';

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- schema existence check
        $found = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table));

        return $found === $table;
    }

    /**
     * Migration to version 1
     *
     * Initial schema creation is handled by Activator::create_tables().
     * This migration just records the version number for future reference.
     *
     * @return void
     */
    private function migrate_to_v1(): void
    {
        // Tables are created by Activator::create_tables() using dbDelta
        // This method just marks version 1 as complete
        // No additional changes needed
    }

    /**
     * Migration to version 2 (historical: Save & Resume drafts tables).
     *
     * The drafts + rate-bucket tables are Pro-owned and now created by
     * Pro\Setup\Pro_Activator when the Pro package boots (versioned by its own
     * option, independent of this Free schema version). A Free install creates
     * nothing here. Kept as a no-op so the version bookkeeping stays sequential.
     *
     * @return void
     */
    private function migrate_to_v2(): void
    {
        // Pro-owned tables — see Pro\Setup\Pro_Activator::ensure_tables().
    }

    /**
     * Migration to version 3 (historical: payments tables).
     *
     * The payment order + event tables are Pro-owned and created by
     * Pro\Setup\Pro_Activator when the Pro package boots. A Free install creates
     * nothing here.
     *
     * @return void
     */
    private function migrate_to_v3(): void
    {
        // Pro-owned tables — see Pro\Setup\Pro_Activator::ensure_tables().
    }

    /**
     * Migration to version 4.
     *
     * Creates the rate-bucket table used by the Free submission rate limiter
     * (F-02: atomic counter replaces the racy transient read/increment/write).
     * The Pro edition also creates this table in Pro_Activator with identical
     * SQL; `CREATE TABLE IF NOT EXISTS` + dbDelta makes double-creation a no-op.
     *
     * @return void
     */
    private function migrate_to_v4(): void
    {
        global $wpdb;

        $charset = $wpdb->get_charset_collate();
        $rate_table = $wpdb->prefix . 'formatrica_rate_buckets';

        $sql_rate = "CREATE TABLE IF NOT EXISTS {$rate_table} (
            id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
            bucket_kind varchar(32) NOT NULL,
            bucket_key varchar(64) NOT NULL,
            count int unsigned NOT NULL DEFAULT 0,
            created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
            updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY  (id),
            UNIQUE KEY bucket (bucket_kind, bucket_key),
            KEY cleanup (created_at)
        ) {$charset};";

        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        dbDelta($sql_rate);
    }

    /**
     * Example future migration (commented out)
     *
     * When adding new fields/tables in future versions:
     *
     * private function migrate_to_v2(): void
     * {
     *     global $wpdb;
     *     $table = $wpdb->prefix . 'formatrica_submissions';
     *
     *     // Add new column with ALTER TABLE
     *     $wpdb->query(
     *         "ALTER TABLE {$table}
     *          ADD COLUMN new_field VARCHAR(255) DEFAULT NULL
     *          AFTER existing_field"
     *     );
     *
     *     // Or use dbDelta for idempotent changes
     *     require_once ABSPATH . 'wp-admin/includes/upgrade.php';
     *     dbDelta($sql);
     * }
     */
}
