package cache

import (
	"context"
	"fmt"
	"time"

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

	"github.com/pingcap/test-infra/services/tcms/service"
	"github.com/pingcap/test-infra/services/tcms/utils"
)

type Cache struct {
	Redis *RedisCache

	User  service.UserService
	Token service.TokenService
}

func (r *Cache) Shutdown() error {
	return r.Redis.Close()
}

func New(redisAddr string, userSvc service.UserService, tokenSvc service.TokenService) (*Cache, error) {
	redisCli, err := NewRedisClient(redisAddr)
	if err != nil {
		return nil, err
	}
	return &Cache{
		Redis: redisCli,
		User:  NewUserService(redisCli, userSvc),
		Token: NewTokenService(redisCli, tokenSvc),
	}, nil
}

func NewRedisClient(addr string) (*RedisCache, error) {
	redisCli := redis.NewClient(&redis.Options{
		Addr:        addr,
		ReadTimeout: 20 * time.Millisecond,
		MaxRetries:  3,
	})
	if _, err := redisCli.Ping(context.Background()).Result(); err != nil {
		return nil, fmt.Errorf("ping redis failed: %v", err)
	}
	return &RedisCache{Client: redisCli}, nil
}

type RedisCache struct {
	*redis.Client
}

func (r *RedisCache) DoubleDel(ctx utils.Context, keys ...string) {
	if len(keys) == 0 {
		return
	}

	if _, err := r.Del(context.Background(), keys...).Result(); err != nil {
		ctx.Log().With("keys", keys).Errorf(err, "redis: delete keys error")
	}
	go func() {
		time.Sleep(100 * time.Millisecond)
		if _, err := r.Del(context.Background(), keys...).Result(); err != nil {
			ctx.Log().With("keys", keys).Errorf(err, "redis: delete keys error")
		}
	}()
}
