package agents

import (
	"context"
	"fmt"
	"strings"
)

type ToolConfig struct {
	Name        string
	Enabled     bool
	Description string
}

type TraceFunc func(tool string, stage string, status string, message string, data map[string]interface{})

type Tool interface {
	Name() string
	Enabled(config ToolConfig) bool
	ShouldUse(messages []ChatMessage) bool
	Enrich(ctx context.Context, messages []ChatMessage, config ToolConfig, trace TraceFunc) ([]ChatMessage, error)
}

type ChatMessage struct {
	Role     string `json:"role"`
	Content  string `json:"content"`
	ImageURL string `json:"image_url,omitempty"`
}

var registry []Tool

func Register(tool Tool) {
	registry = append(registry, tool)
}

func EnabledTools(configs []ToolConfig) []Tool {
	tools := make([]Tool, 0)
	for _, tool := range registry {
		config := FindToolConfig(configs, tool.Name())
		if tool.Enabled(config) {
			tools = append(tools, tool)
		}
	}
	return tools
}

func EnrichMessages(ctx context.Context, messages []ChatMessage, configs []ToolConfig, trace TraceFunc) []ChatMessage {
	enriched := append([]ChatMessage{}, messages...)
	for _, tool := range EnabledTools(configs) {
		if !tool.ShouldUse(enriched) {
			continue
		}
		config := FindToolConfig(configs, tool.Name())
		var err error
		enriched, err = tool.Enrich(ctx, enriched, config, trace)
		if err != nil && trace != nil {
			trace(tool.Name(), "execute", "error", err.Error(), nil)
		}
	}
	return enriched
}

func FindToolConfig(configs []ToolConfig, name string) ToolConfig {
	for _, config := range configs {
		if strings.EqualFold(config.Name, name) {
			return config
		}
	}
	return ToolConfig{Name: name, Enabled: false}
}

func LastUserContent(messages []ChatMessage) string {
	for i := len(messages) - 1; i >= 0; i-- {
		if messages[i].Role == "user" {
			return messages[i].Content
		}
	}
	return ""
}

func SystemMessage(content string) ChatMessage {
	return ChatMessage{Role: "system", Content: content}
}

func SafeString(value interface{}) string {
	if value == nil {
		return ""
	}
	return fmt.Sprint(value)
}
