<?php

namespace FleekDash\Core;

// Load debug helpers
if (!function_exists('fleekdash_log_error')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}

/**
 * Cache Manager - Centralized caching system for optimal performance
 * Provides intelligent caching with automatic invalidation and fallbacks
 */
class CacheManager
{
    /**
     * Cache groups for better organization
     */
    const CACHE_GROUPS = [
        'fleekdash_posts' => 3600,        // 1 hour
        'fleekdash_users' => 1800,        // 30 minutes
        'fleekdash_stats' => 7200,        // 2 hours
        'fleekdash_integrations' => 3600, // 1 hour
        'fleekdash_settings' => 86400,    // 24 hours
        'fleekdash_ui' => 1800,          // 30 minutes
        'fleekdash_api' => 900,          // 15 minutes
    ];

    /**
     * Static cache for current request
     */
    private static $memory_cache = [];
    private static $initialized = false;

    /**
     * Initialize cache manager
     */
    public static function init()
    {
        if (self::$initialized) {
            return;
        }

        self::$initialized = true;

        // Add cache cleanup on shutdown
        \add_action('shutdown', [self::class, 'cleanup_expired_cache']);

        // Clear cache on plugin updates
        \add_action('upgrader_process_complete', [self::class, 'clear_all_cache'], 10, 2);
    }

    /**
     * Get cached data with intelligent fallback
     *
     * @param string $key Cache key
     * @param string $group Cache group
     * @param callable|null $callback Callback to generate data if not cached
     * @param int|null $expiration Custom expiration time
     * @return mixed
     */
    public static function get($key, $group = 'default', $callback = null, $expiration = null)
    {
        // Check memory cache first (fastest)
        $memory_key = "{$group}_{$key}";
        if (isset(self::$memory_cache[$memory_key])) {
            return self::$memory_cache[$memory_key];
        }

        // Check Redis cache if available
        if (self::is_redis_available()) {
            $redis_key = "fleekdash_{$group}_{$key}";
            $cached = wp_cache_get($redis_key, $group);
            if ($cached !== false) {
                self::$memory_cache[$memory_key] = $cached;
                return $cached;
            }
        }

        // Check WordPress transients
        $transient_key = "fleekdash_{$group}_{$key}";
        $cached = \get_transient($transient_key);
        if ($cached !== false) {
            self::$memory_cache[$memory_key] = $cached;
            return $cached;
        }

        // Generate data if callback provided
        if ($callback && is_callable($callback)) {
            $data = $callback();
            self::set($key, $data, $group, $expiration);
            return $data;
        }

        return false;
    }

    /**
     * Set cached data
     *
     * @param string $key Cache key
     * @param string $group Cache group
     * @param mixed $data Data to cache
     * @param int|null $expiration Custom expiration time
     * @return bool
     */
    public static function set($key, $data, $group = 'default', $expiration = null)
    {
        // Set memory cache
        $memory_key = "{$group}_{$key}";
        self::$memory_cache[$memory_key] = $data;

        // Get expiration time
        $exp = $expiration ?? (self::CACHE_GROUPS[$group] ?? 3600);

        // Set Redis cache if available
        if (self::is_redis_available()) {
            $redis_key = "fleekdash_{$group}_{$key}";
            wp_cache_set($redis_key, $data, $group, $exp);
        }

        // Set WordPress transient
        $transient_key = "fleekdash_{$group}_{$key}";
        return \set_transient($transient_key, $data, $exp);
    }

    /**
     * Delete cached data
     *
     * @param string $key Cache key
     * @param string $group Cache group
     * @return bool
     */
    public static function delete($key, $group = 'default')
    {
        // Clear memory cache
        $memory_key = "{$group}_{$key}";
        unset(self::$memory_cache[$memory_key]);

        // Clear Redis cache if available
        if (self::is_redis_available()) {
            $redis_key = "fleekdash_{$group}_{$key}";
            wp_cache_delete($redis_key, $group);
        }

        // Clear WordPress transient
        $transient_key = "fleekdash_{$group}_{$key}";
        return \delete_transient($transient_key);
    }

