// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
//
// SPDX-License-Identifier: LicenseRef-MutuaL-1.2

package mcp

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"testing"

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

	"git.secluded.site/cooked-mcp/internal/cooked"
)

func TestCallToolACIDAPIClientLimits2SummarizesLongShoppingListText(t *testing.T) {
	productGroups := make([]cooked.ProductGroup, maxShoppingListTextItems+1)
	for index := range productGroups {
		productGroups[index] = cooked.ProductGroup{
			ID:   fmt.Sprintf("item-%02d", index+1),
			Name: fmt.Sprintf("Item %02d", index+1),
		}
	}

	backend := &fakeBackend{shoppingList: cooked.ShoppingList{Aisles: []cooked.Aisle{{
		ID:            "pantry",
		Name:          "Pantry",
		ProductGroups: productGroups,
	}}}}
	server := NewServer(backend, "test")

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

	text := requireTextContent(t, result)
	if !strings.Contains(text, "Shopping list (showing first 30 of 31 items):") {
		t.Fatalf("text output missing shopping-list summary: %q", text)
	}
	if strings.Contains(text, "Item 31") || strings.Contains(text, "item-31") {
		t.Fatalf("text output included truncated item: %q", text)
	}
	if !strings.Contains(text, "Additional shopping-list items are available in structured_content") {
		t.Fatalf("text output missing structured_content hint: %q", text)
	}
	if len(output.Aisles) != 1 || len(output.Aisles[0].ProductGroups) != maxShoppingListTextItems+1 {
		t.Fatalf("structured shopping-list item count = %#v, want all items", output.Aisles)
	}
	requireStructuredContent(t, result, output)
}

func TestCallToolACIDAPIClientLimits2PreservesShortShoppingListText(t *testing.T) {
	backend := &fakeBackend{shoppingList: cooked.ShoppingList{Aisles: []cooked.Aisle{{
		ID:   "pantry",
		Name: "Pantry",
		ProductGroups: []cooked.ProductGroup{{
			ID:       "pasta",
			Name:     "Pasta",
			Quantity: "200g",
		}},
	}}}}
	server := NewServer(backend, "test")

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

	text := requireTextContent(t, result)
	want := "Shopping list:\n- Pantry:\n  - Pasta — 200g (id: pasta)"
	if text != want {
		t.Fatalf("short shopping-list text = %q, want %q", text, want)
	}
	if strings.Contains(text, "structured_content") || strings.Contains(text, "showing first") {
		t.Fatalf("short shopping-list text included truncation hint: %q", text)
	}
}

func requireTextContent(t *testing.T, result *sdk.CallToolResult) string {
	t.Helper()

	if len(result.Content) != 1 {
		t.Fatalf("text content length = %d, want 1", len(result.Content))
	}
	textContent, ok := result.Content[0].(*sdk.TextContent)
	if !ok {
		t.Fatalf("content type = %T, want *sdk.TextContent", result.Content[0])
	}

	return textContent.Text
}

func requireStructuredContent(t *testing.T, result *sdk.CallToolResult, want any) {
	t.Helper()
	// tools.RESPONSES.5

	if result == nil {
		t.Fatal("result is nil")
	}
	if result.StructuredContent == nil {
		t.Fatal("structured content is nil")
	}

	gotJSON, err := json.Marshal(result.StructuredContent)
	if err != nil {
		t.Fatalf("marshal structured content: %v", err)
	}
	wantJSON, err := json.Marshal(want)
	if err != nil {
		t.Fatalf("marshal wanted structured content: %v", err)
	}
	if string(gotJSON) != string(wantJSON) {
		t.Fatalf("structured content = %s, want %s", gotJSON, wantJSON)
	}

	var object map[string]any
	if err := json.Unmarshal(gotJSON, &object); err != nil {
		t.Fatalf("structured content is not a JSON object: %v", err)
	}
}
