package agent

import (
	"log/slog"
	"strings"
	"time"
	"unicode/utf8"

	"github.com/tidbcloud/AgentTeam/desktop/internal/workspace"
)

// RecordCheckpoint writes the current recovery snapshot into state/*,
// appends historical evidence into archive/checkpoints.md, and updates the
// Active Context section of MEMORY.md. Consecutive identical checkpoints
// (same trigger+summary) are deduplicated.
func (ap *Process) RecordCheckpoint(trigger, summary string) {
	summary = normalizeCheckpointSummary(summary)
	if summary == "" {
		return
	}

	key := trigger + "|" + summary

	ap.mu.Lock()
	if ap.lastCheckpointKey == key {
		ap.mu.Unlock()
		return
	}
	ap.lastCheckpointKey = key
	workDir := ap.workDir
	sessionID := ap.SessionID
	wakeTarget := ""
	wakeMessageID := ""
	if ap.pendingWake != nil {
		wakeTarget = strings.TrimSpace(ap.pendingWake.Wake.Target)
		wakeMessageID = strings.TrimSpace(ap.pendingWake.Wake.MessageID)
	}
	ap.mu.Unlock()

	if workDir == "" {
		return
	}

	if err := workspace.RecordRecoveryCheckpoint(workDir, ap.AgentID, workspace.RecoveryCheckpoint{
		Timestamp:     time.Now().UTC(),
		Trigger:       trigger,
		Summary:       summary,
		SessionID:     strings.TrimSpace(sessionID),
		WakeTarget:    wakeTarget,
		WakeMessageID: wakeMessageID,
	}); err != nil {
		slog.Warn("failed to record recovery checkpoint",
			"agent_id", ap.AgentID,
			"work_dir", workDir,
			"trigger", trigger,
			"error", err,
		)
	}
}

const (
	maxCheckpointSummaryRunes = 240
)

func normalizeCheckpointSummary(input string) string {
	normalized := strings.Join(strings.Fields(strings.TrimSpace(input)), " ")
	if normalized == "" {
		return ""
	}
	runes := []rune(normalized)
	if utf8.RuneCountInString(normalized) <= maxCheckpointSummaryRunes {
		return normalized
	}
	return string(runes[:maxCheckpointSummaryRunes]) + "…"
}
