package service

import (
	"context"
	"strings"

	roomv1 "hyapp.local/api/proto/room/v1"
	"hyapp/pkg/appcode"
	"hyapp/pkg/roomid"
	"hyapp/pkg/xerr"
)

const (
	// defaultRoomOnlineUsersPageSize 是在线用户弹窗的默认页大小，避免客户端不传 page_size 时一次拉全量。
	defaultRoomOnlineUsersPageSize = 50
	// maxRoomOnlineUsersPageSize 是在线用户列表单页硬上限，保护 presence 读模型查询。
	maxRoomOnlineUsersPageSize = 100
)

// ListRoomOnlineUsers 分页读取房间在线用户列表。
// 该接口用于右上角在线人数弹窗，不能让客户端用完整 RoomSnapshot 做分页。
func (s *Service) ListRoomOnlineUsers(ctx context.Context, req *roomv1.ListRoomOnlineUsersRequest) (*roomv1.ListRoomOnlineUsersResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
	roomID := req.GetRoomId()
	viewerUserID := req.GetViewerUserId()
	if !roomid.ValidStringID(roomID) {
		// 在线用户查询必须绑定真实房间 ID，不能让空 room_id 触发宽查询。
		return nil, xerr.New(xerr.InvalidArgument, "room_id is invalid")
	}
	if viewerUserID <= 0 {
		// viewer_user_id 来自 gateway 鉴权态，用于限制只有房内用户可看在线列表。
		return nil, xerr.New(xerr.InvalidArgument, "viewer_user_id is required")
	}

	// 先用用户当前房间读模型做轻量权限判断，避免为了弹窗分页读取完整 RoomSnapshot。
	presence, exists, err := s.repository.GetCurrentRoomPresence(ctx, viewerUserID)
	if err != nil {
		return nil, err
	}
	if !exists || presence.RoomID != roomID || presence.Status != roomPresenceStatusActive {
		// 不在该房间的用户不能借分页接口枚举房间内成员。
		return nil, xerr.New(xerr.PermissionDenied, "viewer is not in room")
	}

	page := int(req.GetPage())
	if page <= 0 {
		// page 从 1 开始，0 或负数按第一页处理，保持客户端容错。
		page = 1
	}
	pageSize := int(req.GetPageSize())
	if pageSize <= 0 {
		// 缺省页大小走服务端默认，避免前端每个入口复制同一数值。
		pageSize = defaultRoomOnlineUsersPageSize
	}
	if pageSize > maxRoomOnlineUsersPageSize {
		// 单页上限在 service 层压实，repository 不接受无限制分页。
		pageSize = maxRoomOnlineUsersPageSize
	}
	sortMode := strings.TrimSpace(req.GetSort())
	if sortMode != "" && sortMode != "online" && sortMode != "gift_value" {
		return nil, xerr.New(xerr.InvalidArgument, "sort is invalid")
	}

	snapshot, err := s.currentSnapshot(ctx, roomID)
	if err != nil {
		return nil, err
	}
	if snapshot == nil {
		return nil, xerr.New(xerr.NotFound, "room not found")
	}
	adminUsers := make(map[int64]bool, len(snapshot.GetAdminUserIds()))
	for _, userID := range snapshot.GetAdminUserIds() {
		if userID > 0 && userID != snapshot.GetOwnerUserId() {
			adminUsers[userID] = true
		}
	}

	result, err := s.repository.ListRoomOnlineUsers(ctx, RoomOnlineUserQuery{
		AppCode:  appcode.FromContext(ctx),
		RoomID:   roomID,
		Page:     page,
		PageSize: pageSize,
		Sort:     sortMode,
	})
	if err != nil {
		return nil, err
	}

	users := make([]*roomv1.RoomUser, 0, len(result.Users))
	items := make([]*roomv1.RoomOnlineUser, 0, len(result.Users))
	for _, user := range result.Users {
		// 在线列表只返回轻量房间用户态，完整用户资料仍由 user-service 或 gateway 聚合。
		users = append(users, &roomv1.RoomUser{
			UserId:       user.UserID,
			Role:         user.Role,
			JoinedAtMs:   user.JoinedAtMS,
			LastSeenAtMs: user.LastSeenAtMS,
		})
		roomRole := "normal"
		if adminUsers[user.UserID] {
			roomRole = "admin"
		}
		items = append(items, &roomv1.RoomOnlineUser{
			UserId:       user.UserID,
			Role:         user.Role,
			RoomRole:     roomRole,
			GiftValue:    user.GiftValue,
			JoinedAtMs:   user.JoinedAtMS,
			LastSeenAtMs: user.LastSeenAtMS,
			IsOwner:      user.UserID == snapshot.GetOwnerUserId(),
		})
	}

	return &roomv1.ListRoomOnlineUsersResponse{
		Users:        users,
		Items:        items,
		Total:        result.Total,
		Page:         int32(result.Page),
		PageSize:     int32(result.PageSize),
		ServerTimeMs: s.clock.Now().UnixMilli(),
	}, nil
}
