package redis

import (
	"context"
	"fmt"
	"time"

	"tm/pkg/logger"

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

// Config holds Redis configuration
type Config struct {
	Host     string `json:"host"`
	Port     int    `json:"port"`
	Password string `json:"password"`
	DB       int    `json:"db"`
	PoolSize int    `json:"pool_size"`
}

// Client represents a Redis client interface
type Client interface {
	Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error
	Get(ctx context.Context, key string) (string, error)
	Del(ctx context.Context, keys ...string) error
	Exists(ctx context.Context, keys ...string) (int64, error)
	Close() error
}

// client implements the Client interface
type client struct {
	rdb *redis.Client
}

// NewClient creates a new Redis client
func NewClient(config *Config, logger logger.Logger) (Client, error) {
	if config == nil {
		return nil, fmt.Errorf("redis config is required")
	}

	addr := fmt.Sprintf("%s:%d", config.Host, config.Port)

	rdb := redis.NewClient(&redis.Options{
		Addr:     addr,
		Password: config.Password,
		DB:       config.DB,
		PoolSize: config.PoolSize,
	})

	// Test the connection
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := rdb.Ping(ctx).Err(); err != nil {
		logger.Error("Failed to connect to Redis", map[string]interface{}{
			"host":  config.Host,
			"port":  config.Port,
			"error": err.Error(),
		})
		return nil, fmt.Errorf("failed to connect to Redis: %w", err)
	}

	logger.Info("Successfully connected to Redis", map[string]interface{}{
		"host": config.Host,
		"port": config.Port,
		"db":   config.DB,
	})

	return &client{rdb: rdb}, nil
}

// Set sets a key-value pair with expiration
func (c *client) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
	return c.rdb.Set(ctx, key, value, expiration).Err()
}

// Get retrieves a value by key
func (c *client) Get(ctx context.Context, key string) (string, error) {
	return c.rdb.Get(ctx, key).Result()
}

// Del deletes one or more keys
func (c *client) Del(ctx context.Context, keys ...string) error {
	return c.rdb.Del(ctx, keys...).Err()
}

// Exists checks if one or more keys exist
func (c *client) Exists(ctx context.Context, keys ...string) (int64, error) {
	return c.rdb.Exists(ctx, keys...).Result()
}

// Close closes the Redis connection
func (c *client) Close() error {
	return c.rdb.Close()
}
