package cache

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/redis/go-redis/v9"
)

var (
	Client *redis.Client
	ctx    = context.Background()
)

// InitRedis initializes the Redis client using connection pooling
func InitRedis(host, port, password string, db int) {
	addr := fmt.Sprintf("%s:%s", host, port)
	Client = redis.NewClient(&redis.Options{
		Addr:         addr,
		Password:     password,
		DB:           db,
		PoolSize:     20, // Reusable connection pool
		MinIdleConns: 5,
		DialTimeout:  2 * time.Second,
		ReadTimeout:  1 * time.Second,
	})

	// Test the connection
	ctxTimeout, cancel := context.WithTimeout(ctx, 2*time.Second)
	defer cancel()
	
	_, err := Client.Ping(ctxTimeout).Result()
	if err != nil {
		log.Printf("⚠️ Redis connection failed: %v. Running in fallback DB mode.", err)
		Client = nil // Fallback safe: if nil, means Redis is down
		return
	}
	log.Println("✅ Connected to Redis successfully")
}

// Get fetches a value by key safely
func Get(key string) (string, error) {
	if Client == nil {
		return "", fmt.Errorf("redis client is down")
	}
	// Fail-safe: short timeout to avoid blocking requests
	ctxTimeout, cancel := context.WithTimeout(ctx, 1*time.Second)
	defer cancel()
	
	return Client.Get(ctxTimeout, key).Result()
}

// Set stores a key-value pair with expiration safely
func Set(key string, value string, expiration time.Duration) error {
	if Client == nil {
		return fmt.Errorf("redis client is down")
	}
	ctxTimeout, cancel := context.WithTimeout(ctx, 1*time.Second)
	defer cancel()

	return Client.Set(ctxTimeout, key, value, expiration).Err()
}

// Del deletes a key safely
func Del(key string) error {
	if Client == nil {
		return fmt.Errorf("redis client is down")
	}
	ctxTimeout, cancel := context.WithTimeout(ctx, 1*time.Second)
	defer cancel()

	return Client.Del(ctxTimeout, key).Err()
}

// DeletePattern deletes all keys matching a pattern safely
func DeletePattern(pattern string) error {
	if Client == nil {
		return fmt.Errorf("redis client is down")
	}
	ctxTimeout, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()

	keys, err := Client.Keys(ctxTimeout, pattern).Result()
	if err != nil || len(keys) == 0 {
		return err
	}
	return Client.Del(ctxTimeout, keys...).Err()
}
