package knowledgetools

import (
	"context"
	"fmt"
	"strings"

	"github.com/enmanuel/agents/pkg/knowledge"
	"github.com/enmanuel/agents/tools"
)

// KnowledgeStore is the subset of knowledge.Store needed by knowledge tools.
type KnowledgeStore interface {
	Search(ctx context.Context, query string, limit int) ([]knowledge.SearchResult, error)
	Get(ctx context.Context, slug string) (*knowledge.Document, error)
	Put(ctx context.Context, doc knowledge.Document) error
	List(ctx context.Context) ([]knowledge.Document, error)
}

// NewKnowledgeSearch creates a tool that searches the knowledge base.
func NewKnowledgeSearch(store KnowledgeStore) tools.Tool {
	return tools.Tool{
		Def: tools.Def{
			Name:        "knowledge_search",
			Description: "Search your knowledge base for relevant documents. Returns matching snippets ranked by relevance.",
			Parameters: []tools.Param{
				{Name: "query", Type: "string", Description: "Search terms or phrase", Required: true},
				{Name: "limit", Type: "integer", Description: "Max results (default 5)", Required: false},
			},
		},
		Exec: func(ctx context.Context, args map[string]any) tools.Result {
			query := tools.GetString(args, "query")
			if query == "" {
				return tools.Result{Err: fmt.Errorf("knowledge_search: query is required")}
			}
			limit := tools.GetInt(args, "limit")
			if limit <= 0 {
				limit = 5
			}

			results, err := store.Search(ctx, query, limit)
			if err != nil {
				return tools.Result{Err: fmt.Errorf("knowledge_search: %w", err)}
			}
			if len(results) == 0 {
				return tools.Result{Output: "no documents found matching your query"}
			}

			var sb strings.Builder
			for i, r := range results {
				fmt.Fprintf(&sb, "%d. **%s** (`%s`)\n   %s\n", i+1, r.Title, r.Slug, r.Snippet)
			}
			return tools.Result{Output: sb.String()}
		},
	}
}

// NewKnowledgeRead creates a tool that reads a knowledge document.
func NewKnowledgeRead(store KnowledgeStore) tools.Tool {
	return tools.Tool{
		Def: tools.Def{
			Name:        "knowledge_read",
			Description: "Read the full content of a knowledge document by its slug.",
			Parameters: []tools.Param{
				{Name: "slug", Type: "string", Description: "Document slug (e.g. \"go-patterns\")", Required: true},
			},
		},
		Exec: func(ctx context.Context, args map[string]any) tools.Result {
			slug := tools.GetString(args, "slug")
			if slug == "" {
				return tools.Result{Err: fmt.Errorf("knowledge_read: slug is required")}
			}

			doc, err := store.Get(ctx, slug)
			if err != nil {
				return tools.Result{Err: fmt.Errorf("knowledge_read: %w", err)}
			}
			return tools.Result{Output: doc.Content}
		},
	}
}

// NewKnowledgeWrite creates a tool that writes a knowledge document.
func NewKnowledgeWrite(store KnowledgeStore) tools.Tool {
	return tools.Tool{
		Def: tools.Def{
			Name:        "knowledge_write",
			Description: "Create or update a knowledge document. Use this to save new knowledge or improve existing documents.",
			Parameters: []tools.Param{
				{Name: "slug", Type: "string", Description: "Document slug (lowercase, hyphens, e.g. \"matrix-tips\")", Required: true},
				{Name: "content", Type: "string", Description: "Full markdown content of the document", Required: true},
			},
		},
		Exec: func(ctx context.Context, args map[string]any) tools.Result {
			slug := tools.GetString(args, "slug")
			content := tools.GetString(args, "content")
			if slug == "" || content == "" {
				return tools.Result{Err: fmt.Errorf("knowledge_write: slug and content are required")}
			}

			err := store.Put(ctx, knowledge.Document{
				Slug:    slug,
				Content: content,
			})
			if err != nil {
				return tools.Result{Err: fmt.Errorf("knowledge_write: %w", err)}
			}
			return tools.Result{Output: fmt.Sprintf("document saved: %s (%d bytes)", slug, len(content))}
		},
	}
}

// NewKnowledgeList creates a tool that lists all knowledge documents.
func NewKnowledgeList(store KnowledgeStore) tools.Tool {
	return tools.Tool{
		Def: tools.Def{
			Name:        "knowledge_list",
			Description: "List all documents in your knowledge base with their titles.",
			Parameters:  []tools.Param{},
		},
		Exec: func(ctx context.Context, args map[string]any) tools.Result {
			docs, err := store.List(ctx)
			if err != nil {
				return tools.Result{Err: fmt.Errorf("knowledge_list: %w", err)}
			}
			if len(docs) == 0 {
				return tools.Result{Output: "knowledge base is empty"}
			}

			var sb strings.Builder
			for _, d := range docs {
				fmt.Fprintf(&sb, "- `%s`: %s (updated %s)\n",
					d.Slug, d.Title, d.UpdatedAt.Format("2006-01-02"))
			}
			return tools.Result{Output: sb.String()}
		},
	}
}
