package service

import (
	"context"
	"sort"

	roomv1 "hyapp.local/api/proto/room/v1"
	"hyapp/pkg/appcode"
	"hyapp/pkg/roomid"
	"hyapp/pkg/xerr"
	"hyapp/services/room-service/internal/room/state"
)

const (
	// defaultRoomBannedUsersPageSize 是房间黑名单面板默认页大小。
	defaultRoomBannedUsersPageSize = 20
	// maxRoomBannedUsersPageSize 限制单次查询量，避免管理面板一次拉完整治理状态。
	maxRoomBannedUsersPageSize = 100
)

// ListRoomBannedUsers 分页读取房间当前仍有效的黑名单。
// 黑名单状态属于 Room Cell，用户头像、昵称、国家等展示资料由 gateway 批量查询 user-service。
func (s *Service) ListRoomBannedUsers(ctx context.Context, req *roomv1.ListRoomBannedUsersRequest) (*roomv1.ListRoomBannedUsersResponse, error) {
	ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
	roomID := req.GetRoomId()
	viewerUserID := req.GetViewerUserId()
	if !roomid.ValidStringID(roomID) {
		return nil, xerr.New(xerr.InvalidArgument, "room_id is invalid")
	}
	if viewerUserID <= 0 {
		return nil, xerr.New(xerr.InvalidArgument, "viewer_user_id is required")
	}

	snapshot, err := s.currentSnapshot(ctx, roomID)
	if err != nil {
		return nil, err
	}
	if snapshot == nil || snapshot.GetRoomId() == "" {
		return nil, xerr.New(xerr.NotFound, "room not found")
	}
	if snapshot.GetStatus() != state.RoomStatusActive {
		return nil, xerr.New(xerr.RoomClosed, "room closed")
	}

	current := state.FromProto(snapshot)
	if err := requireManagerPresent(current, viewerUserID); err != nil {
		// 黑名单是房间治理数据，只允许当前仍在房间内的 owner/admin 查看。
		return nil, err
	}

	nowMS := s.clock.Now().UnixMilli()
	items := activeBannedUsersFromState(current, nowMS)
	page, pageSize := normalizeRoomBannedUsersPage(req.GetPage(), req.GetPageSize())
	total := int64(len(items))
	start := (page - 1) * pageSize
	if start >= len(items) {
		items = nil
	} else {
		end := start + pageSize
		if end > len(items) {
			end = len(items)
		}
		items = items[start:end]
	}

	return &roomv1.ListRoomBannedUsersResponse{
		Items:        items,
		Total:        total,
		Page:         int32(page),
		PageSize:     int32(pageSize),
		ServerTimeMs: nowMS,
	}, nil
}

func activeBannedUsersFromState(current *state.RoomState, nowMS int64) []*roomv1.RoomBannedUser {
	if current == nil || len(current.BanUsers) == 0 {
		return nil
	}
	items := make([]*roomv1.RoomBannedUser, 0, len(current.BanUsers))
	for _, ban := range current.BanUsers {
		if !ban.ActiveAt(nowMS) {
			continue
		}
		remainingMS := int64(0)
		if ban.ExpiresAtMS > 0 {
			remainingMS = ban.ExpiresAtMS - nowMS
		}
		items = append(items, &roomv1.RoomBannedUser{
			UserId:      ban.UserID,
			ActorUserId: ban.ActorUserID,
			CreatedAtMs: ban.CreatedAtMS,
			UnbanAtMs:   ban.ExpiresAtMS,
			RemainingMs: remainingMS,
			Permanent:   ban.ExpiresAtMS == 0,
		})
	}
	sort.Slice(items, func(i, j int) bool {
		if items[i].GetCreatedAtMs() != items[j].GetCreatedAtMs() {
			return items[i].GetCreatedAtMs() > items[j].GetCreatedAtMs()
		}
		return items[i].GetUserId() < items[j].GetUserId()
	})
	return items
}

func normalizeRoomBannedUsersPage(rawPage int32, rawPageSize int32) (int, int) {
	page := int(rawPage)
	if page <= 0 {
		page = 1
	}
	pageSize := int(rawPageSize)
	if pageSize <= 0 {
		pageSize = defaultRoomBannedUsersPageSize
	}
	if pageSize > maxRoomBannedUsersPageSize {
		pageSize = maxRoomBannedUsersPageSize
	}
	return page, pageSize
}
