package firstrechargereward import ( "context" "sort" "strings" "time" "chatapp3-golang/internal/integration" "chatapp3-golang/internal/model" ) func configSnapshotFromModel(row model.FirstRechargeRewardConfig) configSnapshot { return configSnapshot{ ID: row.ID, SysOrigin: strings.ToUpper(strings.TrimSpace(row.SysOrigin)), Enabled: row.Enabled, MinAppVersion: strings.TrimSpace(row.MinAppVersion), UpdateTime: row.UpdateTime, } } func levelSnapshotFromModel(row model.FirstRechargeRewardLevel) levelSnapshot { return levelSnapshot{ ID: row.ID, Level: row.Level, RechargeAmountCents: row.RechargeAmountCents, GoogleProductID: normalizeGoogleProductID(row.GoogleProductID), RewardGroupID: row.RewardGroupID, RewardGroupName: strings.TrimSpace(row.RewardGroupName), Enabled: row.Enabled, } } func refConfigSnapshot(value configSnapshot) *configSnapshot { return &value } func buildLevelPayloads( levels []levelSnapshot, rewardItems map[int64][]RewardItem, currentRechargeCents int64, matchedLevel int, admin bool, ) []LevelPayload { payloads := make([]LevelPayload, 0, len(levels)) for _, level := range levels { if !admin && !level.Enabled { continue } payloads = append(payloads, LevelPayload{ ID: level.ID, Level: level.Level, RechargeAmount: formatAmountCents(level.RechargeAmountCents), RechargeAmountCents: level.RechargeAmountCents, GoogleProductID: level.GoogleProductID, RewardGroupID: level.RewardGroupID, RewardGroupName: level.RewardGroupName, RewardItems: rewardItems[level.RewardGroupID], Enabled: level.Enabled, Reached: currentRechargeCents >= level.RechargeAmountCents, Current: matchedLevel > 0 && matchedLevel == level.Level, }) } return payloads } func pickMatchedLevel(levels []levelSnapshot, rechargeAmountCents int64, googleProductID string) (levelSnapshot, bool) { googleProductID = normalizeGoogleProductID(googleProductID) if googleProductID != "" { for _, level := range levels { if !level.Enabled || level.RewardGroupID <= 0 || level.GoogleProductID == "" { continue } if level.GoogleProductID == googleProductID { return level, true } } } for _, level := range levels { if !level.Enabled || level.RechargeAmountCents <= 0 || level.RewardGroupID <= 0 { continue } if rechargeAmountCents == level.RechargeAmountCents { return level, true } } return levelSnapshot{}, false } func sortLevels(levels []levelSnapshot) { sort.Slice(levels, func(i, j int) bool { if levels[i].RechargeAmountCents == levels[j].RechargeAmountCents { return levels[i].Level < levels[j].Level } return levels[i].RechargeAmountCents < levels[j].RechargeAmountCents }) } func (s *Service) loadRewardItemsMap(ctx context.Context, levels []levelSnapshot) map[int64][]RewardItem { if s.java == nil { return map[int64][]RewardItem{} } groupIDs := make([]int64, 0) seen := make(map[int64]struct{}) for _, level := range levels { if level.RewardGroupID <= 0 { continue } if _, exists := seen[level.RewardGroupID]; exists { continue } seen[level.RewardGroupID] = struct{}{} groupIDs = append(groupIDs, level.RewardGroupID) } sort.Slice(groupIDs, func(i, j int) bool { return groupIDs[i] < groupIDs[j] }) result := make(map[int64][]RewardItem, len(groupIDs)) for _, groupID := range groupIDs { detail, err := s.java.GetRewardGroupDetail(ctx, groupID) if err != nil { continue } result[groupID] = rewardItemsFromGroup(detail) } return result } func rewardItemsFromGroup(detail integration.RewardGroupDetail) []RewardItem { items := make([]RewardItem, 0, len(detail.RewardConfigList)) for _, item := range detail.RewardConfigList { items = append(items, RewardItem{ ID: int64(item.ID), Type: rewardItemDisplayType(item), Name: strings.TrimSpace(item.Name), Content: strings.TrimSpace(item.Content), Quantity: int64(item.Quantity), Cover: firstNonEmpty(item.Cover, item.SourceURL), Remark: strings.TrimSpace(item.Remark), }) } return items } func rewardItemDisplayType(item integration.RewardGroupItem) string { itemType := strings.ToUpper(strings.TrimSpace(item.Type)) detailType := strings.ToUpper(strings.TrimSpace(item.DetailType)) if itemType == "PROPS" { if detailType != "" && detailType != "PROPS" { return detailType } if isVipRewardItem(item) { return "NOBLE_VIP" } } return itemType } func isVipRewardItem(item integration.RewardGroupItem) bool { name := strings.ToUpper(strings.TrimSpace(item.Name)) remark := strings.ToUpper(strings.TrimSpace(item.Remark)) return strings.Contains(name, "VIP") || strings.Contains(name, "NOBLE") || strings.Contains(remark, "VIP") || strings.Contains(remark, "NOBLE") } func formatDateTime(t time.Time) string { if t.IsZero() { return "" } return t.Format("2006-01-02 15:04:05") } func formatPtrDateTime(t *time.Time) string { if t == nil { return "" } return formatDateTime(*t) }