package agent

import (
	"fmt"
	"os"
	"path/filepath"
	"time"

	"github.com/mudler/LocalAGI/core/types"
	"github.com/mudler/LocalAGI/pkg/xlog"
	"github.com/sashabaranov/go-openai"
)

func (a *Agent) knowledgeBaseLookup(job *types.Job, conv Messages) Messages {
	if (!a.options.enableKB && !a.options.enableLongTermMemory && !a.options.enableSummaryMemory) ||
		len(conv) <= 0 {
		xlog.Debug("[Knowledge Base Lookup] Disabled, skipping", "agent", a.Character.Name)
		return conv
	}
	
	var obs *types.Observable
	if job != nil && job.Obs != nil && a.observer != nil {
		obs = a.observer.NewObservable()
		obs.Name = "Recall"
		obs.Icon = "database"
		obs.ParentID = job.Obs.ID
		a.observer.Update(*obs)
	}

	// Walk conversation from bottom to top, and find the first message of the user
	// to use it as a query to the KB
	userMessage := conv.GetLatestUserMessage().Content

	xlog.Info("[Knowledge Base Lookup] Last user message", "agent", a.Character.Name, "message", userMessage, "lastMessage", conv.GetLatestUserMessage())

	if userMessage == "" {
		xlog.Info("[Knowledge Base Lookup] No user message found in conversation", "agent", a.Character.Name)
		if obs != nil {
			obs.Completion = &types.Completion{
				Error: "No user message found in conversation",
			}
			a.observer.Update(*obs)
		}
		return conv
	}

	results, err := a.options.ragdb.Search(userMessage, a.options.kbResults)
	if err != nil {
		xlog.Info("Error finding similar strings inside KB:", "error", err)
		if obs != nil {
			obs.AddProgress(types.Progress{
				Error: fmt.Sprintf("Error searching knowledge base: %v", err),
			})
			a.observer.Update(*obs)
		}
	}

	if len(results) == 0 {
		xlog.Info("[Knowledge Base Lookup] No similar strings found in KB", "agent", a.Character.Name)
		if obs != nil {
			obs.Completion = &types.Completion{
				ActionResult: "No similar strings found in knowledge base",
			}
			a.observer.Update(*obs)
		}
		return conv
	}

	formatResults := ""
	for _, r := range results {
		formatResults += fmt.Sprintf("- %s \n", r)
	}
	xlog.Info("[Knowledge Base Lookup] Found similar strings in KB", "agent", a.Character.Name, "results", formatResults)

	if obs != nil {
		obs.AddProgress(types.Progress{
			ActionResult: fmt.Sprintf("Found %d results in knowledge base", len(results)),
		})
		a.observer.Update(*obs)
	}

	// Create the message to add to conversation
	systemMessage := openai.ChatCompletionMessage{
		Role:    "system",
		Content: fmt.Sprintf("Given the user input you have the following in memory:\n%s", formatResults),
	}

	// Add the message to the conversation
	conv = append([]openai.ChatCompletionMessage{systemMessage}, conv...)

	if obs != nil {
		obs.Completion = &types.Completion{
				Conversation: []openai.ChatCompletionMessage{systemMessage},
		}
		a.observer.Update(*obs)
	}

	return conv
}

func (a *Agent) saveConversation(m Messages, prefix string) error {
	if a.options.conversationsPath == "" {
		return nil
	}
	dateTime := time.Now().Format("2006-01-02-15-04-05")
	fileName := a.Character.Name + "-" + dateTime + ".json"
	if prefix != "" {
		fileName = prefix + "-" + fileName
	}
	os.MkdirAll(a.options.conversationsPath, os.ModePerm)
	return m.Save(filepath.Join(a.options.conversationsPath, fileName))
}

func (a *Agent) saveCurrentConversation(conv Messages) {

	if err := a.saveConversation(conv, ""); err != nil {
		xlog.Error("Error saving conversation", "error", err)
	}

	if !a.options.enableLongTermMemory && !a.options.enableSummaryMemory {
		xlog.Debug("Long term memory is disabled", "agent", a.Character.Name)
		return
	}

	xlog.Info("Saving conversation", "agent", a.Character.Name, "conversation size", len(conv))

	if a.options.enableSummaryMemory && len(conv) > 0 {
		msg, err := a.askLLM(a.context.Context, []openai.ChatCompletionMessage{{
			Role:    "user",
			Content: "Summarize the conversation below, keep the highlights as a bullet list:\n" + Messages(conv).String(),
		}}, maxRetries)
		if err != nil {
			xlog.Error("Error summarizing conversation", "error", err)
		}

		if err := a.options.ragdb.Store(msg.Content); err != nil {
			xlog.Error("Error storing into memory", "error", err)
		}
	} else {
		for _, message := range conv {
			if message.Role == "user" {
				if err := a.options.ragdb.Store(message.Content); err != nil {
					xlog.Error("Error storing into memory", "error", err)
				}
			}
		}
	}
}
