package pkulaw

import (
	"encoding/json"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/extension/runner"
)

func TestDefinitionPinsClosedPKULawCatalogAndStrictOpaqueOutput(t *testing.T) {
	t.Parallel()

	definition := Definition()
	require.Equal(t, Domain, definition.Domain)
	require.Equal(t, 1, definition.Version)
	require.Equal(t, "PKULaw", definition.Name)

	wantNames := []string{
		ActionSearchLawArticles,
		ActionGetLawArticle,
		ActionSearchLaws,
		ActionSearchCases,
		ActionSearchCaseDocuments,
	}
	gotNames := make([]string, 0, len(definition.Actions))
	for _, action := range definition.Actions {
		gotNames = append(gotNames, action.Name)
		require.NotEqual(t, "list-tools", action.Name)
		require.NotEqual(t, "call-tool", action.Name)
		require.Equal(t, "read", action.Safety.Class)
		require.True(t, action.Safety.Idempotent)
		require.False(t, action.Safety.Destructive)
		require.Equal(t, schemaDialect, action.InputSchema["$schema"])
		require.Equal(t, map[string]any{
			"$schema":              schemaDialect,
			"type":                 "object",
			"description":          "The normalized JSON value returned by the PKULaw MCP tool.",
			"additionalProperties": false,
			"properties": map[string]any{
				"result": map[string]any{
					"description": "The opaque JSON value returned by the selected PKULaw legal research operation.",
				},
			},
			"required": []any{"result"},
		}, action.OutputSchema)
	}
	require.Equal(t, wantNames, gotNames)
}

func TestDefinitionPinsExactPKULawInputSchemas(t *testing.T) {
	t.Parallel()

	actions := make(map[string]map[string]any)
	for _, action := range Definition().Actions {
		actions[action.Name] = action.InputSchema
		require.False(t, action.InputSchema["additionalProperties"].(bool))
	}

	require.Equal(
		t,
		[]any{"query"},
		actions[ActionSearchLawArticles]["required"],
	)
	require.Equal(
		t,
		map[string]any{"query": nonWhitespaceStringSchema(
			"A natural-language legal question or fact pattern in Chinese.",
		)},
		actions[ActionSearchLawArticles]["properties"],
	)

	require.Equal(
		t,
		[]any{"title", "number"},
		actions[ActionGetLawArticle]["required"],
	)
	require.Equal(t, []any{"text"}, actions[ActionSearchCases]["required"])

	for _, action := range []string{
		ActionSearchLaws,
		ActionSearchCaseDocuments,
	} {
		schema := actions[action]
		require.NotContains(t, schema, "required")
		require.Equal(t, []any{
			map[string]any{"required": []any{"title"}},
			map[string]any{"required": []any{"fulltext"}},
		}, schema["anyOf"])
		require.Equal(t, map[string]any{
			"title": nonWhitespaceStringSchema(
				"A keyword to match against document titles.",
			),
			"fulltext": nonWhitespaceStringSchema(
				"A keyword or phrase to match against document text.",
			),
		}, schema["properties"])
	}
}

func TestCatalogValidatorsEnforceClosedInputsAndOuterResultOnly(t *testing.T) {
	t.Parallel()

	validators, err := compileCatalogValidators(Definition())
	require.NoError(t, err)

	for _, invalid := range []string{
		`{}`,
		`{"title":"   "}`,
		`{"fulltext":""}`,
		`{"title":"民法典","unknown":true}`,
		`{"title":null}`,
	} {
		_, err := validators.validateInput(
			ActionSearchLaws,
			json.RawMessage(invalid),
		)
		require.Equal(t, runner.ErrorValidation, runner.CodeOf(err))
	}
	_, err = validators.validateInput(
		ActionSearchLaws,
		json.RawMessage(`{"fulltext":"居住权"}`),
	)
	require.NoError(t, err)

	for _, invalid := range []string{
		`{}`,
		`{"result":{"records":[]},"content":[]}`,
		`{"records":[]}`,
	} {
		_, err := validators.validateOutput(
			ActionSearchLaws,
			json.RawMessage(invalid),
		)
		require.Equal(t, runner.ErrorUpstreamFailure, runner.CodeOf(err))
	}
}
