package tianyancha_test

import (
	"regexp"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/extension"
	"github.com/tidbcloud/AgentTeam/internal/extension/bootstrap"
	"github.com/tidbcloud/AgentTeam/internal/extension/providers/tianyancha"
	"github.com/tidbcloud/AgentTeam/internal/extension/registry"
	"github.com/tidbcloud/AgentTeam/internal/extension/runner"
	appregistry "github.com/tidbcloud/AgentTeam/internal/store/app/registry"
	"github.com/tidbcloud/AgentTeam/internal/store/model"
)

// inputPatternOf returns the declared pattern of one string property of an
// action's input schema.
func inputPatternOf(t *testing.T, actionName, property string) string {
	t.Helper()
	for _, action := range tianyancha.Definition().Actions {
		if action.Name != actionName {
			continue
		}
		properties, ok := action.InputSchema["properties"].(map[string]any)
		require.Truef(t, ok, "action %s declares no properties", actionName)
		propertySchema, ok := properties[property].(map[string]any)
		require.Truef(t, ok, "action %s property %s declares no schema", actionName, property)
		pattern, ok := propertySchema["pattern"].(string)
		require.Truef(t, ok, "property %s declares no pattern", property)
		return pattern
	}
	t.Fatalf("action %s not found in the catalog", actionName)
	return ""
}

// TestNonWhitespaceInputsAllowInternalSpaces locks the upstream
// nonWhitespaceString semantics: a value needs at least one non-whitespace
// character, so ordinary company names and keywords with internal spaces
// are legal inputs, while empty and whitespace-only values stay rejected.
func TestNonWhitespaceInputsAllowInternalSpaces(t *testing.T) {
	t.Parallel()

	expression := regexp.MustCompile(inputPatternOf(t, "search-companies", "keyword"))
	require.True(t, expression.MatchString("ACME Holdings Ltd"))
	require.True(t, expression.MatchString("北京 百度网讯科技有限公司"))
	require.True(t, expression.MatchString("百度"))
	require.False(t, expression.MatchString(""))
	require.False(t, expression.MatchString("   "))
}

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

	extensionUnit, err := tianyancha.Extension(staticCredentialSource{})
	require.NoError(t, err)

	names := make([]string, 0)
	for _, action := range extensionUnit.Definition.Actions {
		names = append(names, action.Name)
	}
	lister, ok := extensionUnit.Implementation.Executor.(runner.ActionLister)
	require.True(t, ok)
	require.ElementsMatch(t, names, lister.ActionNames())
	require.Len(t, names, 24)

	require.Equal(t, "tianyancha-rest-v1", extensionUnit.Implementation.Revision)
	require.Equal(t, appregistry.TianyanchaAppID, extensionUnit.Distribution.AppID)
	require.Equal(t, appregistry.TianyanchaAppSlug, extensionUnit.Distribution.AppSlug)
	require.True(t, appregistry.IsProductApp(
		extensionUnit.Distribution.AppID, extensionUnit.Distribution.AppSlug))
	require.NoError(t, bootstrap.Register(registry.New(), []extension.Extension{extensionUnit}))
}

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

	extensionUnit, err := tianyancha.Extension(staticCredentialSource{})
	require.NoError(t, err)
	reg := registry.New()
	require.NoError(t, bootstrap.Register(reg, []extension.Extension{extensionUnit}))
	entry, ok := reg.LookupByIdentity(tianyancha.Domain, 1)
	require.True(t, ok)
	require.Equal(t, model.TianyanchaBuiltinExtensionDefinitionDigest, entry.Definition.Digest)
}

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

	spec := tianyancha.AuthSpec()
	require.Equal(t, runner.AuthHeader, spec.Kind)
	require.Equal(t, "Authorization", spec.Header)
	require.NoError(t, spec.ValidateSpec())
	require.NoError(t, spec.Validate(runner.Credentials{"apiKey": "token"}))
	require.Error(t, spec.Validate(runner.Credentials{}))
}
