package service

import (
	"context"
	"os"
	"time"

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

var ctx = context.Background()

type RedisService struct {
	Client *redis.Client
}

// NewRedisService creates and returns a new RedisService
func NewRedisService() (*RedisService, error) {
	redisAddr := os.Getenv("REDIS_ADDR")
	if redisAddr == "" {
		redisAddr = "localhost:6389" // Fallback for local dev without Docker
	}

	rdb := redis.NewClient(&redis.Options{
		Addr: redisAddr,
	})

	// Ping the server to check the connection
	if _, err := rdb.Ping(ctx).Result(); err != nil {
		return nil, err
	}

	// [DEV-FIX] Disable stop-writes-on-bgsave-error to allow writes even if persistence fails
	// This is common in dev docker environments with permission issues.
	rdb.ConfigSet(ctx, "stop-writes-on-bgsave-error", "no")

	return &RedisService{Client: rdb}, nil
}

func (s *RedisService) Ping(ctx context.Context) error {
	if s.Client == nil {
		return os.ErrInvalid
	}
	return s.Client.Ping(ctx).Err()
}

// StoreVerificationCode saves the SMS verification code with a 3-minute expiration
func (s *RedisService) StoreVerificationCode(phone, code string) error {
	// Key format: "sms_verify:01012345678"
	key := "sms_verify:" + phone
	expiration := 3 * time.Minute
	err := s.Client.Set(ctx, key, code, expiration).Err()
	return err
}

// GetVerificationCode retrieves the SMS verification code
func (s *RedisService) GetVerificationCode(phone string) (string, error) {
	key := "sms_verify:" + phone
	code, err := s.Client.Get(ctx, key).Result()
	if err == redis.Nil {
		// Key does not exist (expired or incorrect phone number)
		return "", nil
	} else if err != nil {
		return "", err
	}
	return code, nil
}

// DeleteVerificationCode removes the verification code after successful verification
func (s *RedisService) DeleteVerificationCode(phone string) error {
	key := "sms_verify:" + phone
	return s.Client.Del(ctx, key).Err()
}

// Set stores a key-value pair with expiration
func (s *RedisService) Set(key string, value string, expiration time.Duration) error {
	return s.Client.Set(ctx, key, value, expiration).Err()
}

// Get retrieves a value by key
func (s *RedisService) Get(key string) (string, error) {
	val, err := s.Client.Get(ctx, key).Result()
	if err == redis.Nil {
		return "", nil
	}
	return val, err
}

// Delete removes a key
func (s *RedisService) Delete(key string) error {
	return s.Client.Del(ctx, key).Err()
}
