package user

import (
	"context"
	"fmt"
	"strings"
	"time"

	"gorm.io/gorm"
)

// FindActiveSubscribesByUserIds Find active subscriptions for multiple users
func (m *customUserModel) FindActiveSubscribesByUserIds(ctx context.Context, userIds []int64) (map[int64]*UserStatusInfo, error) {
	if len(userIds) == 0 {
		return map[int64]*UserStatusInfo{}, nil
	}

	type Result struct {
		UserId    int64
		Name      string
		Quantity  int64
		UpdatedAt *time.Time
	}
	var results []Result

	// Query latest active subscription for each user
	err := m.QueryNoCacheCtx(ctx, &results, func(conn *gorm.DB, v interface{}) error {
		return conn.Table("user_subscribe us").
			Select("us.user_id, subscribe.name, COALESCE(o.quantity, 1) AS quantity, us.updated_at").
			Joins("LEFT JOIN subscribe ON us.subscribe_id = subscribe.id").
			Joins("LEFT JOIN `order` o ON o.id = (SELECT MAX(o2.id) FROM `order` o2 WHERE o2.user_id = us.user_id AND o2.subscribe_id = us.subscribe_id AND o2.status IN (2, 5))").
			Where("us.user_id IN ? AND us.status IN (0, 1) AND us.expire_time > ?", userIds, time.Now()).
			Order("us.created_at ASC, us.id ASC"). // Ascending so we can overwrite in map to get the latest
			Scan(v).Error
	})

	if err != nil {
		return nil, err
	}

	userMap := make(map[int64]*UserStatusInfo)
	packageTotals := make(map[int64]map[string]int64)
	packageOrder := make(map[int64][]string)
	for _, r := range results {
		name := strings.TrimSpace(r.Name)
		if name == "" {
			name = "Unknown"
		}

		quantity := r.Quantity
		if quantity <= 0 {
			quantity = 1
		}

		if _, ok := packageTotals[r.UserId]; !ok {
			packageTotals[r.UserId] = make(map[string]int64)
		}
		if _, exists := packageTotals[r.UserId][name]; !exists {
			packageOrder[r.UserId] = append(packageOrder[r.UserId], name)
		}
		packageTotals[r.UserId][name] += quantity

		info, ok := userMap[r.UserId]
		if !ok {
			info = &UserStatusInfo{}
			userMap[r.UserId] = info
		}
		info.MemberStatus = formatPackageDisplay(name, quantity)
		if r.UpdatedAt != nil && (info.LastTrafficAt == nil || r.UpdatedAt.After(*info.LastTrafficAt)) {
			info.LastTrafficAt = r.UpdatedAt
		}
	}

	for userID, info := range userMap {
		orderedNames := packageOrder[userID]
		if len(orderedNames) == 0 {
			continue
		}

		parts := make([]string, 0, len(orderedNames))
		for _, name := range orderedNames {
			parts = append(parts, formatPackageDisplay(name, packageTotals[userID][name]))
		}
		info.PurchasedPackage = strings.Join(parts, ", ")
	}

	return userMap, nil
}

func formatPackageDisplay(name string, quantity int64) string {
	if quantity <= 1 {
		return name
	}
	return fmt.Sprintf("%s*%d", name, quantity)
}
