<?php

namespace FleekDash\Services;

use FleekDash\Services\Search\SearchCacheRedisClient;

class SearchCacheService
{
    private const CACHE_GROUP = 'fleekdash_search';
    private const INSTANT_PREFIX = 'instant_';
    /** DB transient prefix — must include "fleekdash" so uninstall and global cache clears match. */
    private const SEMANTIC_PREFIX = 'fleekdash_search_semantic_';
    private const PREVIEW_PREFIX = 'preview_';

    private SearchCacheRedisClient $redisClient;

    public function __construct()
    {
        $this->redisClient = new SearchCacheRedisClient();
    }

    /**
     * Generate cache key from search parameters
     */
    public function getCacheKey($query, $types = [], $limit = 20)
    {
        $normalized_query = strtolower(trim($query));
        $sorted_types = is_array($types) ? $types : [$types];
        sort($sorted_types);
        $types_string = implode(',', $sorted_types);

        return md5("search_{$normalized_query}_{$types_string}_{$limit}");
    }

    /**
     * Get cached search results (unified method for SearchController)
     */
    public function getCachedResults($cache_key)
    {
        $cached = $this->getInstantCache($cache_key);
        if ($cached !== false) {
            return $cached;
        }

        return $this->getSemanticCache($cache_key);
    }

    /**
     * Cache search results (unified method for SearchController)
     */
    public function cacheResults($cache_key, $results)
    {
        $this->setInstantCache($cache_key, $results, 30);
        $this->setSemanticCache($cache_key, $results, 300);

        return true;
    }

    /**
     * Get cached preview data (for SearchController compatibility)
     */
    public function getCachedPreview($cache_key)
    {
        if (strpos($cache_key, 'preview_') === 0) {
            $parts = explode('_', substr($cache_key, 8), 2);
            if (count($parts) === 2) {
                return $this->getPreviewCache($parts[0], $parts[1]);
            }
        }

        return null;
    }

    /**
     * Cache preview data (for SearchController compatibility)
     */
    public function cachePreview($cache_key, $data)
    {
        if (strpos($cache_key, 'preview_') === 0) {
            $parts = explode('_', substr($cache_key, 8), 2);
            if (count($parts) === 2) {
                return $this->setPreviewCache($parts[0], $parts[1], $data);
            }
        }

        return false;
    }

    /**
     * Clear all cache (for SearchController compatibility)
     */
    public function clearCache()
    {
        return $this->clearAllSearchCache();
    }

    /**
     * Get instant cache (Redis/Object Cache) - TTL: 30 seconds
     */
    public function getInstantCache($cache_key)
    {
        if ($this->redisClient->isAvailable()) {
            return $this->redisClient->get(self::INSTANT_PREFIX . $cache_key);
        }

        return wp_cache_get(self::INSTANT_PREFIX . $cache_key, self::CACHE_GROUP);
    }

    /**
     * Set instant cache
     */
    public function setInstantCache($cache_key, $data, $ttl = 30)
    {
        $serialized_data = maybe_serialize($data);

        if ($this->redisClient->isAvailable()) {
            $this->redisClient->set(self::INSTANT_PREFIX . $cache_key, $serialized_data, $ttl);
        }

        wp_cache_set(self::INSTANT_PREFIX . $cache_key, $data, self::CACHE_GROUP, $ttl);

        return true;
    }

    /**
     * Get semantic cache (Transients) - TTL: 5 minutes
     */
    public function getSemanticCache($cache_key)
    {
        return \get_transient(self::SEMANTIC_PREFIX . $cache_key);
    }

    /**
     * Set semantic cache
     */
    public function setSemanticCache($cache_key, $data, $ttl = 300)
    {
        return \set_transient(self::SEMANTIC_PREFIX . $cache_key, $data, $ttl);
    }

    /**
     * Get preview cache
     */
    public function getPreviewCache($type, $id)
    {
        $cache_key = self::PREVIEW_PREFIX . "{$type}_{$id}";

        if ($this->redisClient->isAvailable()) {
            $cached = $this->redisClient->get($cache_key);
            if ($cached !== false) {
                return $cached;
            }
        }

        return wp_cache_get($cache_key, self::CACHE_GROUP);
    }

    /**
     * Set preview cache
     */
    public function setPreviewCache($type, $id, $data, $ttl = 60)
    {
        $cache_key = self::PREVIEW_PREFIX . "{$type}_{$id}";
        $serialized_data = maybe_serialize($data);

        if ($this->redisClient->isAvailable()) {
            $this->redisClient->set($cache_key, $serialized_data, $ttl);
        }

        wp_cache_set($cache_key, $data, self::CACHE_GROUP, $ttl);

        return true;
    }

    /**
     * Clear all search cache
     */
    public function clearAllSearchCache()
    {
        if ($this->redisClient->isAvailable()) {
            $this->redisClient->clearByPattern('fleekdash_search_*');
        }

        wp_cache_flush_group(self::CACHE_GROUP);

        global $wpdb;
        $wpdb->query($wpdb->prepare("
            DELETE FROM {$wpdb->options}
            WHERE option_name LIKE %s
        ", '_transient_' . self::SEMANTIC_PREFIX . '%'));

        $wpdb->query($wpdb->prepare("
            DELETE FROM {$wpdb->options}
            WHERE option_name LIKE %s
        ", '_transient_timeout_' . self::SEMANTIC_PREFIX . '%'));

        return true;
    }

    /**
     * Clear cache for specific object
     */
    public function clearObjectCache($type, $id)
    {
        $preview_key = self::PREVIEW_PREFIX . "{$type}_{$id}";

        if ($this->redisClient->isAvailable()) {
            $this->redisClient->delete($preview_key);
        }

        wp_cache_delete($preview_key, self::CACHE_GROUP);
        $this->clearAllSearchCache();

        return true;
    }

    /**
     * Get cache statistics
     */
    public function getCacheStats()
    {
        $stats = [
            'redis_available' => $this->redisClient->isAvailable(),
            'object_cache_enabled' => wp_using_ext_object_cache(),
            'total_cached_searches' => 0,
            'cache_hit_ratio' => 0,
        ];

        $search_stats = \get_option('fleekdash_search_cache_stats', []);

        return array_merge($stats, $search_stats);
    }

    /**
     * Update cache hit statistics
     */
    public function recordCacheHit($hit = true)
    {
        $stats = \get_option('fleekdash_search_cache_stats', [
            'total_requests' => 0,
            'cache_hits' => 0,
            'last_updated' => time(),
        ]);

        $stats['total_requests']++;

        if ($hit) {
            $stats['cache_hits']++;
        }

        $stats['hit_ratio'] = $stats['total_requests'] > 0
            ? round(($stats['cache_hits'] / $stats['total_requests']) * 100, 2)
            : 0;

        $stats['last_updated'] = time();

        \update_option('fleekdash_search_cache_stats', $stats);
    }
}