    /**
     * Clear entire cache group
     *
     * @param string $group Cache group
     * @return bool
     */
    public static function clear_group($group)
    {
        // Clear memory cache for group
        foreach (self::$memory_cache as $key => $value) {
            if (strpos($key, "{$group}_") === 0) {
                unset(self::$memory_cache[$key]);
            }
        }

        // Clear Redis group if available
        if (self::is_redis_available()) {
            if (function_exists('wp_cache_delete_group')) {
                wp_cache_delete_group($group);
            } else {
                wp_cache_flush_group($group);
            }
        }

        // Clear WordPress transients for group
        global $wpdb;
        $deleted = $wpdb->query(
            $wpdb->prepare(
                "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s",
                "_transient_fleekdash_{$group}_%",
                "_transient_timeout_fleekdash_{$group}_%",
            ),
        );

        return $deleted !== false;
    }

    /**
     * Clear all FleekDash cache
     *
     * @return bool
     */
    public static function clear_all_cache()
    {
        // Clear memory cache
        self::$memory_cache = [];

        // Clear Redis cache if available
        if (self::is_redis_available()) {
            wp_cache_flush();
        }

        // Clear all FleekDash transients
        global $wpdb;
        $deleted = $wpdb->query(
            "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_fleekdash_%' OR option_name LIKE '_transient_timeout_fleekdash_%'",
        );

        return $deleted !== false;
    }

    /**
     * Check if Redis is available
     *
     * @return bool
     */
    private static function is_redis_available()
    {
        return function_exists('wp_cache_get') &&
            defined('WP_REDIS_ENABLED') &&
            WP_REDIS_ENABLED;
    }

    /**
     * Cleanup expired cache entries
     */
    public static function cleanup_expired_cache()
    {
        // WordPress handles transient cleanup automatically
        // This is just for additional cleanup if needed
        if (self::is_redis_available()) {
            // Redis handles expiration automatically
            return;
        }
    }

    /**
     * Get cache statistics
     *
     * @return array
     */
    public static function get_stats()
    {
        global $wpdb;

        $stats = [
            'memory_cache_size' => count(self::$memory_cache),
            'redis_available' => self::is_redis_available(),
            'transient_count' => 0,
            'cache_groups' => []
        ];

        // Count transients
        $transient_count = $wpdb->get_var(
            "SELECT COUNT(*) FROM {$wpdb->options} WHERE option_name LIKE '_transient_fleekdash_%'",
        );
        $stats['transient_count'] = (int) $transient_count;

        // Get stats per group
        foreach (self::CACHE_GROUPS as $group => $expiration) {
            $group_count = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT COUNT(*) FROM {$wpdb->options} WHERE option_name LIKE %s",
                    "_transient_fleekdash_{$group}_%",
                ),
            );
            $stats['cache_groups'][$group] = [
                'count' => (int) $group_count,
                'expiration' => $expiration
            ];
        }

        return $stats;
    }

    /**
     * Warm up cache for critical data
     */
    public static function warm_cache()
    {
        // Cache user data
        if (\is_user_logged_in()) {
            $user_id = \get_current_user_id();
            self::get("user_{$user_id}", 'users', function () use ($user_id) {
                return \get_userdata($user_id);
            });
        }

        // Cache active integrations
        self::get('active_integrations', 'integrations', function () {
            // V3.0: Use IntegrationManager
            try {
                $manager = \FleekDash\Core\IntegrationManager::getInstance();
                return $manager->getAll();
            } catch (\Exception $e) {
                fleekdash_log_error('Error getting integrations in CacheManager: ' . $e->getMessage());
                return [
                    'plugin' => [],
                    'theme' => [],
                    'api' => []
                ];
            }
        });

        // Cache settings
        self::get('settings', 'settings', function () {
            return \get_option('fleekdash_settings', []);
        });
    }

    /**
     * Batch cache operations for better performance
     *
     * @param array $operations Array of cache operations
     * @return array Results of operations
     */
    public static function batch_operations($operations)
    {
        $results = [];

        foreach ($operations as $operation) {
            $action = $operation['action'] ?? 'get';
            $key = $operation['key'] ?? '';
            $group = $operation['group'] ?? 'default';
            $data = $operation['data'] ?? null;
            $callback = $operation['callback'] ?? null;
            $expiration = $operation['expiration'] ?? null;

            switch ($action) {
                case 'get':
                    $results[] = self::get($key, $group, $callback, $expiration);
                    break;
                case 'set':
                    $results[] = self::set($key, $data, $group, $expiration);
                    break;
                case 'delete':
                    $results[] = self::delete($key, $group);
                    break;
            }
        }

        return $results;
    }
}
