package mcpserver

import (
	"context"
	"net/http/httptest"
	"reflect"
	"sort"
	"testing"
	"time"

	"github.com/modelcontextprotocol/go-sdk/mcp"

	"git.warky.dev/wdevs/amcs/internal/config"
)

func TestNewListsAllRegisteredTools(t *testing.T) {
	cs := newStreamableTestClient(t)

	result, err := cs.ListTools(context.Background(), nil)
	if err != nil {
		t.Fatalf("ListTools() error = %v", err)
	}

	got := make([]string, 0, len(result.Tools))
	for _, tool := range result.Tools {
		got = append(got, tool.Name)
	}
	sort.Strings(got)

	want := []string{
		"add_guardrail",
		"add_learning",
		"add_plan_dependency",
		"add_plan_guardrail",
		"add_plan_skill",
		"add_project_guardrail",
		"add_project_skill",
		"add_related_plan",
		"add_skill",
		"annotate_tool",
		"archive_thought",
		"backfill_embeddings",
		"capture_thought",
		"create_plan",
		"create_project",
		"delete_chat_history",
		"delete_plan",
		"delete_thought",
		"describe_tools",
		"get_active_project",
		"get_chat_history",
		"get_learning",
		"get_plan",
		"get_project_context",
		"get_thought",
		"get_version_info",
		"link_thoughts",
		"list_chat_histories",
		"list_files",
		"list_guardrails",
		"list_learnings",
		"list_plan_guardrails",
		"list_plan_skills",
		"list_plans",
		"list_project_guardrails",
		"list_project_skills",
		"list_projects",
		"list_skills",
		"list_thoughts",
		"load_file",
		"recall_context",
		"related_thoughts",
		"remove_guardrail",
		"remove_plan_dependency",
		"remove_plan_guardrail",
		"remove_plan_skill",
		"remove_project_guardrail",
		"remove_project_skill",
		"remove_related_plan",
		"remove_skill",
		"reparse_thought_metadata",
		"retry_failed_metadata",
		"save_chat_history",
		"save_file",
		"search_thoughts",
		"set_active_project",
		"summarize_thoughts",
		"thought_stats",
		"update_plan",
		"update_thought",
		"upload_file",
	}
	sort.Strings(want)

	if !reflect.DeepEqual(got, want) {
		t.Fatalf("ListTools() names = %#v, want %#v", got, want)
	}
}

func TestNewListsStoredFileResourceTemplate(t *testing.T) {
	cs := newStreamableTestClient(t)

	result, err := cs.ListResourceTemplates(context.Background(), nil)
	if err != nil {
		t.Fatalf("ListResourceTemplates() error = %v", err)
	}

	if len(result.ResourceTemplates) != 1 {
		t.Fatalf("ListResourceTemplates() count = %d, want 1", len(result.ResourceTemplates))
	}

	template := result.ResourceTemplates[0]
	if template.Name != "stored_file" {
		t.Fatalf("resource template name = %q, want %q", template.Name, "stored_file")
	}
	if template.URITemplate != "amcs://files/{id}" {
		t.Fatalf("resource template uri = %q, want %q", template.URITemplate, "amcs://files/{id}")
	}
}

func newStreamableTestClient(t *testing.T) *mcp.ClientSession {
	t.Helper()

	handler, err := New(config.MCPConfig{
		ServerName:     "test",
		Version:        "0.0.1",
		SessionTimeout: time.Minute,
	}, nil, streamableTestToolSet(), nil)
	if err != nil {
		t.Fatalf("mcpserver.New() error = %v", err)
	}

	httpServer := httptest.NewServer(handler)
	t.Cleanup(httpServer.Close)

	client := mcp.NewClient(&mcp.Implementation{Name: "client", Version: "0.0.1"}, nil)
	cs, err := client.Connect(context.Background(), &mcp.StreamableClientTransport{Endpoint: httpServer.URL}, nil)
	if err != nil {
		t.Fatalf("connect client: %v", err)
	}
	t.Cleanup(func() {
		_ = cs.Close()
	})

	return cs
}
