package service

import (
	"context"
	"fmt"
	"strconv"
	"time"

	"github.com/redis/go-redis/v9"
	"hyapp/pkg/appcode"
	"hyapp/pkg/idgen"
	"hyapp/pkg/xerr"
)

const releaseLuckyGiftSendLockScript = `
if redis.call("GET", KEYS[1]) == ARGV[1] then
	return redis.call("DEL", KEYS[1])
end
return 0
`

type LuckyGiftSendLocker interface {
	AcquireLuckyGiftSendLock(ctx context.Context, appCode string, userID int64, ttl time.Duration) (func(context.Context), error)
}

type RedisLuckyGiftSendLocker struct {
	client *redis.Client
}

func NewRedisLuckyGiftSendLocker(client *redis.Client) *RedisLuckyGiftSendLocker {
	return &RedisLuckyGiftSendLocker{client: client}
}

func (l *RedisLuckyGiftSendLocker) AcquireLuckyGiftSendLock(ctx context.Context, appCode string, userID int64, ttl time.Duration) (func(context.Context), error) {
	if l == nil || l.client == nil {
		return nil, nil
	}
	if userID <= 0 {
		return nil, xerr.New(xerr.InvalidArgument, "lucky gift sender is invalid")
	}
	if ttl <= 0 {
		ttl = 5 * time.Second
	}
	key := luckyGiftSendLockKey(appCode, userID)
	token := idgen.New("lucky_gift_send_lock")
	ok, err := l.client.SetNX(ctx, key, token, ttl).Result()
	if err != nil {
		return nil, err
	}
	if !ok {
		return nil, xerr.New(xerr.Conflict, "lucky gift send is already processing")
	}
	return func(releaseCtx context.Context) {
		_ = l.client.Eval(releaseCtx, releaseLuckyGiftSendLockScript, []string{key}, token).Err()
	}, nil
}

func luckyGiftSendLockKey(rawAppCode string, userID int64) string {
	return fmt.Sprintf("lucky_gift_send:%s:%s", appcode.Normalize(rawAppCode), strconv.FormatInt(userID, 10))
}
