package repository

import (
	"context"
	"fmt"
	"github.com/redis/go-redis/v9"
	"strconv"
	"time"
)

// PlanListType 定义了要操作的套餐列表类型
type PlanListType string

const (
	// ClosedPlansList 代表已关闭的套餐列表 (使用 Redis Set)
	ClosedPlansList PlanListType = "closed"
	// ExpiringSoonPlansList 代表即将过期的套餐列表 (使用 Redis Sorted Set)
	ExpiringSoonPlansList PlanListType = "expiring_soon"
)

// ExpiredRepository 定义了与过期套餐相关的操作接口
type ExpiredRepository interface {
	// AddPlans 将一个或多个套餐ID添加到指定的列表中
	AddPlans(ctx context.Context, listType PlanListType, planIds ...int64) error
	// RemovePlans 从指定的列表中移除一个或多个套餐ID
	RemovePlans(ctx context.Context, listType PlanListType, planIds ...int64) error
	// GetAllPlanIds 获取指定列表中的所有套餐ID
	GetAllPlanIds(ctx context.Context, listType PlanListType) ([]int64, error)
	// IsPlanInList 检查一个套餐ID是否存在于指定的列表中
	IsPlanInList(ctx context.Context, listType PlanListType, planId int64) (bool, error)
}

func NewExpiredRepository(
	repository *Repository,
) ExpiredRepository {
	return &expiredRepository{
		Repository: repository,
	}
}

type expiredRepository struct {
	*Repository
}

// Key的前缀，用于标识所有已关闭套餐的Key
// closePlansKey 用于存储所有已关闭套餐ID的Set
const closePlansKey = "waf:closed_plans"

// expiringSoonPlansKey 用于存储7天后过期套餐ID的Sorted Set
// Score: 过期时间戳, Value: planId
const expiringSoonPlansKey = "waf:expiring_soon_plans"

// AddPlans 将一个或多个套餐ID添加到指定的列表中
func (r *expiredRepository) AddPlans(ctx context.Context, listType PlanListType, planIds ...int64) error {
	if len(planIds) == 0 {
		return nil
	}

	switch listType {
	case ClosedPlansList:
		members := make([]interface{}, len(planIds))
		for i, id := range planIds {
			members[i] = id
		}
		return r.Rdb.SAdd(ctx, closePlansKey, members...).Err()

	case ExpiringSoonPlansList:
		// Score 代表套餐的实际过期时间戳，用于后续查询
		expirationTimestamp := float64(time.Now().Add(7 * 24 * time.Hour).Unix())
		members := make([]redis.Z, len(planIds))
		for i, id := range planIds {
			members[i] = redis.Z{
				Score:  expirationTimestamp,
				Member: id,
			}
		}
		return r.Rdb.ZAdd(ctx, expiringSoonPlansKey, members...).Err()

	default:
		return fmt.Errorf("未知的列表类型: %s", listType)
	}
}

// RemovePlans 从指定的列表中移除一个或多个套餐ID
func (r *expiredRepository) RemovePlans(ctx context.Context, listType PlanListType, planIds ...int64) error {
	if len(planIds) == 0 {
		return nil
	}

	members := make([]interface{}, len(planIds))
	for i, id := range planIds {
		members[i] = id
	}

	switch listType {
	case ClosedPlansList:
		return r.Rdb.SRem(ctx, closePlansKey, members...).Err()
	case ExpiringSoonPlansList:
		return r.Rdb.ZRem(ctx, expiringSoonPlansKey, members...).Err()
	default:
		return fmt.Errorf("未知的列表类型: %s", listType)
	}
}

// GetAllPlanIds 获取指定列表中的所有套餐ID
func (r *expiredRepository) GetAllPlanIds(ctx context.Context, listType PlanListType) ([]int64, error) {
	var members []string
	var err error

	switch listType {
	case ClosedPlansList:
		members, err = r.Rdb.SMembers(ctx, closePlansKey).Result()
	case ExpiringSoonPlansList:
		members, err = r.Rdb.ZRange(ctx, expiringSoonPlansKey, 0, -1).Result()
	default:
		return nil, fmt.Errorf("未知的列表类型: %s", listType)
	}

	if err != nil {
		return nil, err
	}

	planIds := make([]int64, len(members))
	for i, memberStr := range members {
		id, err := strconv.ParseInt(memberStr, 10, 64)
		if err != nil {
			return nil, fmt.Errorf("无法解析套餐ID '%s': %w", memberStr, err)
		}
		planIds[i] = id
	}

	return planIds, nil
}

// IsPlanInList 检查一个套餐ID是否存在于指定的列表中
func (r *expiredRepository) IsPlanInList(ctx context.Context, listType PlanListType, planId int64) (bool, error) {
	switch listType {
	case ClosedPlansList:
		return r.Rdb.SIsMember(ctx, closePlansKey, planId).Result()
	case ExpiringSoonPlansList:
		_, err := r.Rdb.ZScore(ctx, expiringSoonPlansKey, strconv.FormatInt(planId, 10)).Result()
		if err == redis.Nil {
			return false, nil
		}
		return err == nil, err
	default:
		return false, fmt.Errorf("未知的列表类型: %s", listType)
	}
}