<?php
/**
 * Database key migration for the plugin rebrand.
 *
 * @package VendorTasksDokanClickUp
 */

namespace VendorTasksDokanClickUp\Migration;

use VendorTasksDokanClickUp\Queue\RetryScheduler;

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

/**
 * Renames persisted options, user meta, and scheduled cron from the legacy
 * "vendor_tasks_for_clickup" prefix to the rebranded
 * "vendor_tasks_dokan_clickup" prefix.
 *
 * The plugin was renamed from "Vendor Tasks for ClickUp" to
 * "Alamin Vendor Tasks for Dokan with ClickUp" (slug
 * alamin-vendor-tasks-dokan-clickup). Existing installs store settings and
 * per-vendor task state under the old prefix; this migration moves them in
 * place so upgrades are seamless. Runs once, gated by a DB version option.
 */
class KeyMigrator {

	/**
	 * Option that records the completed migration version.
	 */
	private const VERSION_OPTION = 'vendor_tasks_dokan_clickup_db_version';

	/**
	 * Current migration version. Bump when adding new migration steps.
	 */
	private const TARGET_VERSION = '1';

	/*
	 * Legacy identifiers from before the rebrand. These literals intentionally
	 * keep the old prefix and must NOT be renamed by find/replace passes.
	 */
	private const LEGACY_OPTION_PREFIX = 'vendor_tasks_for_clickup';
	private const LEGACY_META_PREFIX   = '_vendor_tasks_for_clickup';
	private const LEGACY_CRON_HOOK     = 'vendor_tasks_for_clickup_retry_queue';

	/**
	 * Rebranded identifiers.
	 */
	private const NEW_OPTION_PREFIX = 'vendor_tasks_dokan_clickup';
	private const NEW_META_PREFIX   = '_vendor_tasks_dokan_clickup';

	/**
	 * Run the migration once if it has not already completed.
	 */
	public function maybe_migrate(): void {
		if ( self::TARGET_VERSION === get_option( self::VERSION_OPTION ) ) {
			return;
		}

		$this->migrate_options();
		$this->migrate_user_meta();
		$this->migrate_cron();

		update_option( self::VERSION_OPTION, self::TARGET_VERSION, true );
	}

	/**
	 * Rename all options carrying the legacy prefix.
	 */
	private function migrate_options(): void {
		global $wpdb;

		$like = $wpdb->esc_like( self::LEGACY_OPTION_PREFIX ) . '%';

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->query(
			$wpdb->prepare(
				"UPDATE {$wpdb->options} SET option_name = REPLACE( option_name, %s, %s ) WHERE option_name LIKE %s",
				self::LEGACY_OPTION_PREFIX,
				self::NEW_OPTION_PREFIX,
				$like
			)
		);

		// Drop the now-stale autoloaded options cache so renamed values load.
		wp_cache_delete( 'alloptions', 'options' );
		wp_cache_flush();
	}

	/**
	 * Rename all user meta keys carrying the legacy prefix.
	 */
	private function migrate_user_meta(): void {
		global $wpdb;

		$like = $wpdb->esc_like( self::LEGACY_META_PREFIX ) . '%';

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->query(
			$wpdb->prepare(
				"UPDATE {$wpdb->usermeta} SET meta_key = REPLACE( meta_key, %s, %s ) WHERE meta_key LIKE %s",
				self::LEGACY_META_PREFIX,
				self::NEW_META_PREFIX,
				$like
			)
		);

		wp_cache_flush();
	}

	/**
	 * Clear the orphaned legacy retry cron and reschedule under the new hook.
	 */
	private function migrate_cron(): void {
		wp_clear_scheduled_hook( self::LEGACY_CRON_HOOK );

		// Constructor registers the custom cron interval before scheduling.
		( new RetryScheduler() )->schedule_cron();
	}
}
