package adapter

import (
	"bytes"
	"context"
	"encoding/gob"
	"errors"
	"fmt"
	"time"

	"ariga.io/entcache"
	"github.com/redis/go-redis/v9"
)

type RedisCache struct {
	redis *redis.ClusterClient
}

func NewRedisCache(redis *redis.ClusterClient) *RedisCache {
	return &RedisCache{redis: redis}
}

func (c *RedisCache) Del(ctx context.Context, key entcache.Key) error {
	if k, ok := key.(string); !ok {
		return fmt.Errorf("key is not a string")
	} else {
		c.redis.Del(ctx, k)
		return nil
	}
}

func (c *RedisCache) Add(ctx context.Context, key entcache.Key, entry *entcache.Entry, duration time.Duration) error {
	k, ok := key.(string)
	if !ok {
		return fmt.Errorf("key is not a string")
	}
	var buf bytes.Buffer
	if err := gob.NewEncoder(&buf).Encode(entry); err != nil {
		return fmt.Errorf("failed to encode entry: %w", err)
	}
	return c.redis.Set(ctx, k, buf.Bytes(), duration).Err()
}

func (c *RedisCache) Get(ctx context.Context, key entcache.Key) (*entcache.Entry, error) {
	k, ok := key.(string)
	if !ok {
		return nil, fmt.Errorf("key is not a string")
	}
	val, err := c.redis.Get(ctx, k).Bytes()
	if err != nil {
		if errors.Is(err, redis.Nil) {
			// 缓存未命中
			return nil, nil
		}
		return nil, err
	}
	var entry entcache.Entry
	if err := gob.NewDecoder(bytes.NewReader(val)).Decode(&entry); err != nil {
		return nil, fmt.Errorf("failed to decode entry: %w", err)
	}
	return &entry, nil
}
