<?php
/**
 * MU-Plugin: Object Cache Bootstrap
 *
 * Поддержка объектного кеша (Memcached/Redis) с изоляцией по сайтам.
 *
 * ИЗОЛЯЦИЯ КЛЮЧЕЙ (защита от смешивания данных между сайтами):
 *   WP_CACHE_KEY_SALT задаётся в wp-config.php на основе DB_NAME.
 *   Это гарантирует уникальные ключи для каждого сайта ДО загрузки
 *   object-cache.php (drop-in). Если в wp-config.php соль не задана,
 *   MU-плагин пробует выставить её через fallback + re-salt хаки.
 *
 * УСТАНОВКА MEMCACHED НА ПРОДЕ:
 *   1. Установить PHP-расширение: sudo apt install php-memcache
 *   2. wp plugin install memcached
 *   3. Скопировать drop-in:
 *      cp wp-content/plugins/memcached/object-cache.php wp-content/object-cache.php
 *   4. Плагин НЕ активировать.
 *
 * @package Dekart
 * @version 2.3
 */

// ============================================================
// 1. КОНСТАНТЫ — fallback, если не заданы в wp-config.php
// ============================================================

// WP_CACHE_KEY_SALT должна быть определена в wp-config.php.
// Если нет — пробуем задать здесь (хуже, но хоть что-то).
if ( ! defined( 'WP_CACHE_KEY_SALT' ) && defined( 'DB_NAME' ) ) {
	define( 'WP_CACHE_KEY_SALT', DB_NAME );
}

if ( ! defined( 'WP_REDIS_HOST' ) ) {
	define( 'WP_REDIS_HOST', '127.0.0.1' );
}
if ( ! defined( 'WP_REDIS_PORT' ) ) {
	define( 'WP_REDIS_PORT', 6379 );
}
if ( ! defined( 'WP_REDIS_DATABASE' ) ) {
	define( 'WP_REDIS_DATABASE', 0 );
}

// Re-salt для Memcached drop-in: WP_CACHE_KEY_SALT в MU-плагине
// слишком поздна (object-cache.php грузится раньше MU).
// Если у object-cache.php есть salt_keys() — вызываем напрямую.
if ( defined( 'DB_NAME' ) ) {
	add_action( 'muplugins_loaded', function () {
		global $wp_object_cache;
		if ( isset( $wp_object_cache ) && method_exists( $wp_object_cache, 'salt_keys' ) ) {
			$wp_object_cache->salt_keys( DB_NAME );
		}
	}, 0 );
}

// ============================================================
// 2. АВТООПРЕДЕЛЕНИЕ BACKEND
// ============================================================

function dekart_detect_cache_backend(): string {
	if ( class_exists( 'Memcache' ) || class_exists( 'Memcached' ) ) {
		$sock = @fsockopen( '127.0.0.1', 11211, $errno, $errstr, 0.5 );
		if ( $sock ) {
			fclose( $sock );
			return 'memcached';
		}
	}

	if ( class_exists( 'Predis\Client' ) ) {
		$sock = @fsockopen( '127.0.0.1', 6379, $errno, $errstr, 0.5 );
		if ( $sock ) {
			fclose( $sock );
			return 'redis';
		}
	}

	if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
		return 'dropin-no-connection';
	}

	return 'none';
}

// ============================================================
// 3. VERSIONED CACHE KEY
// ============================================================

function my_cache_version(): int {
	return (int) get_option( 'my_cache_version', 1 );
}

function my_cache_key( string $key ): string {
	return 'v:' . my_cache_version() . ':' . $key;
}

// ============================================================
// 4. ИНВАЛИДАЦИЯ КЕША
// ============================================================

function my_cache_bump_version(): void {
	static $running = false;
	if ( $running ) {
		return;
	}
	$running = true;

	wp_cache_flush();
	$v = my_cache_version();
	update_option( 'my_cache_version', $v + 1, false );

	$running = false;
}

add_action( 'update_option', function ( $option ) {
	if ( str_starts_with( $option, 'branch_' ) ) {
		my_cache_bump_version();
	}
}, 10, 1 );

add_action( 'save_post', 'my_cache_bump_version' );
add_action( 'carbon_fields_post_meta_container_saved', 'my_cache_bump_version' );

