package im

import (
	"sort"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/unread"
)

// WorkspaceRuntimeSnapshot is the streaming-native runtime snapshot used by the
// live emitter to seed runtime.* events on every fresh connection. The shape
// mirrors the legacy realtime.WorkspaceRuntimeSnapshot so existing
// RuntimeBootstrapSource implementations still apply.
type WorkspaceRuntimeSnapshot struct {
	Machines []WorkspaceRuntimeMachineSnapshot
}

// WorkspaceRuntimeMachineSnapshot describes one machine and its agents.
type WorkspaceRuntimeMachineSnapshot struct {
	MachineID   string
	OwnerUserID string
	Agents      []WorkspaceRuntimeAgentSnapshot
}

// WorkspaceRuntimeAgentSnapshot describes one agent's live runtime state.
type WorkspaceRuntimeAgentSnapshot struct {
	AgentID   string
	Status    string
	SessionID string
}

// RuntimeBootstrapSource exposes current live runtime truth for one workspace
// so fresh connections can replay it during streaming bootstrap.
type RuntimeBootstrapSource interface {
	WorkspaceRuntimeSnapshot(workspaceID string) WorkspaceRuntimeSnapshot
}

// UnreadProjectionReader is the minimal unread projection read API the live
// emitter needs when replaying unread state at bootstrap.
type UnreadProjectionReader interface {
	ScopeStates(workspaceID string, memberID string, scopeIDs []string) map[string]unread.ScopeUnreadState
}

// UnreadProjectionReplayPayloads returns one unread_updated payload per scope
// the member currently tracks. The workspace aggregate is derived from that
// same captured state map: reading it separately would let a live mutation land
// between the scope snapshot and aggregate read, then be counted once in the
// newer aggregate and again when its buffered live delta is applied after
// bootstrap. Payloads are stable-sorted by scopeID for deterministic ordering.
func UnreadProjectionReplayPayloads(workspaceID string, memberID string, reader UnreadProjectionReader) []map[string]any {
	workspaceID = strings.TrimSpace(workspaceID)
	memberID = strings.TrimSpace(memberID)
	if reader == nil || workspaceID == "" || memberID == "" {
		return nil
	}
	states := reader.ScopeStates(workspaceID, memberID, nil)
	if len(states) == 0 {
		return nil
	}
	scopeIDs := make([]string, 0, len(states))
	stateByScopeID := make(map[string]unread.ScopeUnreadState, len(states))
	for scopeID, state := range states {
		trimmedScopeID := strings.TrimSpace(scopeID)
		if trimmedScopeID != "" {
			stateByScopeID[trimmedScopeID] = state
			scopeIDs = append(scopeIDs, trimmedScopeID)
		}
	}
	sort.Strings(scopeIDs)

	var workspaceUnreadConversationCount int64
	for _, state := range stateByScopeID {
		if state.HasUnread() {
			workspaceUnreadConversationCount++
		}
	}
	workspaceHasUnread := workspaceUnreadConversationCount > 0
	payloads := make([]map[string]any, 0, len(scopeIDs))
	for _, scopeID := range scopeIDs {
		state := stateByScopeID[scopeID]
		payloadWorkspaceID := strings.TrimSpace(state.WorkspaceID)
		if payloadWorkspaceID == "" {
			payloadWorkspaceID = workspaceID
		}
		payloadMemberID := strings.TrimSpace(state.MemberID)
		if payloadMemberID == "" {
			payloadMemberID = memberID
		}
		payloadScopeID := strings.TrimSpace(state.ScopeID)
		if payloadScopeID == "" {
			payloadScopeID = scopeID
		}
		if payloadWorkspaceID == "" || payloadMemberID == "" || payloadScopeID == "" {
			continue
		}
		count := state.Count()
		payloads = append(payloads, map[string]any{
			"workspaceId":                      payloadWorkspaceID,
			"memberId":                         payloadMemberID,
			"scopeId":                          payloadScopeID,
			"scopeType":                        string(state.ScopeType),
			"count":                            count,
			"manualUnread":                     state.ManualUnread,
			"hasUnread":                        count > 0 || state.ManualUnread,
			"workspaceHasUnread":               workspaceHasUnread,
			"workspaceUnreadConversationCount": workspaceUnreadConversationCount,
			"servingState":                     string(state.ServingState),
		})
	}
	return payloads
}
