package im

import (
	"strings"
	"time"
)

type liveWakeStatusSnapshot struct {
	agentID        string
	agentName      string
	displayName    string
	channelID      string
	messageID      string
	wakeToken      string
	target         string
	status         string
	replyMessageID string
	detail         string
	timestamp      string
	expiresAt      time.Time
}

func (emitter *LiveEventEmitter) storeWakeStatusSnapshot(workspaceID string, payload liveWakeStatusSnapshot) {
	if emitter == nil {
		return
	}
	now := time.Now()
	spaceKey := strings.TrimSpace(workspaceID)
	channelKey := strings.TrimSpace(payload.channelID)
	if spaceKey == "" || channelKey == "" {
		return
	}
	key := wakeStatusSnapshotKey(payload.agentID, payload.messageID)
	if key == "\x00" {
		return
	}
	emitter.wakeStatusMu.Lock()
	defer emitter.wakeStatusMu.Unlock()
	if emitter.nextWakeStatusPruneAt.IsZero() || !now.Before(emitter.nextWakeStatusPruneAt) {
		emitter.pruneExpiredWakeStatusSnapshotsLocked(now)
		emitter.nextWakeStatusPruneAt = now.Add(liveEmitterWakeStatusPruneInterval)
	}
	snapshotsByChannel := emitter.wakeStatusBySpace[spaceKey]
	if snapshotsByChannel == nil {
		snapshotsByChannel = make(map[string]map[string]liveWakeStatusSnapshot)
		emitter.wakeStatusBySpace[spaceKey] = snapshotsByChannel
	}
	snapshots := snapshotsByChannel[channelKey]
	if snapshots == nil {
		snapshots = make(map[string]liveWakeStatusSnapshot)
		snapshotsByChannel[channelKey] = snapshots
	}
	for existingKey, snapshot := range snapshots {
		if !snapshot.expiresAt.After(now) {
			delete(snapshots, existingKey)
		}
	}
	if existing, ok := snapshots[key]; !shouldReplaceWakeStatusSnapshot(existing, ok, payload) {
		return
	}
	payload.expiresAt = now.Add(liveEmitterWakeStatusTTL)
	snapshots[key] = payload
}

func (emitter *LiveEventEmitter) clearAgentWakeStatusSnapshotsForChannel(workspaceID string, channelID string, agentID string, now time.Time) []liveWakeStatusSnapshot {
	if emitter == nil {
		return nil
	}
	spaceKey := strings.TrimSpace(workspaceID)
	channelKey := strings.TrimSpace(channelID)
	agentKey := strings.TrimSpace(agentID)
	if spaceKey == "" || channelKey == "" || agentKey == "" {
		return nil
	}
	emitter.wakeStatusMu.Lock()
	defer emitter.wakeStatusMu.Unlock()
	snapshotsByChannel := emitter.wakeStatusBySpace[spaceKey]
	if len(snapshotsByChannel) == 0 {
		return nil
	}
	snapshots := snapshotsByChannel[channelKey]
	if len(snapshots) == 0 {
		return nil
	}
	terminal := make([]liveWakeStatusSnapshot, 0)
	for key, snapshot := range snapshots {
		if strings.TrimSpace(snapshot.agentID) != agentKey {
			continue
		}
		delete(snapshots, key)
		snapshot.status = "completed_without_visible_reply"
		snapshot.replyMessageID = ""
		snapshot.detail = ""
		snapshot.timestamp = now.UTC().Format(time.RFC3339Nano)
		snapshot.channelID = channelKey
		snapshot.expiresAt = time.Time{}
		terminal = append(terminal, snapshot)
	}
	if len(snapshots) == 0 {
		delete(snapshotsByChannel, channelKey)
	}
	if len(snapshotsByChannel) == 0 {
		delete(emitter.wakeStatusBySpace, spaceKey)
	}
	return terminal
}

func (emitter *LiveEventEmitter) pruneExpiredWakeStatusSnapshotsLocked(now time.Time) {
	for spaceKey, snapshotsByChannel := range emitter.wakeStatusBySpace {
		for channelKey, snapshots := range snapshotsByChannel {
			for key, snapshot := range snapshots {
				if !snapshot.expiresAt.After(now) {
					delete(snapshots, key)
				}
			}
			if len(snapshots) == 0 {
				delete(snapshotsByChannel, channelKey)
			}
		}
		if len(snapshotsByChannel) == 0 {
			delete(emitter.wakeStatusBySpace, spaceKey)
		}
	}
}

func wakeStatusSnapshotKey(agentID string, messageID string) string {
	return strings.TrimSpace(agentID) + "\x00" + strings.TrimSpace(messageID)
}

func shouldReplaceWakeStatusSnapshot(existing liveWakeStatusSnapshot, hasExisting bool, incoming liveWakeStatusSnapshot) bool {
	if !hasExisting {
		return true
	}
	sameWakeToken := strings.TrimSpace(existing.wakeToken) != "" &&
		strings.TrimSpace(existing.wakeToken) == strings.TrimSpace(incoming.wakeToken)
	if sameWakeToken {
		if incoming.status == "reply_sent" && existing.status == "completed_without_visible_reply" {
			return true
		}
		if existing.status == "reply_sent" && incoming.status == "completed_without_visible_reply" {
			return false
		}
	}
	return existing.timestamp <= incoming.timestamp
}

func (snapshot liveWakeStatusSnapshot) payloadMap() map[string]any {
	return map[string]any{
		"agentId":          snapshot.agentID,
		"agentName":        snapshot.agentName,
		"agentDisplayName": snapshot.displayName,
		"channelId":        snapshot.channelID,
		"messageId":        snapshot.messageID,
		"wakeToken":        snapshot.wakeToken,
		"target":           snapshot.target,
		"status":           snapshot.status,
		"replyMessageId":   snapshot.replyMessageID,
		"detail":           snapshot.detail,
		"timestamp":        snapshot.timestamp,
	}
}