// ============================================================
// 5. АДМИН-НОТИСЫ
// ============================================================

/**
 * Убрать ссылку "Активировать" у плагина Memcached Object Cache.
 * Плагин — только источник object-cache.php, активация вызывает фатальную ошибку.
 */
add_filter( 'plugin_action_links_memcached/object-cache.php', function ( $actions ) {
	unset( $actions['activate'] );
	$actions['info'] = '<span style="color:#999">⚠ установите drop-in вручную</span>';
	return $actions;
} );

add_action( 'admin_notices', function () {
	if ( ! current_user_can( 'manage_options' ) ) {
		return;
	}

	$source = WP_CONTENT_DIR . '/plugins/memcached/object-cache.php';
	$target = WP_CONTENT_DIR . '/object-cache.php';

	if ( ! file_exists( $source ) ) {
		return; // плагин не установлен
	}
	if ( file_exists( $target ) ) {
		return; // drop-in уже стоит
	}

	if ( class_exists( 'Memcache' ) || class_exists( 'Memcached' ) ) {
		$conn = @fsockopen( '127.0.0.1', 11211, $errno, $errstr, 0.5 );
		if ( $conn ) {
			fclose( $conn );
			printf(
				'<div class="notice notice-info is-dismissible"><p>%s</p></div>',
				'<strong>Кеширование:</strong> Memcached доступен. Установите drop-in командой:
				<code>cp ' . esc_html( str_replace( ABSPATH, '', $source ) ) . ' ' . esc_html( str_replace( ABSPATH, '', $target ) ) . '</code>
				или через WP-CLI: <code>wp dekart cache-memcached</code>'
			);
			return;
		}
		printf(
			'<div class="notice notice-warning is-dismissible"><p>%s</p></div>',
			'<strong>Кеширование:</strong> PHP-расширение Memcache установлено, но сервер Memcached (127.0.0.1:11211) не отвечает.
			Запустите Memcached на сервере или обратитесь в хостинг.'
		);
		return;
	}

	printf(
		'<div class="notice notice-warning is-dismissible"><p>%s</p></div>',
		'<strong>Кеширование:</strong> Плагин Memcached Object Cache установлен, но PHP-расширение <code>memcache</code> не найдено.
		Установите его на сервере (через панель хостинга: PHP → Расширения → memcache).
		<strong>Не активируйте плагин</strong> — он работает как drop-in.'
	);
} );

// ============================================================
// 6. WP-CLI
// ============================================================

if ( defined( 'WP_CLI' ) && WP_CLI ) {

	WP_CLI::add_command( 'dekart cache-flush', function () {
		my_cache_bump_version();
		WP_CLI::success( 'Cache flushed + version bumped.' );
	} );

	WP_CLI::add_command( 'dekart cache-memcached', function () {
		$source = WP_CONTENT_DIR . '/plugins/memcached/object-cache.php';
		$target = WP_CONTENT_DIR . '/object-cache.php';

		if ( ! file_exists( $source ) ) {
			WP_CLI::error( 'Memcached Object Cache plugin not installed. Run: wp plugin install memcached' );
			return;
		}

		if ( file_exists( $target ) ) {
			WP_CLI::success( 'Drop-in already exists at wp-content/object-cache.php' );
			return;
		}

		if ( ! class_exists( 'Memcache' ) && ! class_exists( 'Memcached' ) ) {
			WP_CLI::warning( 'PHP memcache extension not found. Install it:' );
			WP_CLI::line( '  sudo apt install php-memcache' );
			WP_CLI::line( '  sudo systemctl restart php8.3-fpm' );
			WP_CLI::line( 'Then run this command again.' );
			return;
		}

		if ( copy( $source, $target ) ) {
			WP_CLI::success( 'Memcached drop-in installed to wp-content/object-cache.php' );
		} else {
			WP_CLI::error( 'Failed to copy drop-in. Check permissions.' );
		}
	} );
}

// ============================================================
// 7. ЛОГИРОВАНИЕ
// ============================================================

if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
	add_action( 'init', function () {
		$b = dekart_detect_cache_backend();
		if ( 'none' === $b ) {
			error_log( '[Object Cache] WARNING: No cache backend available.' );
		}
	}, 0 );
}
