package knowledgetools

import (
	"context"
	"testing"

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

func TestNewSharedKnowledgeTools(t *testing.T) {
	store := newMockKnowledgeStore()
	tools := NewSharedKnowledgeTools(store)

	if len(tools) != 4 {
		t.Errorf("expected 4 tools, got %d", len(tools))
	}

	names := make(map[string]bool)
	for _, tool := range tools {
		names[tool.Def.Name] = true
	}

	expected := []string{
		"shared_knowledge_search",
		"shared_knowledge_read",
		"shared_knowledge_write",
		"shared_knowledge_list",
	}

	for _, name := range expected {
		if !names[name] {
			t.Errorf("expected tool %q not found", name)
		}
	}
}

func TestSharedKnowledgeSearchTool(t *testing.T) {
	store := newMockKnowledgeStore()
	store.docs["shared-doc"] = knowledge.Document{
		Slug: "shared-doc", Title: "Shared Doc", Content: "This is shared knowledge",
	}

	tools := NewSharedKnowledgeTools(store)
	tool := tools[0] // shared_knowledge_search is first

	// Missing query
	r := tool.Exec(context.Background(), map[string]any{})
	if r.Err == nil {
		t.Error("expected error for missing query")
	}

	// Valid search
	r = tool.Exec(context.Background(), map[string]any{"query": "shared"})
	if r.Err != nil {
		t.Errorf("unexpected error: %v", r.Err)
	}
	if r.Output == "" {
		t.Error("expected non-empty output")
	}

	// Empty results
	store2 := newMockKnowledgeStore()
	tools2 := NewSharedKnowledgeTools(store2)
	r = tools2[0].Exec(context.Background(), map[string]any{"query": "nothing"})
	if r.Err != nil {
		t.Errorf("unexpected error: %v", r.Err)
	}
	if r.Output != "no documents found in shared knowledge base matching your query" {
		t.Errorf("expected empty message, got %q", r.Output)
	}
}

func TestSharedKnowledgeReadTool(t *testing.T) {
	store := newMockKnowledgeStore()
	store.docs["shared-doc"] = knowledge.Document{
		Slug: "shared-doc", Title: "Shared", Content: "Shared content",
	}

	tools := NewSharedKnowledgeTools(store)
	tool := tools[1] // shared_knowledge_read is second

	// Missing slug
	r := tool.Exec(context.Background(), map[string]any{})
	if r.Err == nil {
		t.Error("expected error for missing slug")
	}

	// Valid read
	r = tool.Exec(context.Background(), map[string]any{"slug": "shared-doc"})
	if r.Err != nil {
		t.Errorf("unexpected error: %v", r.Err)
	}
	if r.Output != "Shared content" {
		t.Errorf("output = %q, want %q", r.Output, "Shared content")
	}

	// Not found
	r = tool.Exec(context.Background(), map[string]any{"slug": "nope"})
	if r.Err == nil {
		t.Error("expected error for nonexistent doc")
	}
}

func TestSharedKnowledgeWriteTool(t *testing.T) {
	store := newMockKnowledgeStore()
	tools := NewSharedKnowledgeTools(store)
	tool := tools[2] // shared_knowledge_write is third

	// Missing params
	r := tool.Exec(context.Background(), map[string]any{"slug": "test"})
	if r.Err == nil {
		t.Error("expected error for missing content")
	}

	// Valid write
	r = tool.Exec(context.Background(), map[string]any{
		"slug":    "shared-doc",
		"content": "# Shared Doc\nShared by agent A",
	})
	if r.Err != nil {
		t.Errorf("unexpected error: %v", r.Err)
	}
	if _, ok := store.docs["shared-doc"]; !ok {
		t.Error("document was not stored")
	}

	// Verify the output message mentions "shared"
	if r.Output != "shared document saved: shared-doc (30 bytes)" {
		t.Errorf("output = %q, want mention of shared", r.Output)
	}
}

func TestSharedKnowledgeListTool(t *testing.T) {
	store := newMockKnowledgeStore()
	tools := NewSharedKnowledgeTools(store)
	tool := tools[3] // shared_knowledge_list is fourth

	// Empty
	r := tool.Exec(context.Background(), map[string]any{})
	if r.Err != nil {
		t.Errorf("unexpected error: %v", r.Err)
	}
	if r.Output != "shared knowledge base is empty" {
		t.Errorf("expected empty message, got %q", r.Output)
	}

	// With docs
	store.docs["shared-doc1"] = knowledge.Document{Slug: "shared-doc1", Title: "Shared 1"}
	r = tool.Exec(context.Background(), map[string]any{})
	if r.Err != nil {
		t.Errorf("unexpected error: %v", r.Err)
	}
	if r.Output == "shared knowledge base is empty" {
		t.Error("expected non-empty output after adding docs")
	}
}

// TestSharedAndPrivateCoexist verifies that shared and private tools can coexist
// with different stores and don't interfere with each other.
func TestSharedAndPrivateCoexist(t *testing.T) {
	privateStore := newMockKnowledgeStore()
	sharedStore := newMockKnowledgeStore()

	// Write to private store
	privateStore.docs["private-doc"] = knowledge.Document{
		Slug: "private-doc", Title: "Private", Content: "Private content",
	}

	// Write to shared store
	sharedStore.docs["shared-doc"] = knowledge.Document{
		Slug: "shared-doc", Title: "Shared", Content: "Shared content",
	}

	// Verify private has only private doc
	privateDocs, _ := privateStore.List(context.Background())
	if len(privateDocs) != 1 || privateDocs[0].Slug != "private-doc" {
		t.Error("private store should only have private doc")
	}

	// Verify shared has only shared doc
	sharedDocs, _ := sharedStore.List(context.Background())
	if len(sharedDocs) != 1 || sharedDocs[0].Slug != "shared-doc" {
		t.Error("shared store should only have shared doc")
	}

	// Verify tools from different stores don't mix data
	privateTool := NewKnowledgeRead(privateStore)
	sharedTools := NewSharedKnowledgeTools(sharedStore)
	sharedTool := sharedTools[1] // shared_knowledge_read

	// Private tool can't read shared doc
	r := privateTool.Exec(context.Background(), map[string]any{"slug": "shared-doc"})
	if r.Err == nil {
		t.Error("private tool should not be able to read shared doc")
	}

	// Shared tool can't read private doc
	r = sharedTool.Exec(context.Background(), map[string]any{"slug": "private-doc"})
	if r.Err == nil {
		t.Error("shared tool should not be able to read private doc")
	}
}
