<?php

require_once __DIR__ . '/../config/database.php';

class CacheService
{
    private static $redis = null;
    private static $redisChecked = false;

    public static function get(string $key, $default = null)
    {
        $redis = self::redis();

        if ($redis) {
            try {
                $value = $redis->get($key);

                if ($value !== false && $value !== null) {
                    return json_decode($value, true);
                }
            } catch (Throwable $e) {
            }
        }

        try {
            $stmt = db()->prepare("
                SELECT cache_value
                FROM cache_fallback
                WHERE cache_key = ?
                  AND expires_at > NOW()
                LIMIT 1
            ");
            $stmt->execute([$key]);
            $value = $stmt->fetchColumn();

            return $value !== false ? json_decode($value, true) : $default;
        } catch (Throwable $e) {
            return $default;
        }
    }

    public static function set(string $key, $value, int $ttlSeconds = 300): bool
    {
        $payload = json_encode($value);

        $redis = self::redis();

        if ($redis) {
            try {
                return (bool)$redis->setex($key, $ttlSeconds, $payload);
            } catch (Throwable $e) {
            }
        }

        try {
            $expiresAt = date('Y-m-d H:i:s', time() + $ttlSeconds);

            db()->prepare("
                INSERT INTO cache_fallback
                    (cache_key, cache_value, expires_at, created_at, updated_at)
                VALUES
                    (?, ?, ?, NOW(), NOW())
                ON DUPLICATE KEY UPDATE
                    cache_value = VALUES(cache_value),
                    expires_at = VALUES(expires_at),
                    updated_at = NOW()
            ")->execute([$key, $payload, $expiresAt]);

            return true;
        } catch (Throwable $e) {
            return false;
        }
    }

    public static function remember(string $key, int $ttlSeconds, callable $callback)
    {
        $cached = self::get($key, null);

        if ($cached !== null) {
            return $cached;
        }

        $value = $callback();

        self::set($key, $value, $ttlSeconds);

        return $value;
    }

    public static function delete(string $key): void
    {
        $redis = self::redis();

        if ($redis) {
            try {
                $redis->del($key);
            } catch (Throwable $e) {
            }
        }

        try {
            db()->prepare("DELETE FROM cache_fallback WHERE cache_key = ?")->execute([$key]);
        } catch (Throwable $e) {
        }
    }

    private static function redis()
    {
        if (self::$redisChecked) {
            return self::$redis;
        }

        self::$redisChecked = true;

        if (!class_exists('Redis')) {
            return null;
        }

        try {
            $host = defined('REDIS_HOST') ? REDIS_HOST : '127.0.0.1';
            $port = defined('REDIS_PORT') ? REDIS_PORT : 6379;
            $password = defined('REDIS_PASSWORD') ? REDIS_PASSWORD : null;

            $redis = new Redis();
            $redis->connect($host, (int)$port, 1.5);

            if ($password) {
                $redis->auth($password);
            }

            self::$redis = $redis;

            return self::$redis;
        } catch (Throwable $e) {
            self::$redis = null;
            return null;
        }
    }
}
