package handlers

import (
	"context"
	"fmt"
	"log"
	"strings"

	"chat-switchboard/knowledge"
	"chat-switchboard/models"
	"chat-switchboard/store"
)

// maxMemoryChars is the approximate character budget for injected memories.
const maxMemoryChars = 6000

// BuildMemoryHint loads active memories for the user (and persona if active)
// and formats them as a system prompt injection.
//
// Phase 2: if an embedder is available and the user's latest message
// is provided, it generates a query vector for semantic recall. Otherwise
// falls back to keyword/confidence ranking.
func BuildMemoryHint(ctx context.Context, stores store.Stores, embedder *knowledge.Embedder, userID, personaID, lastUserMessage string) string {
	if stores.Memories == nil {
		return ""
	}

	var pID *string
	if personaID != "" {
		pID = &personaID
	}

	var memories []models.Memory
	var err error

	// Try hybrid recall with embedding if available
	if embedder != nil && embedder.IsConfigured(ctx) && lastUserMessage != "" {
		memories, err = hybridRecallForInjection(ctx, stores, embedder, userID, pID, lastUserMessage)
	}

	// Fall back to keyword recall
	if err != nil || len(memories) == 0 {
		memories, err = stores.Memories.Recall(ctx, userID, pID, "", 30)
	}

	if err != nil {
		log.Printf("⚠ memory injection failed: %v", err)
		return ""
	}
	if len(memories) == 0 {
		return ""
	}

	// Format memories as bullet points, respecting token budget
	var b strings.Builder
	b.WriteString("Known facts about this user (from previous conversations):\n")

	totalChars := b.Len()
	included := 0
	for _, m := range memories {
		line := fmt.Sprintf("• %s: %s\n", m.Key, m.Value)
		if totalChars+len(line) > maxMemoryChars {
			break
		}
		b.WriteString(line)
		totalChars += len(line)
		included++
	}

	if included == 0 {
		return ""
	}

	log.Printf("🧠 Injected %d memories for user %s (persona: %s)", included, userID, personaID)
	return b.String()
}

// hybridRecallForInjection generates a query vector from the user's message
// and performs hybrid semantic + keyword recall.
func hybridRecallForInjection(ctx context.Context, stores store.Stores, embedder *knowledge.Embedder, userID string, personaID *string, message string) ([]models.Memory, error) {
	text := message
	if len(text) > 2000 {
		text = text[:2000]
	}

	var teamID *string
	if stores.Teams != nil {
		ids, _ := stores.Teams.GetUserTeamIDs(ctx, userID)
		if len(ids) > 0 {
			teamID = &ids[0]
		}
	}

	result, err := embedder.EmbedChunks(ctx, userID, teamID, []string{text})
	if err != nil || len(result.Vectors) == 0 {
		return nil, err
	}

	return stores.Memories.RecallHybrid(ctx, userID, personaID, "", result.Vectors[0], 30)
}
