<?php

namespace FleekDash\Services\Search;

use Throwable;

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

if (!\function_exists('fleekdash_safe_unserialize')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/functions.php';
}

/**
 * Optional Redis client for Fleek Search cache (requires ext-redis + WP_REDIS_* constants).
 */
final class SearchCacheRedisClient
{
    private const ERROR_LOG_PREFIX = 'FleekDash Redis Error: ';

    public function isAvailable(): bool
    {
        return \class_exists('Redis', false)
            && \defined('WP_REDIS_HOST')
            && \WP_REDIS_HOST;
    }

    /**
     * @return mixed|false Unserialized value or false
     */
    public function get(string $key)
    {
        if (!$this->isAvailable()) {
            return false;
        }

        try {
            $redis = $this->openConnection();
            $data = $redis->get($key);
            $redis->close();

            return $data !== false ? fleekdash_safe_unserialize($data) : false;
        } catch (Throwable $e) {
            fleekdash_log_error(self::ERROR_LOG_PREFIX . $e->getMessage());

            return false;
        }
    }

    public function set(string $key, $data, int $ttl = 30): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        try {
            $redis = $this->openConnection();
            $result = $redis->setex($key, $ttl, maybe_serialize($data));
            $redis->close();

            return (bool) $result;
        } catch (Throwable $e) {
            fleekdash_log_error(self::ERROR_LOG_PREFIX . $e->getMessage());

            return false;
        }
    }

    public function delete(string $key): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        try {
            $redis = $this->openConnection();
            $result = $redis->del($key);
            $redis->close();

            return (bool) $result;
        } catch (Throwable $e) {
            fleekdash_log_error(self::ERROR_LOG_PREFIX . $e->getMessage());

            return false;
        }
    }

    public function clearByPattern(string $pattern): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        try {
            $redis = $this->openConnection();
            $keys = $redis->keys($pattern);
            if (!empty($keys)) {
                $redis->del($keys);
            }
            $redis->close();

            return true;
        } catch (Throwable $e) {
            fleekdash_log_error(self::ERROR_LOG_PREFIX . $e->getMessage());

            return false;
        }
    }

    /**
     * Open Redis connection using optional ext-redis (instantiated by name so static analysis does not require the extension).
     *
     * @return object
     */
    private function openConnection()
    {
        $className = 'Redis';
        if (!\class_exists($className, false)) {
            throw new SearchCacheRedisException('Redis extension not loaded');
        }

        /** @var object $redis */
        $redis = new $className();
        $redis->connect(\WP_REDIS_HOST, \WP_REDIS_PORT ?? 6379);

        if (\defined('WP_REDIS_PASSWORD') && \WP_REDIS_PASSWORD) {
            $redis->auth(\WP_REDIS_PASSWORD);
        }

        if (\defined('WP_REDIS_DATABASE')) {
            $redis->select(\WP_REDIS_DATABASE);
        }

        return $redis;
    }
}
