package cache

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"time"

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

	"infogenie-backend/config"
)

// Key suffixes（完整 key = KeyPrefix + suffix）
const (
	KeySite60sDisabled     = "site:60s-disabled"
	KeySite60sSource       = "site:60s-source"
	KeySiteAIModelDisabled = "site:ai-model-disabled"
)

func KeySiteFeatureClicks(section string) string {
	return "site:feature-clicks:" + section
}

var (
	rdb          *redis.Client
	keyPrefix    string
	siteCacheTTL time.Duration
	redisOn      bool
)

// Init 在 REDIS_ENABLED 时连接并 Ping；未启用时为空操作
func Init(rc config.RedisConfig) error {
	if !rc.Enabled {
		redisOn = false
		rdb = nil
		return nil
	}
	redisOn = true
	keyPrefix = rc.KeyPrefix
	siteCacheTTL = rc.SiteTTL
	if siteCacheTTL <= 0 {
		siteCacheTTL = 60 * time.Second
	}
	rdb = redis.NewClient(&redis.Options{
		Addr:     rc.Addr,
		Password: rc.Password,
		DB:       rc.DB,
	})
	if err := rdb.Ping(context.Background()).Err(); err != nil {
		return fmt.Errorf("redis: %w", err)
	}
	return nil
}

// Enabled 表示已初始化且客户端可用
func Enabled() bool {
	return redisOn && rdb != nil
}

func fullKey(suffix string) string {
	return keyPrefix + suffix
}

// GetJSON 命中返回 true；未启用或未命中返回 false（err 仅表示 Redis/JSON 异常）
func GetJSON(ctx context.Context, suffix string, dest interface{}) (bool, error) {
	if !Enabled() {
		return false, nil
	}
	val, err := rdb.Get(ctx, fullKey(suffix)).Bytes()
	if err == redis.Nil {
		return false, nil
	}
	if err != nil {
		return false, err
	}
	if err := json.Unmarshal(val, dest); err != nil {
		return false, err
	}
	return true, nil
}

// SetJSON ttl<=0 时使用配置的 SiteTTL
func SetJSON(ctx context.Context, suffix string, v interface{}, ttl time.Duration) error {
	if !Enabled() {
		return nil
	}
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}
	if ttl <= 0 {
		ttl = siteCacheTTL
	}
	return rdb.Set(ctx, fullKey(suffix), b, ttl).Err()
}

// Delete 删除若干后缀对应的 key；失败仅打日志
func Delete(ctx context.Context, suffixes ...string) {
	if !Enabled() || len(suffixes) == 0 {
		return
	}
	keys := make([]string, 0, len(suffixes))
	for _, s := range suffixes {
		keys = append(keys, fullKey(s))
	}
	if err := rdb.Del(ctx, keys...).Err(); err != nil {
		log.Printf("redis DEL 失败: %v keys=%v", err, keys)
	}
}

// Ping 未启用时返回 nil
func Ping(ctx context.Context) error {
	if !Enabled() {
		return nil
	}
	return rdb.Ping(ctx).Err()
}
